Jump to content

Memory Leak Finder


Recommended Posts

  • Honorable Member
This is the hidden content, please

 

Hello everyone,

Some time ago I created this memory leak finder for Land of Heroes, but we don't really use it anymore so I decided to release it.

You can use it only on Windows (otherwise you have to modify it a bit), and you will need

This is the hidden content, please
for it to work.

namespace MemoryLeakFinder
{
	typedef void* (__cdecl* _malloc)(_In_ _CRT_GUARDOVERFLOW size_t _Size);
	typedef void (__cdecl* _free)(_Pre_maybenull_ _Post_invalid_ void* _Block);

	_malloc True_malloc = (_malloc) ::malloc;
	_free True_free = (_free) ::free;

	template <class T>
	class NoTraceAllocator
	{
	public:
		using value_type = T;
		NoTraceAllocator() noexcept {}
		template <class U> NoTraceAllocator(NoTraceAllocator<U> const&) noexcept {}
		value_type* allocate(std::size_t n)
		{
			return static_cast<value_type*>(True_malloc(n * sizeof(value_type)));
		}
		void deallocate(value_type* p, std::size_t) noexcept
		{
			True_free(p);
		}
	};

	static bool GetStackWalk(char* outWalk)
	{
		::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_UNDNAME);
		if (!::SymInitialize(::GetCurrentProcess(), "http://msdl.microsoft.com/download/symbols", TRUE))
			return false;
		PVOID addrs[25] = { 0 };
		USHORT frames = CaptureStackBackTrace(1, 25, addrs, NULL);

		char* ptr = outWalk;
		for (USHORT i = 0; i < frames; i++)
		{
			ULONG64 buffer[(sizeof(SYMBOL_INFO) + 1024 + sizeof(ULONG64) - 1) / sizeof(ULONG64)] = { 0 };
			SYMBOL_INFO* info = (SYMBOL_INFO*)buffer;
			info->SizeOfStruct = sizeof(SYMBOL_INFO);
			info->MaxNameLen = 1024;
			DWORD64 displacement = 0;
			if (::SymFromAddr(::GetCurrentProcess(), (DWORD64)addrs[i], &displacement, info)) 
			{
				ptr += sprintf_s(outWalk, 1024, "%s\n", info->Name);
			}
		}
		::SymCleanup(::GetCurrentProcess());
		return true;
	}

	std::unordered_map<void*, const char*
		, std::hash<void*>
		, std::equal_to<void*>
		, NoTraceAllocator<std::pair<const void*, const char*>>> memoryAllocations;

	void* My_malloc(_In_ _CRT_GUARDOVERFLOW size_t _Size)
	{
		void* ptr = True_malloc(_Size);
		char* stackTrace = (char*)True_malloc(1024);
		GetStackWalk(stackTrace);
		memoryAllocations.emplace(std::make_pair(ptr, stackTrace));
		return ptr;
	}
	void My_free(_Pre_maybenull_ _Post_invalid_ void* _Block)
	{
		auto it = memoryAllocations.find(_Block);
		if (it != memoryAllocations.end())
		{
			True_free((void*)it->second);
			memoryAllocations.erase(it);
		}
		return True_free(_Block);
	}

	void StartMemoryLeakFinder()
	{
		Mhook_SetHook((PVOID*)&True_malloc,
			My_malloc);
		Mhook_SetHook((PVOID*)&True_free,
			My_free);
	}

	void StopMemoryLeakFinder()
	{
		Mhook_Unhook((PVOID*)&True_malloc);
		Mhook_Unhook((PVOID*)&True_free);

		std::ofstream ofs("memoryleaks.txt");
		for (auto it = memoryAllocations.begin(); it != memoryAllocations.end(); ++it)
		{
			ofs << it->second << std::endl;
			True_free((void*)it->second);
		}
		ofs.close();
	}
}

 

You have to call StartMemoryLeakFinder() and StopMemoryLeakFinder() where you'd like them to start and stop accordingly.

  • Metin2 Dev 157
  • Eyes 2
  • Scream 1
  • Good 35
  • Love 3
  • Love 56

WRnRW3H.gif

