# Memory Management: Error in VS2003 headers?

## Recommended Posts

Someone earlier proposed that I use the _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); call to make the VS2003 debugger automatically track memory leaks. However, this generates memory leak reports that tell you nothing about where the data was allocated. Trying to find a way to make this output more useful, I ran accross this MSDN article. Apparently, you can make it track your memory leaks without problems. So I did what is suggested... But it didn't work as planned... This is the output I get for my test memory leak: Detected memory leaks! Dumping objects -> e:\visual studio .net 2003\vc7\include\crtdbg.h(689) : {158} normal block at 0x007C7288, 4 bytes long. Data: < @> 00 00 A0 40 Object dump complete. The program '[1344] engine.exe: Native' has exited with code 0 (0x0). I decided to go check what was at line 689 of crtdbg.h, and had a bad surprise: inline void * __cdecl operator new(size_t s) { return ::operator new(s, _NORMAL_BLOCK, __FILE__, __LINE__); } This looks like a dumb mistake to me. It looks like someone tried to convert a macro into an inline function directly, but was not careful enough. Obviously, the file and line are *always* going to tell me that the allocation is coming from crtdbg.h... I am now trying to decide if I should make my own macro to fix this lameness...

##### Share on other sites
What's wrong with setting a breakpoint at that line? Are there that many placement new's in your project?

Alternatively, you could implement a global placement new yourself.

www.fluidstudios.com

##### Share on other sites
The problem is that it does not behave as the MSDN article suggest. As for other memory managers, they would need to be able to handle memory allocations accross DLL boundaries.

##### Share on other sites
I had the exact same problem, and after downloading several memory leak loggers that didn’t work, I cobbled this together from code I got of the net and studying how the MSDN method is supposed to work. I'm using VS2003 my self so it should be compatible for you.

//MyNew.h#ifndef _MY_NEW_#define _MY_NEW_#include <windows.h>#include <list>using namespace std;      inline void * __cdecl operator new(unsigned int size,                                          const char *file, int line);      inline void __cdecl operator delete(void *p);void AddTrack(DWORD addr,  DWORD asize,  const char *fname, DWORD lnum);void RemoveTrack(DWORD addr);void DumpUnfreed();inline void * __cdecl operator new(unsigned int size,const char *file, int line){	void *ptr = (void *)malloc(size);	AddTrack((DWORD)ptr, size, file, line);	return(ptr);}inline void __cdecl operator delete(void *p){	RemoveTrack((DWORD)p);	free(p);}#ifdef _DEBUG#define DEBUG_NEW new(__FILE__, __LINE__)#else#define DEBUG_NEW new#endif#define new DEBUG_NEW  class ALLOC_INFO { public:	      DWORD	address;	      DWORD	size;	      char	file[128];	      DWORD	line;		  ALLOC_INFO()		  {			  address = 0;			  size = 0;			  line = 0;			  file[0] = 0;		  }		  bool operator ==(const ALLOC_INFO& Rh)		  {			  if(address != Rh.address) return false;			  if(size != Rh.size) return false;			  if(strcmp(file,Rh.file)) return false;			  if(address != Rh.address) return false;			  return true;		  } } ; typedef list<ALLOC_INFO> AllocList;      #endif

//Mynew.cpp#ifdef _DEBUG#include "MYnew.h"static AllocList allocList;      void AddTrack(DWORD addr,  DWORD asize,  const char *fname, DWORD lnum)      {	      ALLOC_INFO info;	     /* if(!allocList) {		      allocList = new(AllocList);	      }*/	      //info = new(ALLOC_INFO);	      info.address = addr;	      strncpy(info.file, fname, 128);	      info.line = lnum;	      info.size = asize;	      allocList.insert(allocList.begin(), info);      };      void RemoveTrack(DWORD addr)      {	      AllocList::iterator i;	      if(!allocList.size())		      return;	      for(i = allocList.begin(); i != allocList.end(); i++)	      {		      if((*i).address == addr)		      {			      allocList.erase(i);			      break;		      }	      }      };      void DumpUnfreed()      {	      AllocList::iterator i;	      DWORD totalSize = 0;	      char buf[1024];	      if(!allocList.size())		      return;	      for(i = allocList.begin(); i != allocList.end(); i++) {		      sprintf(buf, "%-50s:\t\tLINE %d,\t\tADDRESS %d\t%d unfreed\n",			      (*i).file, (*i).line, (*i).address, (*i).size);		      OutputDebugString(buf);		      totalSize += (*i).size;	      }	      sprintf(buf, "-----------------------------------------------------------\n");	      OutputDebugString(buf);	      sprintf(buf, "Total Unfreed: %d bytes\n", totalSize);	      OutputDebugString(buf);      };  #endif

