Background
Dynamic memory in C typically uses malloc, while C++ uses the new operator. On bare-metal systems this often works without special handling, but in RTOS environments you must consider resource protection. If multiple tasks call malloc concurrently, and you do not protect the allocator with interrupt disabling or a mutex, the same memory block could be returned to two tasks or allocator internal global state may be corrupted.
Common operating systems such as freeRTOS and RT-Thread provide their own dynamic memory implementations. It is generally safer to use the allocation routines provided by the OS.
Problem with Legacy Code
When maintaining legacy projects that have widespread use of malloc and new, manually replacing all calls can be time consuming and error prone. An alternative is to redirect the functions while keeping the original names, similar to weak linking used by some standard library functions.
Function Redirection in MDK
In MDK (Keil) you can implement redirection by providing "sub" functions that call the original implementations. Place the following in any C source file:
#include <stdlib.h> #if defined(__CC_ARM) void *$Super$$malloc(size_t); void *$Sub$$malloc(size_t size){ // mutex_lock() void *addr = $Super$$malloc(size); // mutex_unlock() return addr; } void $Super$$free(void *); void $Sub$$free(void *addr){ // mutex_lock() $Super$$free(addr); // mutex_unlock() } #endif
This approach lets upper-layer code remain unchanged. All calls to malloc and free will be routed through the sub functions, where you can add a mutex or tracing statements for debugging.
C++ Replacement Operators
C++ also allows overriding global new and delete operators. Note that many STL templates are not internally thread-safe, for example push_back() may not be protected, so use caution.
#include <cstdlib> void *operator new(size_t size) throw(std::bad_alloc){ void *addr = malloc(size); return addr; } void operator delete(void *addr) throw(){ free(addr); } void *operator new[](size_t size) throw(std::bad_alloc){ void *addr = malloc(size); return addr; } void operator delete[](void *addr) throw(){ free(addr); } void *operator new(std::size_t size, const std::nothrow_t& nothrow){ void *addr = malloc(size); return addr; } void *operator new[](std::size_t size, const std::nothrow_t& nothrow){ void *addr = malloc(size); return addr; }
Summary
This redirection method can be a practical way to introduce synchronization or tracing into existing projects without modifying all call sites.
ALLPCB