DebugNew.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #ifdef GAMEPLAY_MEM_LEAK_DETECTION
  2. #include <new>
  3. #include <exception>
  4. #include <cstdio>
  5. #include <cstdarg>
  6. struct MemoryAllocationRecord
  7. {
  8. unsigned long address; // address returned to the caller after allocation
  9. unsigned int size; // size of the allocation request
  10. const char* file; // source file of allocation request
  11. int line; // source line of the allocation request
  12. MemoryAllocationRecord* next;
  13. MemoryAllocationRecord* prev;
  14. };
  15. MemoryAllocationRecord* __memoryAllocations = 0;
  16. int __memoryAllocationCount = 0;
  17. void* debugAlloc(std::size_t size, const char* file, int line);
  18. void debugFree(void* p);
  19. #ifdef _MSC_VER
  20. #pragma warning( disable : 4290 )
  21. #endif
  22. void* operator new (std::size_t size, const char* file, int line)
  23. {
  24. return debugAlloc(size, file, line);
  25. }
  26. void* operator new[] (std::size_t size, const char* file, int line)
  27. {
  28. return operator new (size, file, line);
  29. }
  30. void* operator new (std::size_t size) throw(std::bad_alloc)
  31. {
  32. return operator new (size, "", 0);
  33. }
  34. void* operator new[] (std::size_t size) throw(std::bad_alloc)
  35. {
  36. return operator new (size, "", 0);
  37. }
  38. void* operator new (std::size_t size, const std::nothrow_t&) throw()
  39. {
  40. return operator new (size, "", 0);
  41. }
  42. void* operator new[] (std::size_t size, const std::nothrow_t&) throw()
  43. {
  44. return operator new (size, "", 0);
  45. }
  46. void operator delete (void* p) throw()
  47. {
  48. debugFree(p);
  49. }
  50. void operator delete[] (void* p) throw()
  51. {
  52. operator delete (p);
  53. }
  54. void operator delete (void* p, const char* file, int line) throw()
  55. {
  56. operator delete (p);
  57. }
  58. void operator delete[] (void* p, const char* file, int line) throw()
  59. {
  60. operator delete (p);
  61. }
  62. #ifdef _MSC_VER
  63. #pragma warning( default : 4290 )
  64. #endif
  65. // Include Base.h (needed for logging macros) AFTER new operator impls
  66. #include "Base.h"
  67. void* debugAlloc(std::size_t size, const char* file, int line)
  68. {
  69. // Allocate memory + size for a MemoryAlloctionRecord
  70. unsigned char* mem = (unsigned char*)malloc(size + sizeof(MemoryAllocationRecord));
  71. MemoryAllocationRecord* rec = (MemoryAllocationRecord*)mem;
  72. // Move memory pointer past record
  73. mem += sizeof(MemoryAllocationRecord);
  74. rec->address = (unsigned long)mem;
  75. rec->size = size;
  76. rec->file = file;
  77. rec->line = line;
  78. rec->next = __memoryAllocations;
  79. rec->prev = 0;
  80. if (__memoryAllocations)
  81. __memoryAllocations->prev = rec;
  82. __memoryAllocations = rec;
  83. ++__memoryAllocationCount;
  84. return mem;
  85. }
  86. void debugFree(void* p)
  87. {
  88. assert(p);
  89. // Backup passed in pointer to access memory allocation record
  90. void* mem = ((unsigned char*)p) - sizeof(MemoryAllocationRecord);
  91. MemoryAllocationRecord* rec = (MemoryAllocationRecord*)mem;
  92. // Sanity check: ensure that address in record matches passed in address
  93. if (rec->address != (unsigned long)p)
  94. {
  95. gameplay::printError("[memory] CORRUPTION: Attempting to free memory address with invalid memory allocation record.");
  96. return;
  97. }
  98. // Link this item out
  99. if (__memoryAllocations == rec)
  100. __memoryAllocations = rec->next;
  101. if (rec->prev)
  102. rec->prev->next = rec->next;
  103. if (rec->next)
  104. rec->next->prev = rec->prev;
  105. --__memoryAllocationCount;
  106. // Free the address from the original alloc location (before mem allocation record)
  107. free(mem);
  108. }
  109. extern void printMemoryLeaks()
  110. {
  111. // Dump general heap memory leaks
  112. if (__memoryAllocationCount == 0)
  113. {
  114. gameplay::printError("[memory] All HEAP allocations successfully cleaned up (no leaks detected).");
  115. }
  116. else
  117. {
  118. gameplay::printError("[memory] WARNING: %d HEAP allocations still active in memory.", __memoryAllocationCount);
  119. MemoryAllocationRecord* rec = __memoryAllocations;
  120. while (rec)
  121. {
  122. gameplay::printError("[memory] LEAK: HEAP allocation leak of size %d leak from line %d in file '%s'.", rec->size, rec->line, rec->file);
  123. rec = rec->next;
  124. }
  125. }
  126. }
  127. #endif