How to make sure no Dynamic Memory is used

In many embedded applications, it is mandatory that memory allocation is static and not dynamic. Means that no calls to things like malloc() or free() shall be used in the application, because they might fail at runtime (out of memory, heap fragmentation).

But when linking with 3rd party libraries or even with the C/C++ standard libraries, how to ensure no dynamic memory is used? The problem can occur as well for C++ objects, or a simple call to printf() which internally requires some dynamic memory allocated.

Zero Heap Size?

An easy (and rather naive) approach is to set the heap size to zero. Most linker script or linker environments have the ability to set the heap size to zero, as below:

However, this won’t help, as most linker scripts just uses the free space between the stack space and the variables (bss): So setting the heap size to zero just assumes a zero reservation, but the _sbrk() of the library will continue to use dynamic memory, potentially crashing into the stack space.

Bottom line: with most linker scripts heap size set to zero will not help anything. It even increases the chances that the heap will crash into the stack as the linker assumes zero usage of heap. But it won’t prevent that the heap is used.

Heap in Linker File

This can be seen from the linker file shown below:

To make sure that no heap is used, the easiest way is to simply remove the .heap allocation in above linker file. Check your linker file for ‘heap’ or something similar, and make sure no memory is allocated for it. Especially make sure that no symbol ‘__prvHeapStart‘ or ‘__prvHeapLimit‘ is used, as they usually are required by the newlib/newlib-nano library dynamic memory allocation.

Linker FreeMarker Scripts

Some environments like the NXP MCUXpresso IDE is using an automatic generation of linker files. But it is easy to deal with this, if you know about the FreeMarker Scripts used by this. The Scripts are located in

<MCUXpresso IDE Installation Path>\ide\Wizards\linker

So I can easily disable the .heap using my modified FreeMarker Script:

__sbrk()

With the heap and its symbols removed, any usage of malloc() should give a linker error, similar to this one:

Invoking: MCU Linker
arm-none-eabi-gcc -nostdlib -Xlinker -Map="AEMBS_tinyK22_HS22.map" -Xlinker --gc-sections -Xlinker -print-memory-usage -Xlinker --sort-section=alignment -Xlinker --cref -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -T "AEMBS_tinyK22_HS22_Debug.ld" -o "AEMBS_tinyK22_HS22.axf" ./utilities/fsl_assert.o ...  ./McuLib/FreeRTOS/FreeRTOShooks.o   
arm-none-eabi/bin/ld.exe: arm-none-eabi/lib/thumb/v7e-m+fp/hard\libcr_newlib_semihost.a(_cr_sbrk.o): in function `_sbrk':
_cr_sbrk.c:(.text._sbrk+0x38): undefined reference to `_pvHeapStart'

Good!

Linker Cross Reference

In case it is not clear what is using memory allocation or causing the error, the linker cross reference can be used. For this the GNU linker –cref option has to be added to the linker options:

This generates an information like below in the linker .map file:

Cross Reference Table

Symbol                                            File
ADC0_DriverIRQHandler                             ./startup/startup_mk22f51212.o
ADC0_IRQHandler                                   ./startup/startup_mk22f51212.o
ADC16_ClearStatusFlags                            ./drivers/fsl_adc16.o
ADC16_Deinit                                      ./drivers/fsl_adc16.o
...
main                                              ./source/main.o
                                                  ./startup/startup_mk22f51212.o
malloc                                            arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-malloc.o)
                                                  arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-rand.o)
                                                  ./drivers/fsl_common.o
mcgConfig_BOARD_BootClockRUN                      ./board/clock_config.o

This gives a list of modules which are using things like malloc().

Image Information

Another way to find out the dependencies is using the ‘Image Information’ view in Eclipse/MCUXpresso, see Listing Code and Data Size for all Files with the GNU size Utility in a Post-Build Action:

FreeRTOS static memory allocation

More on a side-note: FreeRTOS by default is using its own dynamic heap allocation. But it is possible to run the RTOS in a static way (no dynamic memory allocation), see FreeRTOS V9.0.0 with Static Memory Allocation.

Summary

Dynamic memory allocation and usage is not desired in many applications. To prevent usage of malloc() and free(), it is best to remove any heap definition in the linker file, to cause a linker error. Then the GNU linker cross reference table or the image information can be very useful.

Happy linking 🙂

Links

