| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : LevelEdit *
- * *
- * $Archive:: /Commando/Code/Tools/LevelEdit/test.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 7/23/99 7:23p $*
- * *
- * $Revision:: 6 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- //#define _CATCH_MEM_LEAKS
- #if (defined(_CATCH_MEM_LEAKS) && defined (_DEBUG))
- #include "Windows.H"
- #include "Winnt.H"
- #include "ImageHlp.H"
- extern void *_ptr_array[10000];
- extern int g_allocs;
- extern int g_frees;
- typedef struct {
- char function_name[80];
- } MY_DEBUG_INFO;
- const int DATA_LEVELS = 5;
- const DATA_SIZE = sizeof (MY_DEBUG_INFO) * DATA_LEVELS;
- void *_ptr_array[10000] = { 0 };
- int g_allocs = 0;
- int g_frees = 0;
- bool _g_binit = false;
- class ReportDebugClass
- {
- public:
- ReportDebugClass (void) {}
- ~ReportDebugClass (void)
- {
- int counter = 0;
- for (int index = 0; index < 10000; index ++) {
- if (_ptr_array[index] != 0) {
- MY_DEBUG_INFO debug_info[DATA_LEVELS] = { 0 };
- ::memcpy (debug_info, ((char*)(_ptr_array[index]))-DATA_SIZE, DATA_SIZE);
- counter ++;
- ::OutputDebugString ("Possible memory leak for stack:\n");
- for (int ilevel = 0; ilevel < DATA_LEVELS; ilevel ++) {
- ::OutputDebugString ("\t");
- ::OutputDebugString (debug_info[ilevel].function_name);
- ::OutputDebugString ("\n");
- }
- ::OutputDebugString ("\n");
- }
- }
- return ;
- }
- };
- ReportDebugClass _debug_class;
- ///////////////////////////////////////////////////////////////////////////
- //
- // ::operator new
- //
- void *
- ::operator new (size_t size)
- {
- if (_g_binit == false) {
- _g_binit = true;
- ::SymInitialize (::GetCurrentProcess (), NULL, TRUE);
- }
- CONTEXT context = { 0 };
- HANDLE hthread = ::GetCurrentThread ();
- context.ContextFlags = CONTEXT_FULL;
- ::GetThreadContext (hthread, &context);
- HANDLE hthread2 = NULL;
- DuplicateHandle (::GetCurrentProcess (), hthread, ::GetCurrentProcess (), &hthread2, THREAD_ALL_ACCESS | THREAD_GET_CONTEXT, FALSE, 0);
- context.ContextFlags = CONTEXT_FULL;
- ::GetThreadContext (hthread2, &context);
- ::CloseHandle (hthread2);
- MY_DEBUG_INFO debug_info[DATA_LEVELS] = { 0 };
- // Initialize the STACKFRAME structure for the first call. This is only
- // necessary for Intel CPUs, and isn't mentioned in the documentation.
- STACKFRAME sf = { 0 };
- sf.AddrPC.Offset = context.Eip;
- sf.AddrPC.Mode = AddrModeFlat;
- sf.AddrStack.Offset = context.Esp;
- sf.AddrStack.Mode = AddrModeFlat;
- sf.AddrFrame.Offset = context.Ebp;
- sf.AddrFrame.Mode = AddrModeFlat;
-
- // Walk the stack up to DATA_LEVELS calls
- for (int iframe = 0; iframe < DATA_LEVELS+1; iframe ++)
- {
- // Get a stack trace for this frame
- if (!::StackWalk (IMAGE_FILE_MACHINE_I386,
- GetCurrentProcess (),
- GetCurrentThread (),
- &sf,
- &context,
- 0,
- SymFunctionTableAccess,
- SymGetModuleBase,
- 0)) {
- break;
- }
- // Basic sanity check to make sure
- if (sf.AddrFrame.Offset == 0) {
- break;
- }
- // IMAGEHLP is wacky, and requires you to pass in a pointer to an
- // IMAGEHLP_SYMBOL structure. The problem is that this structure is
- // variable length. That is, you determine how big the structure is
- // at runtime. This means that you can't use sizeof(struct).
- // So...make a buffer that's big enough, and make a pointer
- // to the buffer. We also need to initialize not one, but TWO
- // members of the structure before it can be used.
- BYTE symbol_buffer [sizeof(IMAGEHLP_SYMBOL) + 512];
- PIMAGEHLP_SYMBOL psymbol = (PIMAGEHLP_SYMBOL)symbol_buffer;
- ::memset (symbol_buffer, 0, sizeof (symbol_buffer));
- psymbol->SizeOfStruct = sizeof(symbol_buffer);
- psymbol->MaxNameLength = 512;
- DWORD sym_displacement = 0;
- if (::SymGetSymFromAddr (::GetCurrentProcess (),
- sf.AddrPC.Offset,
- &sym_displacement,
- psymbol))
- {
- // We don't care about the first stack frame (its inside the GetThreadContext call)
- if (iframe >=1) {
- ::lstrcpyn (debug_info[iframe-1].function_name, psymbol->Name, sizeof (MY_DEBUG_INFO)-1);
- debug_info[iframe-1].function_name[sizeof (debug_info[iframe-1].function_name)-1] = 0;
- }
- } else {
- DWORD dwerror = ::GetLastError ();
- int itest = 0;
- }
- }
- // Allocate the buffer + our debug information
- void *ptr = ::malloc (size + DATA_SIZE);
- ::memcpy (ptr, debug_info, DATA_SIZE);
- // Stick the new buffer into our array (should be moved to linked list)
- if (ptr) {
- for (int index = 0; index < 10000; index ++) {
- if (_ptr_array[index] == 0) {
- _ptr_array[index] = (void *)(((char *)ptr) + DATA_SIZE);
- break;
- }
- }
- }
- g_allocs ++;
- // Return the pointer
- return (void*)(((char *)ptr) + DATA_SIZE);
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // :::operator delete
- //
- void
- ::operator delete (void *ptr)
- {
- if (ptr) {
- // Attempt to find the buffer in our array
- bool bfound = false;
- for (int index = 0; index < 10000; index ++) {
- if (_ptr_array[index] == ptr) {
- ::free ((void*)(((char *)ptr) - DATA_SIZE));
- _ptr_array[index] = 0;
- bfound = true;
- break;
- }
- }
- // If we didn't find it in our array, just free it
- if (!bfound) {
- //::free (ptr);
- }
- }
- g_frees ++;
- return ;
- }
- #endif //defined(_CATCH_MEM_LEAKS) && defined (_DEBUG)
|