Search code examples
c++armembeddedstdcortex-m

Dynamic memory allocation in STD


Working a lot with microcontrollers and C++ it is important for me to know that I do not perform dynamic memory allocations. However I would like to get the most out of the STD lib. What would be the best strategy to determine if a function/class from STD uses dynamic memory allocation?

So far I come up with these options:

  1. Read and understand the STD code. This is of course possible but lets be honest, it is not the easiest code to read and there is a lot of it.
  2. A variation on reading the code could be to have a script search for memory allocation and highlight those parts to it make it easier to read. This still would require figuring out where functions allocating memory are used, and so forts.
  3. Just testing what I would like to use and watch the memory with the debugger. So far I have been using this method but this is a reactive approach. I would like to know before hand when designing code what I can use from STD. Also what is there to say that there are some (edge) cases where memory is allocated. Those might not show up in this limited test.
  4. Finally what could be done is regularly scan the generated assembler code for memory allocations. I suspect this could be scripted and included in the toolchain but again this is a reactive method.

If you see any other options or have experience doing something similar, please let me know.

p.s. I work mainly with ARM Cortex-Mx chips at this moment compiling with GCC.


Solution

  • You have some very good suggestions in the comments, but no actual answers, so I will attempt an answer.

    In essence you are implying some difference between C and C++ that does not really exist. How do you know that stdlib functions don't allocate memory?

    Some STL functions are allowed to allocate memory and they are supposed to use allocators. For example, vectors take an template parameter for an alternative allocator (for example pool allocators are common). There is even a standard function for discovering if a type uses memory

    But... some types like std::function sometimes use memory allocation and sometimes do not, depending on the size of the parameter types, so your paranoia is not entirely unjustified.

    C++ allocates via new/delete. New/Delete allocate via malloc/free.

    So the real question is, can you override malloc/free? The answer is yes, see this answer https://stackoverflow.com/a/12173140/440558. This way you can track all allocations, and catch your error at run-time, which is not bad.

    You can go better, if you are really hardcore. You can edit the standard "runtime C library" to rename malloc/free to something else. This is possible with "objcopy" which is part of the gcc tool chain. After renaming the malloc/free, to say ma11oc/fr33, any call to allocate/free memory will no longer link. Link your executable with "-nostdlib" and "-nodefaultlibs" options to gcc, and instead link your own set of libs, which you generated with objcopy.

    To be honest, I've only seen this done successfully once, and by a programmer you did not trust objcopy, so he just manually found the labels "malloc" "free" using a binary editor, and changed them. It definitely works though.

    Edit: As pointed out by Fureeish (see comments), it is not guaranteed by the C++ standard that new/delete use the C allocator functions. It is however, a very common implementation, and your question does specifically mention GCC. In 30 years of development, I have never seen a C++ program that runs two heaps (one for C, and one for C++) just because the standard allows for it. There would simply be no advantage in it. That doesn't preclude the possibility that there may be an advantage in the future though.
    Just to be clear, my answer assumes new USES malloc to allocate memory. This doesn't mean you can assume that every new call calls malloc though, as there may be caching involved, and the operator new may be overloaded to use anything at all at the global level. See here for GCC/C++ allocator schemes.

    https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html

    Yet another edit:
    If you want to get technical - it depends on the version of libstdc++ you are using. You can find operator new in new_op.cc, in the (what I assume is the official) source repository

    (I will stop now)