Skip to content

Instantly share code, notes, and snippets.

@ttsuki
Last active December 25, 2015 00:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ttsuki/98a60653f398062b15e5 to your computer and use it in GitHub Desktop.
Save ttsuki/98a60653f398062b15e5 to your computer and use it in GitHub Desktop.
// 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")
// 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);
}
// 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