This feature is well documented, but yet from what I see – doesn’t get the usage it deserves. Here’s a quick, beginner-oriented rehash – if only to refer my teammates.
Problem and Immediate Solution
If you’re developing MFC apps, the way you’ll usually notice any leaks is by terminating your app and seeing the following in the output window:
Detected memory leaks!
Dumping objects ->
C:\myfile.cpp(20): {130} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
the {130} is emphasized on purpose – it is the serial number of the leaking allocation. What if you could count allocation occurrences, and break in exactly the leaky one? You could not only get a complete stack trace for the leak, but even step and debug it!
Well, it might not be that easy. If the allocation serial number is not consistent across multiple runs, it means the leaking memory is allocated in a threaded code portion. In such cases, you’re probably better off resorting to other methods.
Now if the serial number is consistent, what allocations exactly does it count? In what API do you brake?? must you really set a breakpoint with a ‘hit count’ there? If the number is high, it could easily get prohibitively slow.
Happily, there is an easy solution to the second set of worries. Early in your code, call –
_CrtSetBreakAlloc(130)
Mid-depth Dive
The _CrtSetBreakAlloc trick is an iceberg-tip of some heavier CRT machinery. It is entirely operated for you if you use MFC, but you can use it yourself in non-MFC apps (although you should watch out for some issues).
The dump that starts it all is the output of _CrtDumpMemoryLeaks. You can call it directly in your app – but if you’re down to a binary search for the leak , you might prefer _CrtMemDumpAllObjectsSince for more fine-grained control of the allocations you dump. Maybe more on that in a future post.
The allocation counter resides in the undocumented _heap_alloc_dbg, which channels calls from all C allocators – namely new, malloc, and their brethren (_malloc_dbg, aligned /offset flavours, etc.). This is a CRT apparatus, so naturally it won’t catch direct OS allocations (HeapAlloc, VirtualAlloc et. al.), not to mention COM allocators (SysAllocString, CoTaskMemAlloc etc.).
When you do set an allocation breakpoint, you’d (naturally) break in the counting function itself, _heap_alloc_dbg. Your own code probably resides a good 4-5 stack levels below – go there and debug away.
Bonus
You can do all the above at runtime, from the debugger. The documentation for VS2005 says you can put –
{,,msvcr71d.dll}_crtBreakAlloc
in the watch window, and modify its contents directly (say, to 130). However, the documentation is wrong in 3 places.
- For VS2005, the correct dll version is msvcr80d.dll. This seems to have been fixed for the VS2008 and VS2010 pages.
- When using the context operator, you must use decorated symbol names – which amounts to adding another underscore.
- The value is an int*, and for some reason my debugger fails to deduce it himself.
All in all, just type at the watch window –
(int*){,,msvcr80d.dll}__crtBreakAlloc
And debug happily ever after.
I have been pondering on that serial number for quite a few years, and new found a good tutorial on it.
This really solves a lot of mysteries.
Thanks for the article.
Pingback: Debugging Memory Leaks, Part 3: Breaking on Allocations of Given Size « Ofek's Visual C++ stuff
Pingback: Debugging Reference Count – Part 1 « Ofek's Visual C++ stuff