//Put this at the beginning of every file that calls new or delete#ifdef _DEBUG#include "MYnew.h"#endif//Put this where your program exits.#ifdef _DEBUGDumpUnfreed();#endif

##### Share on other sites
Quote:
 Original post by Max_PayneI decided to go check what was at line 689 of crtdbg.h, and had a bad surprise:inline void * __cdecl operator new(size_t s) { return ::operator new(s, _NORMAL_BLOCK, __FILE__, __LINE__); }This looks like a dumb mistake to me. It looks like someone tried to convert a macro into an inline function directly, but was not careful enough. Obviously, the file and line are *always* going to tell me that the allocation is coming from crtdbg.h...I am now trying to decide if I should make my own macro to fix this lameness...

#ifdef _DEBUG#define new DEBUG_NEW#endif // _DEBUG

(You know, these lines we always delete when they are present or never add if they are not [wink])

After you included all your headers? This way, you are supposed to use the correct new() operator (the crtdbg.h one is provided by default if you don't use the DEBUG_NEW macro).

Regards,

##### Share on other sites
I haven't seen any "DEBUG_NEW" definition in my brief look in there. I will look into it. If its simply not present, then I will try to define my own operator new macro and make it work with the crtdbg memory leak tracking.

##### Share on other sites
Well... I almost got it to work.

I did this:

#define CRTDBG_MAP_ALLOC#include <stdlib.h>#include <crtdbg.h>#define new new(s, _NORMAL_BLOCK, __FILE__, __LINE__)

I also enabled automatic memory leak checking. This results in a memory leak report that tells me in which file and line the leaked data was allocated... *But*, it only works for my main binary. I happen to have several modules (dynamically linked DLLs). They also include the above code, and the memory leak report tracks memory leaks from the modules. *However*, it does not keep track of the line numbers, it just says something along the lines of: #File Error#: {158} normal block at ...

My guess is that the data to track the memory allocations is somehow separate from the memory heap itself, and is separate for external modules. This is rather unfortunate. I would really like to be able to track memory leaks everywhere, and know where they were allocated. Unfortunately, I don't know if there is a way to make the crtdbg code do this (I suspect not)... And even if I can, technically, program my own memory leak tracker, its annoying because I have to link the allocation map dynamically by hand. Since I need access to the engine to do this, it means I must count on the idea that nothing is allocated before the DLL interface is initialized. Which is feasible, but somewhat annoying.

Could anyone tell me if there is a mechanism in DLLs that is similar to GetProcAddress(), but for exporting a variable? Or something that could automatically link an exported variable when the DLL is loaded?

##### Share on other sites
Quote:
 Could anyone tell me if there is a mechanism in DLLs that is similar to GetProcAddress(), but for exporting a variable? Or something that could automatically link an exported variable when the DLL is loaded?

GetProcAddress simply scans the export dir, so it works for functions as well as variables. Exporting variables is not something you want to do, though, because it makes delay-loading impossible.
I could rant here about how DLLs for low-level engine components are probably not a good idea at all, but that's most likely not what you want to hear ;)
As for leak detection, here is the way to go: determine owner of an allocation by walking the call stack and derive symbol name+file+line from debug information. Although outdated (update is forthcoming), the code here covers the basics of what it takes to hopefully make leaks no longer an issue :)

## Create an account

Register a new account

• ## Partner Spotlight

• ### Forum Statistics

• Total Topics
627657
• Total Posts
2978472

• 10
• 12
• 22
• 13
• 33