Implemented automatic memory leak detection and reporting for CRT.

This commit is contained in:
sigonasr2 2023-11-11 04:03:48 -06:00
parent 67a5288984
commit 380582dfeb
12 changed files with 31067 additions and 16 deletions

View File

@ -5,6 +5,8 @@ VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Crawler", "Crawler\Crawler.vcxproj", "{8E3067AF-CFE7-4B11-BC6B-B867C32753D7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MemoryLeakFileParser", "MemoryLeakFileParser\MemoryLeakFileParser.vcxproj", "{3054FF55-6C4E-4A38-89DA-E707AE2F3178}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -27,6 +29,18 @@ Global
{8E3067AF-CFE7-4B11-BC6B-B867C32753D7}.Release|x64.Build.0 = Release|x64
{8E3067AF-CFE7-4B11-BC6B-B867C32753D7}.Release|x86.ActiveCfg = Release|Win32
{8E3067AF-CFE7-4B11-BC6B-B867C32753D7}.Release|x86.Build.0 = Release|Win32
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Debug|x64.ActiveCfg = Debug|x64
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Debug|x64.Build.0 = Debug|x64
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Debug|x86.ActiveCfg = Debug|Win32
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Debug|x86.Build.0 = Debug|Win32
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release Desktop|x64.ActiveCfg = Release|x64
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release Desktop|x64.Build.0 = Release|x64
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release Desktop|x86.ActiveCfg = Release|Win32
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release Desktop|x86.Build.0 = Release|Win32
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release|x64.ActiveCfg = Release|x64
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release|x64.Build.0 = Release|x64
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release|x86.ActiveCfg = Release|Win32
{3054FF55-6C4E-4A38-89DA-E707AE2F3178}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -6,6 +6,7 @@
class IAttributable{
protected:
inline virtual ~IAttributable(){};
std::map<Attribute,std::variant<VARIANTS>>attributes;
inline float&GetFloat(Attribute a){
if(attributes.count(a)==0){

View File

@ -1551,7 +1551,32 @@ int main()
demo.Start();
}
#ifdef _DEBUG
HANDLE hLogFile;
hLogFile = CreateFile(L"assets/memoryleak.txt", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
_CrtSetReportMode(_CRT_WARN,_CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN,hLogFile);
_CrtDumpMemoryLeaks();
CloseHandle(hLogFile);
std::ifstream file("assets/memoryleak.txt");
bool leaked=false;
while(file.good()){
std::string line;
std::getline(file,line);
if(line.find("Crawler\\")!=std::string::npos){
if(!leaked){
leaked=true;
std::cout<<std::endl<<std::endl<<std::endl<<"Memory leak detected!"<<std::endl;
}
std::cout<<line<<std::endl;
std::getline(file,line);
std::cout<<line<<std::endl;
}
}
#endif
return 0;
}
@ -1631,9 +1656,17 @@ bool Crawler::OnUserDestroy(){
delete MAP_DATA[data.first].optimizedTile;
}
}
for(auto&key:MAP_TILESETS){
delete key.second.tileset;
}
for(auto&data:GameState::states){
delete data.second;
}
delete[]pathfinder.nodes;
Menu::CleanupAllMenus();
for(auto&key:MonsterData::imgs){
delete key.second;
}
return true;
}

View File

@ -35,7 +35,7 @@ protected:
}
}
}
void inline RemoveEmptySlots(){
inline void RemoveEmptySlots(){
//Algorithm will iterate through all slots, finding blank slots. Each time a blank slot is found, all items will shift over by one, and then the last item will be removed. Repeat until all slots iterated through.
for(int i=0;i<components.size();i++){
MenuComponent*button=components[i];
@ -58,7 +58,7 @@ protected:
}
bounds=CalculateBounds(); //Recalculate the bounds as it's possible the width/height of the component has changed.
}
virtual void OnInventorySlotsUpdate(ITCategory cat)override{
virtual inline void OnInventorySlotsUpdate(ITCategory cat)override{
std::vector<std::string>&inv=Inventory::get(cat);
//We only want to refresh the inventory slots if the component count no longer matches what's actually in our inventory.
if(components.size()<inv.size()){//We need more space to display our items.
@ -82,4 +82,7 @@ protected:
RemoveEmptySlots();
}
}
virtual inline void Cleanup()override{
}
};

View File

@ -18,8 +18,8 @@ std::vector<MenuComponent*>Menu::unhandledComponents;
///__/////////////////////////////////////////////////////////////////////////////////////////////
//| |////////////////////////////////////////////////////////////////////////////////////////////
//| |/////WARNING! If you are adding something here you likely are adding another container with MenuComponent pointers in it right now.
//| |/////Because we are handling raw pointers, you must also add this container to the list of iterating search removal contains that occur in the
//| |/////DESTRUCTOR of MenuComponents!!!!! THIS IS NOT A DRILL!
//| |/////Because we are handling raw pointers, you must also add this container to the list of iterating search removal containers that occur in the
//| |/////DESTRUCTOR of MenuComponents!!!!! (Go to MenuComponent::~MenuComponent()) THIS IS NOT A DRILL!
//|__|////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
///__/////////////////////////////////////////////////////////////////////////////////////////////
@ -648,5 +648,18 @@ bool Menu::IsMenuOpen(){
}
void Menu::CleanupAllMenus(){
for(auto key:Menu::menus){
Menu*menu=key.second;
for(auto componentKey:menu->components){
MenuComponent*component=componentKey.second;
component->Cleanup();
delete component;
}
menu->components.Reset();
menu->Cleanup();
delete menu;
}
Menu::menus.clear();
}
void Menu::Cleanup(){}

View File

@ -67,6 +67,7 @@ public:
vf2d center();
//Returns the last menu type created and last registered component, in case a component is detected as memory leaking, provides this information to each component for safety.
static std::pair<MenuType,std::string>GetMemoryLeakReportInfo();
virtual void Cleanup();
private:
Menu(vf2d pos,vf2d size);
static MenuType lastMenuTypeCreated;

View File

@ -25,6 +25,7 @@ MenuComponent::~MenuComponent(){
std::erase_if(components,[&](MenuComponent*component){return component==this;});
}
std::erase_if(pMenu->displayComponents,[&](MenuComponent*component){return component==this;});
//pMenu->components.erase(this->name); //We're not going to do this here because we are in the middle of a loop for another menu component when cleaning up.
}
void MenuComponent::AfterCreate(){}
@ -123,3 +124,5 @@ std::string MenuComponent::GetLabel(){
void MenuComponent::Enable(bool enabled){
disabled=!enabled;
};
void MenuComponent::Cleanup(){}

View File

@ -70,6 +70,7 @@ public:
virtual void OnInventorySlotsUpdate(ITCategory cat);
std::string GetLabel();
void Enable(bool enabled);
virtual void Cleanup();
};
constexpr auto operator|(ButtonAttr attribute,ButtonAttr attribute2) noexcept

View File

@ -26,13 +26,6 @@ public:
:MenuComponent(parent,rect,"",onClick,ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
r.Create(rect.size.x,rect.size.y);
}
virtual inline ~ScrollableWindowComponent(){
MenuComponent::~MenuComponent();
for(MenuComponent*component:components){
delete component;
}
}
protected:
virtual inline void AfterCreate()override{
upButton=NEW MenuComponent(parentMenu,{vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
@ -192,4 +185,5 @@ public:
V(A::SCROLL_OFFSET).y+=rect.size.y/2;
return true;
};
virtual void Cleanup()override{}
};

View File

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_PATCH 1
#define VERSION_BUILD 2592
#define VERSION_BUILD 2618
#define stringify(a) stringify_(a)
#define stringify_(a) #a

30985
Crawler/assets/memoryleak.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,9 @@ public:
size_t erase(const T&key){
return map.erase(key);
}
auto erase(std::map<T,O>::iterator it){
return map.erase(it);
}
};
//A class that has an initialization lock so that when the lock is activated, any further gets that are missing items in it will report themselves for easier debugging detection.