test.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/test.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 7/23/99 7:23p $*
  29. * *
  30. * $Revision:: 6 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. //#define _CATCH_MEM_LEAKS
  36. #if (defined(_CATCH_MEM_LEAKS) && defined (_DEBUG))
  37. #include "Windows.H"
  38. #include "Winnt.H"
  39. #include "ImageHlp.H"
  40. extern void *_ptr_array[10000];
  41. extern int g_allocs;
  42. extern int g_frees;
  43. typedef struct {
  44. char function_name[80];
  45. } MY_DEBUG_INFO;
  46. const int DATA_LEVELS = 5;
  47. const DATA_SIZE = sizeof (MY_DEBUG_INFO) * DATA_LEVELS;
  48. void *_ptr_array[10000] = { 0 };
  49. int g_allocs = 0;
  50. int g_frees = 0;
  51. bool _g_binit = false;
  52. class ReportDebugClass
  53. {
  54. public:
  55. ReportDebugClass (void) {}
  56. ~ReportDebugClass (void)
  57. {
  58. int counter = 0;
  59. for (int index = 0; index < 10000; index ++) {
  60. if (_ptr_array[index] != 0) {
  61. MY_DEBUG_INFO debug_info[DATA_LEVELS] = { 0 };
  62. ::memcpy (debug_info, ((char*)(_ptr_array[index]))-DATA_SIZE, DATA_SIZE);
  63. counter ++;
  64. ::OutputDebugString ("Possible memory leak for stack:\n");
  65. for (int ilevel = 0; ilevel < DATA_LEVELS; ilevel ++) {
  66. ::OutputDebugString ("\t");
  67. ::OutputDebugString (debug_info[ilevel].function_name);
  68. ::OutputDebugString ("\n");
  69. }
  70. ::OutputDebugString ("\n");
  71. }
  72. }
  73. return ;
  74. }
  75. };
  76. ReportDebugClass _debug_class;
  77. ///////////////////////////////////////////////////////////////////////////
  78. //
  79. // ::operator new
  80. //
  81. void *
  82. ::operator new (size_t size)
  83. {
  84. if (_g_binit == false) {
  85. _g_binit = true;
  86. ::SymInitialize (::GetCurrentProcess (), NULL, TRUE);
  87. }
  88. CONTEXT context = { 0 };
  89. HANDLE hthread = ::GetCurrentThread ();
  90. context.ContextFlags = CONTEXT_FULL;
  91. ::GetThreadContext (hthread, &context);
  92. HANDLE hthread2 = NULL;
  93. DuplicateHandle (::GetCurrentProcess (), hthread, ::GetCurrentProcess (), &hthread2, THREAD_ALL_ACCESS | THREAD_GET_CONTEXT, FALSE, 0);
  94. context.ContextFlags = CONTEXT_FULL;
  95. ::GetThreadContext (hthread2, &context);
  96. ::CloseHandle (hthread2);
  97. MY_DEBUG_INFO debug_info[DATA_LEVELS] = { 0 };
  98. // Initialize the STACKFRAME structure for the first call. This is only
  99. // necessary for Intel CPUs, and isn't mentioned in the documentation.
  100. STACKFRAME sf = { 0 };
  101. sf.AddrPC.Offset = context.Eip;
  102. sf.AddrPC.Mode = AddrModeFlat;
  103. sf.AddrStack.Offset = context.Esp;
  104. sf.AddrStack.Mode = AddrModeFlat;
  105. sf.AddrFrame.Offset = context.Ebp;
  106. sf.AddrFrame.Mode = AddrModeFlat;
  107. // Walk the stack up to DATA_LEVELS calls
  108. for (int iframe = 0; iframe < DATA_LEVELS+1; iframe ++)
  109. {
  110. // Get a stack trace for this frame
  111. if (!::StackWalk (IMAGE_FILE_MACHINE_I386,
  112. GetCurrentProcess (),
  113. GetCurrentThread (),
  114. &sf,
  115. &context,
  116. 0,
  117. SymFunctionTableAccess,
  118. SymGetModuleBase,
  119. 0)) {
  120. break;
  121. }
  122. // Basic sanity check to make sure
  123. if (sf.AddrFrame.Offset == 0) {
  124. break;
  125. }
  126. // IMAGEHLP is wacky, and requires you to pass in a pointer to an
  127. // IMAGEHLP_SYMBOL structure. The problem is that this structure is
  128. // variable length. That is, you determine how big the structure is
  129. // at runtime. This means that you can't use sizeof(struct).
  130. // So...make a buffer that's big enough, and make a pointer
  131. // to the buffer. We also need to initialize not one, but TWO
  132. // members of the structure before it can be used.
  133. BYTE symbol_buffer [sizeof(IMAGEHLP_SYMBOL) + 512];
  134. PIMAGEHLP_SYMBOL psymbol = (PIMAGEHLP_SYMBOL)symbol_buffer;
  135. ::memset (symbol_buffer, 0, sizeof (symbol_buffer));
  136. psymbol->SizeOfStruct = sizeof(symbol_buffer);
  137. psymbol->MaxNameLength = 512;
  138. DWORD sym_displacement = 0;
  139. if (::SymGetSymFromAddr (::GetCurrentProcess (),
  140. sf.AddrPC.Offset,
  141. &sym_displacement,
  142. psymbol))
  143. {
  144. // We don't care about the first stack frame (its inside the GetThreadContext call)
  145. if (iframe >=1) {
  146. ::lstrcpyn (debug_info[iframe-1].function_name, psymbol->Name, sizeof (MY_DEBUG_INFO)-1);
  147. debug_info[iframe-1].function_name[sizeof (debug_info[iframe-1].function_name)-1] = 0;
  148. }
  149. } else {
  150. DWORD dwerror = ::GetLastError ();
  151. int itest = 0;
  152. }
  153. }
  154. // Allocate the buffer + our debug information
  155. void *ptr = ::malloc (size + DATA_SIZE);
  156. ::memcpy (ptr, debug_info, DATA_SIZE);
  157. // Stick the new buffer into our array (should be moved to linked list)
  158. if (ptr) {
  159. for (int index = 0; index < 10000; index ++) {
  160. if (_ptr_array[index] == 0) {
  161. _ptr_array[index] = (void *)(((char *)ptr) + DATA_SIZE);
  162. break;
  163. }
  164. }
  165. }
  166. g_allocs ++;
  167. // Return the pointer
  168. return (void*)(((char *)ptr) + DATA_SIZE);
  169. }
  170. ///////////////////////////////////////////////////////////////////////////
  171. //
  172. // :::operator delete
  173. //
  174. void
  175. ::operator delete (void *ptr)
  176. {
  177. if (ptr) {
  178. // Attempt to find the buffer in our array
  179. bool bfound = false;
  180. for (int index = 0; index < 10000; index ++) {
  181. if (_ptr_array[index] == ptr) {
  182. ::free ((void*)(((char *)ptr) - DATA_SIZE));
  183. _ptr_array[index] = 0;
  184. bfound = true;
  185. break;
  186. }
  187. }
  188. // If we didn't find it in our array, just free it
  189. if (!bfound) {
  190. //::free (ptr);
  191. }
  192. }
  193. g_frees ++;
  194. return ;
  195. }
  196. #endif //defined(_CATCH_MEM_LEAKS) && defined (_DEBUG)