Is there a way to get a stack trace whenever a new one is called in C ++?

I have a long running C ++ program that is usually compiled using gcc (g ++). I used valgrind to check for memory leaks, so I'm not looking for a leak detector.

However, I deal with memory fragmentation and unnecessary new / deleted pairs on temporary buffers / objects.

Is there a way to register all calls to new ones (even if they occur inside STL containers) by providing a stack trace so that I can track them in my code? I tried mtrace, but this only applies to C ++ - it ends up with all distributions happening in the global new distributor when I look at the responsible line of code. Somehow, valgrind memcheck is able to do almost what I want in that it shows stacks of memory allocation traces. Unfortunately, it seems that they are displayed only for distributions without corresponding deallocations.

+4
source share
2 answers

I confirmed Nik B.'s answer by pointing me in the right direction, and this is what I actually did with libunwind instead, since a linked stack offer can only get function names for linked libraries. This code is available on GitHub at https://github.com/landtuna/opnew-stacktraces

newdelete.cpp:

 #include <exception> #include <new> #include <cstdlib> #include <iostream> #include "stacktrace.hpp" void* operator new (size_t size) { void* p = malloc(size); if (p == 0) { throw std::bad_alloc(); } std::cout << "allocated " << size << std::endl; printTrace(std::cout); return p; } void operator delete (void* p) { free(p); } 

stacktrace.cpp:

 #include <cxxabi.h> #include <libunwind.h> #include <ostream> #include <cstdlib> #include <cstring> using namespace std; #include "stacktrace.hpp" void printTrace(ostream& out) { unw_cursor_t cursor; unw_context_t context; unw_getcontext(&context); unw_init_local(&cursor, &context); while (unw_step(&cursor) > 0) { unw_word_t offset, pc; char fname[200]; size_t demangledSize = 200; char* demangled = (char*) malloc(demangledSize); unw_get_reg(&cursor, UNW_REG_IP, &pc); fname[0] = '\0'; unw_get_proc_name(&cursor, fname, sizeof(fname), &offset); int status; char *ret = abi::__cxa_demangle(fname, demangled, &demangledSize, &status); if (ret) { // return value may be a realloc() of the input demangled = ret; } else { // demangling failed, just pretend it a C demangled with no args strncpy(demangled, fname, demangledSize); strncat(demangled, "()", demangledSize); demangled[demangledSize-1] = '\0'; } out << hex << demangled << "+0x" << offset << " [" << pc << "]" << dec << '\n'; free(demangled); } out << endl; } 
+1
source

You can always override the new / delete global functions if you want to track additional distribution statistics:

 void* operator new (size_t size) { void *pPtr = alloc_memory(size); /* perform the allocation here but don't use new! */ if(pPtr == 0) throw std::bad_alloc(); /* additional code here to do whatever sort of tracking you want */ return pPtr; } void operator delete (void *pPtr) { if(pPtr == 0) return; // legal to call delete on NULL pointers - don't pass NULL to free() /* additional code to do whatever tracking you want here */ free(pPtr); } 

As for getting the return line, it depends on the compiler and O / S, and there is no standard way to get to it. Since you mention GCC, the following may work for you:

http://tombarta.wordpress.com/2008/08/01/c-stack-traces-with-gcc/

+6
source

All Articles