Link to comment
Share on other sites

  • 9 months later...
  • Replies 1
  • Created
  • Last Reply

Top Posters In This Topic

  • Active Member
On 4/5/2023 at 10:28 PM, Distraught said:
This is the hidden content, please

 

Hello everyone,

Some time ago I created this memory leak finder for Land of Heroes, but we don't really use it anymore so I decided to release it.

You can use it only on Windows (otherwise you have to modify it a bit), and you will need

This is the hidden content, please
for it to work.

namespace MemoryLeakFinder
{
	typedef void* (__cdecl* _malloc)(_In_ _CRT_GUARDOVERFLOW size_t _Size);
	typedef void (__cdecl* _free)(_Pre_maybenull_ _Post_invalid_ void* _Block);

	_malloc True_malloc = (_malloc) ::malloc;
	_free True_free = (_free) ::free;

	template <class T>
	class NoTraceAllocator
	{
	public:
		using value_type = T;
		NoTraceAllocator() noexcept {}
		template <class U> NoTraceAllocator(NoTraceAllocator<U> const&) noexcept {}
		value_type* allocate(std::size_t n)
		{
			return static_cast<value_type*>(True_malloc(n * sizeof(value_type)));
		}
		void deallocate(value_type* p, std::size_t) noexcept
		{
			True_free(p);
		}
	};

	static bool GetStackWalk(char* outWalk)
	{
		::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_UNDNAME);
		if (!::SymInitialize(::GetCurrentProcess(), "http://msdl.microsoft.com/download/symbols", TRUE))
			return false;
		PVOID addrs[25] = { 0 };
		USHORT frames = CaptureStackBackTrace(1, 25, addrs, NULL);

		char* ptr = outWalk;
		for (USHORT i = 0; i < frames; i++)
		{
			ULONG64 buffer[(sizeof(SYMBOL_INFO) + 1024 + sizeof(ULONG64) - 1) / sizeof(ULONG64)] = { 0 };
			SYMBOL_INFO* info = (SYMBOL_INFO*)buffer;
			info->SizeOfStruct = sizeof(SYMBOL_INFO);
			info->MaxNameLen = 1024;
			DWORD64 displacement = 0;
			if (::SymFromAddr(::GetCurrentProcess(), (DWORD64)addrs[i], &displacement, info)) 
			{
				ptr += sprintf_s(outWalk, 1024, "%s\n", info->Name);
			}
		}
		::SymCleanup(::GetCurrentProcess());
		return true;
	}

	std::unordered_map<void*, const char*
		, std::hash<void*>
		, std::equal_to<void*>
		, NoTraceAllocator<std::pair<const void*, const char*>>> memoryAllocations;

	void* My_malloc(_In_ _CRT_GUARDOVERFLOW size_t _Size)
	{
		void* ptr = True_malloc(_Size);
		char* stackTrace = (char*)True_malloc(1024);
		GetStackWalk(stackTrace);
		memoryAllocations.emplace(std::make_pair(ptr, stackTrace));
		return ptr;
	}
	void My_free(_Pre_maybenull_ _Post_invalid_ void* _Block)
	{
		auto it = memoryAllocations.find(_Block);
		if (it != memoryAllocations.end())
		{
			True_free((void*)it->second);
			memoryAllocations.erase(it);
		}
		return True_free(_Block);
	}

	void StartMemoryLeakFinder()
	{
		Mhook_SetHook((PVOID*)&True_malloc,
			My_malloc);
		Mhook_SetHook((PVOID*)&True_free,
			My_free);
	}

	void StopMemoryLeakFinder()
	{
		Mhook_Unhook((PVOID*)&True_malloc);
		Mhook_Unhook((PVOID*)&True_free);

		std::ofstream ofs("memoryleaks.txt");
		for (auto it = memoryAllocations.begin(); it != memoryAllocations.end(); ++it)
		{
			ofs << it->second << std::endl;
			True_free((void*)it->second);
		}
		ofs.close();
	}
}

 

You have to call StartMemoryLeakFinder() and StopMemoryLeakFinder() where you'd like them to start and stop accordingly.

Can you update to VC140 please

  • Metin2 Dev 2
Link to comment
Share on other sites

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.