Ted Logan

When memory leaks don't leak

Thursday, 2 February 2006

Not long ago, Visual Studio started complaining about memory leaks. Which was odd, since I really wasn't allocating very much memory.

Detected memory leaks!
Dumping objects ->
{116} normal block at 0x003463A8, 24 bytes long.
Data: <Pc4 Pc4 Pc4 > 50 63 34 00 50 63 34 00 50 63 34 00 00 00 00 00 {115} normal block at 0x00346350, 24 bytes long.
Data: < c4 c4 c4 > A8 63 34 00 A8 63 34 00 A8 63 34 00 CD CD CD CD {114} normal block at 0x003462F0, 32 bytes long.
Data: <A tiff error has> 41 20 74 69 66 66 20 65 72 72 6F 72 20 68 61 73 {113} normal block at 0x00346290, 32 bytes long.
Data: <An error has occ> 41 6E 20 65 72 72 6F 72 20 68 61 73 20 6F 63 63 Object dump complete.

The strings it reported as "leaked" seemed to be the text I initialized a pair of std::strings with, scoped as globals within a source file. So if std::string wasn't freeing its memory, something was horribly wrong. After some long and hard Googling, I came across this post, which revealed the secret: The debug build of MFC will call _CrtDumpMemoryLeaks() when it is unloaded. With the appropriate flags turned on (see _CrtSetDbgFlag()), that handy function will walk the heap and dump, to Visual Studio's Output window, all of the blocks that were allocated and never freed. The only problem is that I built two libraries: one that depended on MFC and one that didn't, and the one that did use MFC was unloaded first. Both of these libraries used the debug C runtime, so any memory allocated by my non-MFC library was reported as memory leaks.

My solution was to force my non-MFC library to link to MFC by telling Visual Studio to link it and by including afx.h in one of my source files. Maybe not the most elegant solution, but it got the job done; now I can concern myself with real memory leaks, which fortunately don't actually exist.

While I'm on the topic of memory leaks in C++, I should note that Microsoft's C runtime's heap dump is especially useful with MFC if one includes the following incantation at the beginning of one's source files:

#ifdef _DEBUG
# define new DEBUG_NEW

DEBUG_NEW will log the source file and line where new was called; _CrtDumpMemoryLeaks() will report that line of code instead of the point deep within the C++ standard library where it actually allocates the memory.

One more exciting C++ standard template library feature (not Microsoft-specific) is auto_ptr. It's a template that behaves (almost) like a regular pointer to a single object, but it automatically frees the pointer when it goes out of scope. It's also possible to assign auto_ptrs to each other, and return them from functions, and it still works exactly the way we expect. (But don't use it to store dynamically-allocated arrays; odds are you'd be better off with a vector<> anyway, since its internal structure is guaranteed to be C-compatible.)