DebugNew.cpp 4.2 KB

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