12 thoughts on “How to make sure no Dynamic Memory is used

  1. I much prefer creating __wrap functions like malloc and free and then using a partition/block memory manager. Not allowing malloc and free creates extra work when working with third party libraries and code.

    Liked by 1 person

    • Sure, that’s an approach too. But would pretty much undermine the goal of not using a dynamic memory manager. But it all depends on the application, of course: using your own manager might reduce the problem of memory fragmentation. But it won’t remove the problem possibly not meeting your real-time requirements because the time for allocation or freeing memory is not consistent. Beside of the usual programming errors (double free, memory leaks) this is the main reason why using dynamic memory allocation is not used for any system which shall be reliable (which I assume every system should be?).

      Like

      • Define reliable and real time? Do you consider a cellphone or satellite modem reliable or real time? Are you talking medical devices, aviation, space, etc. with zero room for failure and at time extreme power requirements? What RTOS providers are you going to recommend that does not require a heap and memory management? I recognize your goal, but I do not see a problem statement it solves with real world examples which are needed to to justify the long term effort of removing the heap.

        Liked by 1 person

        • ‘Reliability’ has many aspects, and I consider it as the concern about a system to perform its required function under stated conditions for a defined time.
          And ‘real-time’ as the concern about a system to perform its duties correctly and under the given timing conditions. Each of your mentioned systems (cellphone, satellite modem) has concerns in each domain, with different requirements, so do the other areas you mention (aviation, medical, …) where usually there is a distinction between ‘hard’ and ‘soft’ real-time, with the criteria if some failures are acceptable or not.
          As for the RTOS to be used: this again depends on the requirements and domain you want to use it in, for example if it requires certification or not, or if you want to make your own certification. As for FreeRTOS: it had originally the concept of ‘dynamic heap’, where the RTOS allocates its structures (stack for tasks, internal data structures) on its own dynamic heap. Because of the requirements of certain industries (like medical, aviation) not to use any dynamic allocation, Richard Barry added the feature of a ‘static’ RTOS, means that all previously dynamic parts can be defined as static memory areas.
          The main motivation of not using a dynamic heap is to have a more predictable execution time to meet the real-time requirements, because typical heap implementation maintain a list of memory blocks, and the length of this list affects the execution time, making it difficult to ‘prove’ the real-time requirements met. The other aspect is that depending on the order and usage of the heap, it is subject to memory fragmentation leading possibly to an ‘out-of-memory’ situation.

          Like

  2. Dynamic memory is always an interesting question for Embedded.

    For my former employer chips… the applications were so complicated that using Malloc was actually the only safe way to deal with this problem. My experience was that without dynamic memory you would do things like creating buffer pools… which was another name for your bad implementation of dynamic memory.

    Unfortunately this is just a topic of dogma

    I hope you are well.

    Alan

    >

    Like

    • Hi Alan,
      Thanks for your thoughts, as always!
      Yes, it always has been an interesting question and debate. I think dynamic memory allocation is just a useful thing if done right. I feel it has been ‘banned’ because of all the problems if it is not done properly, putting the usual real-time aspects and possible memory fragmentation aside. But they are not an issue with the right architecture and if the real-time aspects are within boundaries.
      Dynamic memory allocation is in a similar class like stack (overflows) and pointer usage: the usage of the stack, pointers or things like ring buffers are used in safety applications too. So here again: things need to be done properly.
      To me, the thing is much more about awareness, and should not be a dogma: it should be about knowing the possible issues and properly solving things in an engineering way. Guidelines like MISRA and others are a good approach to me, because it creates awareness, and this is probably the most important aspect of it.

      Like

  3. Hi Erich,
    Thank you for a fine article.

    Using malloc might not be a problem in an embedded system, but making sure that it isn’t is difficult.
    Malloc and friends could sneak in by use of sprintf, sscanf and the like.
    Of course calling functions like that from an interrupt is not good practice, but it could happen by mistake.
    In an RTOS the task scheduler might switch in the middle of a malloc call..
    Odds that this happen are probably very low, but it might happen..
    We use FreeRTOS (when using a RTOS at all) and as I see it there’s no guarantee that two tasks using malloc etc will not eventually step on each others toes.
    Let’s says that two tasks uses malloc. Each once a second at a rate of 1ms and that executing malloc (with pants down) takes 20us. One task is capable of interrupting the other.
    So there’s a 1/50.000 risk that a task is interrupted at a critical moment.
    This is only a problem if the interrupting task decides it’s time to use malloc.
    So we’re looking at a 1 out of 500.000 risk every second.
    500.000s is a long time, so finding this problem is tricky.
    I know I’m not getting an A grade for the above calculus.

    Then we have all the hard real time task driven by interrupts directly ,and with a higher priority (more important) that the FreeRTOS tasks and scheduler.
    They should definitely NOT call anything that results in calls to malloc, but it’s hard to tell.

    My advice is to completely skip malloc (and palls) in embedded systems unless it’s a dead simple setup and that rebooting is not an issue.

    Adding this to your linker command line (assuming you’re using Gcc)
    -Wl,–wrap=_malloc_r
    prevents any compile job from succeeding if malloc has been drawn in by mistake.
    Always have a look at your objdump too when making critical software.

    Best Regard
    Jacob

    Like

    • Hi Jacob,
      indeed, as the normal malloc() and friends are definitely not thread-safe. I always pay attention not to use things like printf() and the like, because as you say: depending on the library they could use dynamic memory too.

      Like

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.