Jump to content
  • Advertisement
Sign in to follow this  
M4573R

Memory debugging in large projects

This topic is 2506 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm dusting off some old memory debugging code that overloads new and delete. I'd like to have this code in a separate library, but am not sure how to include my overloads elsewhere without having conflicts. If I try putting it in a pch for a project, I get all sorts of errors in crtdbg, xlocale, etc. I'd like to not have to include this in every source file.

These are the overloads I'm using:
void * operator new(size_t size, const char * file, unsigned line) throw (std::bad_alloc);
void * operator new(size_t size, const char * file, unsigned line, const std::nothrow_t&) throw ();
void * operator new[](size_t size, const char * file, unsigned line) throw (std::bad_alloc);
void * operator new[](size_t size, const char * file, unsigned line, const std::nothrow_t&) throw ();
void operator delete(void * ptr) throw ();
void operator delete(void * ptr, const std::nothrow_t&) throw ();
void operator delete[](void * ptr) throw ();
void operator delete[](void * ptr, const std::nothrow_t&) throw ();
#define new new(__FILE__, __LINE__)

Share this post


Link to post
Share on other sites
Advertisement
The short answer is that you can't use that header globally without causing problems. The basic problem is that you try to turn every single new expression into a placement new expression, including new expressions that are already placement new expressions. I would recommend using an existing leak tracking library for your compiler. If for some reason you can't or don't want to do that, I'd go for changing the default new and delete operators so that it creates a stack walk (partial or full) to get location information without preprocessor mangling.

Share this post


Link to post
Share on other sites
I can do that, I saw a resource describing that process and can find it again. Though I'll still need to replace new/delete to do it. I was also having a problem with an stl container calling my delete, but not my new. Is there a more manual way to replace new/delete that only I will use (like a NEW macro).

Share this post


Link to post
Share on other sites
You can, if you want, create a macro named NEW that will expand to new (__FILE__, __LINE__). That won't change the fact that some allocations will be made with your version of operator new and some won't, which is the root of the deletion issue. In order to solve that you'd need to create a custom deleter to call the destructor and release the memory. It's really not worth the effort and creates non-idiomatic code.

Share this post


Link to post
Share on other sites
Agreed, it doesn't sound like a great way to go. I wanted to use crt leak checking but I still have to redefine new for the file and line to show up, but it has the issue where I can't define it globally which is irritating.

Share this post


Link to post
Share on other sites
It's probably too late now, but in most of the game engines/middleware that I've used, they've avoided this problem by not using new/malloc/delete/free directly ever in their code-bases. Instead they use a macro replacement, such as 'myNew', which makes hijacking your own allocations easier (but not screwing up other libraries like the stl)

Share this post


Link to post
Share on other sites
So I did some more research, and alloc hooks using the crt seems sufficient enough for what I'm doing. However documentation on it is awful. My google-fu is completely failing me. I can record allocs fine, but when I get frees, I only have a point and must somehow get at the _CrtMemBlockHeader which is not defined for my use. Resources I've found use something called "pHdr" to go from pointer to header, but I can't find a single piece of official documentation on it. Any thoughts?

Edit: It appears people are redefining a matching _CrtMemBlockHeader locally that matches the one in dbgint.h, then manually grabbing the pointer to it by casting an allocation to it and subtracting 1. That feels completely gross. Why is there not a better way to do this? Why does the documention on the CRT not describe how to grab information from a free in your alloc hook? There is no other way to match a request ID of an allocation to a pointer otherwise.

Yet another edit: Since I don't want to define the debug new everywhere so the crt can pickup and file and line numbers, is there a way I can hook the output and translate its output to symbols manually?

Share this post


Link to post
Share on other sites
Yet another edit: Since I don't want to define the debug new everywhere so the crt can pickup and file and line numbers, is there a way I can hook the output and translate its output to symbols manually?
[/quote]

The methods described here have always worked for me. I get a file and line number without having to make a new macro, and it counts the allocations so you can see which alloc numbers leak and then re-run the program and break on those allocs to see exactly what context they happen in. Of course that only works while your code remains deterministic, such as at startup.

Some people don't get the line numbers and files for some reason, I never looked into why since it never happened to me.

Share this post


Link to post
Share on other sites
Why not use the stack walking method? That's what I've always done, and it works fine with the STL and my own allocations alike.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!