I'm about to remove "as many as possible" dynamic heap allocation in my application and I wonder how I can make sure I didn't miss anything.
Currently I'm looking for a way to easily or even automatically tell, if any (or which) parts of the code might invoke the standard implementations of new
/delete
or malloc
/free
without having to dynamically trace allocations (i.e. via static code analysis or feedback from compiler/linker).
It's easy to spot (or search for) code which directly calls new
or malloc
of course:
int main() {
auto s = new std::string();
delete s;
}
Just in case the allocations are hidden deep in a 3rd party library or in cases which are less obvious (like throw
) I can still search for the mangled symbols for new/delete in my binary:
g++ main.cpp
nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
U _ZdlPvm@@CXXABI_1.3.9
U _Znwm@@GLIBCXX_3.4
But this approach will only find direct uses of new/delete/malloc/free
. In case my code (or 3rd party stuff) makes use of the standard library you won't detect it by just calling nm
:
int main() {
std::string a;
for(int i = 0; i < 100; ++i) {
a += "data ";
}
}
My current approach is to link against static standard libraries (-static-libgcc
/ -static-libstdc++
) and look if there's a reference to new
/delete
at all in the whole binary:
g++ -static-libgcc -static-libstdc++ main.cpp
nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
0000000000471fd0 T __cxa_free_dependent_exception
0000000000471f30 T __cxa_free_exception
U free@@GLIBC_2.2.5
U __freelocale@@GLIBC_2.2.5
U malloc@@GLIBC_2.2.5
0000000000471b20 T _ZdlPv
0000000000491bf0 T _ZdlPvm
0000000000471bc0 t _ZN12_GLOBAL__N_14pool4freeEPv.constprop.2
0000000000402a20 t _ZN12_GLOBAL__N_14pool4freeEPv.constprop.2.cold.5
0000000000471e80 T _ZN9__gnu_cxx9__freeresEv
0000000000472240 T _Znwm
0000000000491c00 T _ZnwmRKSt9nothrow_t
0000000000403f37 t _ZnwmRKSt9nothrow_t.cold.0
This approach works for small binaries where you can manage to have zero heap allocations but as soon as you want to allow some allocations (e.g. in code which gets executed only once or in error cases it becomes very difficult to consequently separate code which might allocate heap memory and the stuff which won't.
In the best scenario I can currently imagine the compiler or a static code analyzer provides me with a list of locations in my source code which could result in dynamic heap allocations. This list I could regularly check/filter for cases which are OK in my setup (e.g. bootstrap code or error handling) and those where I have to refactor (e.g. by providing a special allocator).
What are your approaches, tools, experiences?
.heap
segment from the linker files. If something screams at linker stage after that, there's some hidden heap code in some library. The long term solution is to port to C, since it is more suitable for embedded programming. – Lundin