-
-
Save ttsuki/98a60653f398062b15e5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// memory_allocator.cpp | |
#include <Windows.h> | |
#include <cstdio> | |
#include <cassert> | |
#include <crtdbg.h> | |
#include "memory_allocator.hpp" | |
namespace DebugMemoryAllocator | |
{ | |
#define MAGIC 0xDEADBEEF | |
struct MemoryBlock | |
{ | |
unsigned int magic; ///< magic == MAGIC | |
size_t blocksize; ///< ブロックサイズ | |
void *callee; ///< 呼び出し元アドレス | |
const char *filename; ///< 呼び出し元ソースファイル | |
int line; ///< 呼び出し元ソースファイル行番号 | |
DWORD timeStamp; ///< 時刻(初回呼び出しからのミリ秒) | |
MemoryBlock *next; ///< 次ブロックへのポインタ | |
MemoryBlock *prev; ///< 前ブロックへのポインタ | |
}; | |
static MemoryBlock ringHead = {}; | |
void *Allocate(size_t size, const char *filename, int line, void *callee) | |
{ | |
static int allocIndex = 0; | |
// initialize ring | |
if (!ringHead.magic) | |
{ | |
ringHead.magic = MAGIC; | |
ringHead.next = &ringHead; | |
ringHead.prev = &ringHead; | |
ringHead.filename = ""; | |
ringHead.timeStamp = GetTickCount(); | |
} | |
// alloc memory | |
void *pMem = _malloc_dbg(sizeof(MemoryBlock) + size, _NORMAL_BLOCK, filename, line); | |
// save alloc info | |
MemoryBlock *pBlock = reinterpret_cast<MemoryBlock *>(pMem); | |
pBlock->magic = MAGIC; | |
pBlock->blocksize = size; | |
pBlock->callee = callee; | |
pBlock->filename = filename; | |
pBlock->line = line; | |
pBlock->timeStamp = GetTickCount() - ringHead.timeStamp; | |
// link to ring | |
MemoryBlock * const pHead = &ringHead; | |
pBlock->next = pHead; | |
pBlock->prev = pHead->prev; | |
pHead->prev->next = pBlock; | |
pHead->prev = pBlock; | |
allocIndex++; | |
return pBlock + 1; | |
} | |
void Release(void *object) | |
{ | |
if (object == NULL) { return; } | |
MemoryBlock *pBlock = reinterpret_cast<MemoryBlock *>(object) - 1; | |
if (::IsBadReadPtr(pBlock, sizeof(*pBlock)) || pBlock->magic != MAGIC) | |
{ | |
// unknown memory block... | |
assert(false); | |
return; | |
} | |
// unlink | |
pBlock->prev->next = pBlock->next; | |
pBlock->next->prev = pBlock->prev; | |
// release memory | |
_free_dbg(pBlock, _NORMAL_BLOCK); | |
} | |
void DumpMemoryBlockList(FILE *out) | |
{ | |
if (ringHead.magic != MAGIC) return; | |
for (MemoryBlock *pBlock = ringHead.next; pBlock != &ringHead; pBlock = pBlock->next) | |
{ | |
#define dms(d) (d % 60000 + d / 60000 % 60 * 100000 + d / 3600000 * 10000000) | |
fprintf_s(out, "addr 0x%08X size %8d time%10d from 0x%08X %s:%d\n", | |
pBlock + 1, pBlock->blocksize, dms(pBlock->timeStamp), | |
pBlock->callee, pBlock->filename, pBlock->line); | |
} | |
} | |
} | |
// new/deleteのmapper | |
#pragma push_macro("new") | |
#undef new | |
#define asm __asm | |
#define naked __declspec(naked) | |
#define prologue { asm mov eax, [esp] asm push ebp asm mov ebp, esp asm mov callee, eax } | |
#define epilogue { asm pop ebp asm ret } | |
#define calleeproxy(func, ...) { void *callee; prologue; func(__VA_ARGS__); epilogue; } | |
naked void * operator new (size_t size) calleeproxy(DebugMemoryAllocator::Allocate, size, "????????.cpp", 0, callee); // 確保:ソースはわからん | |
naked void * operator new [](size_t size) calleeproxy(DebugMemoryAllocator::Allocate, size, "????????.cpp", 0, callee); // 確保:ソースはわからん | |
naked void * operator new (size_t size, const char *fn, int line) calleeproxy(DebugMemoryAllocator::Allocate, size, fn, line, callee); // 確保:ソースも分かる | |
naked void * operator new [](size_t size, const char *fn, int line) calleeproxy(DebugMemoryAllocator::Allocate, size, fn, line, callee); // 確保:ソースも分かる | |
naked void operator delete (void *object) calleeproxy(DebugMemoryAllocator::Release, object); // 解放 | |
naked void operator delete [](void *object) calleeproxy(DebugMemoryAllocator::Release, object); // 解放 | |
#pragma pop_macro("new") | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// memory_allocator.hpp | |
void * operator new (size_t size); | |
void * operator new [](size_t size); | |
void * operator new (size_t size, const char *fn, int line); | |
void * operator new [](size_t size, const char *fn, int line); | |
void operator delete (void *object); | |
void operator delete [](void *object); | |
#define new new(__FILE__, __LINE__) | |
namespace DebugMemoryAllocator | |
{ | |
void *Allocate(size_t size, const char *filename, int line, void *callee); | |
void Release(void *object); | |
void DumpMemoryBlockList(FILE *out); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// test.cpp | |
#include <Windows.h> | |
#include <cstdio> | |
#include <crtdbg.h> | |
#include "memory_allocator.hpp" | |
int main(int argc, char* argv []) | |
{ | |
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF); | |
int **mem = new int*[8]; | |
for (int i = 0; i < 8; i++) | |
{ | |
Sleep(1); | |
mem[i] = new int[rand() % 1024]; | |
} | |
DebugMemoryAllocator::DumpMemoryBlockList(stdout); | |
for (int i = 0; i < 8; i++) | |
{ | |
delete mem[i]; | |
} | |
// delete [] mem; //leak | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment