How to make sure no dynamic memory is used
mcuoneclipse.com
mcuoneclipse.com
I think I need to go tweak LwIP and rip out esp_modem for a custom PPPoS implementation — as currently it leaks memory every socket creation (and we’re not the only ones to hit it)
I do wish we could've gone to Zephyr instead, it has real promise IMO. Though I'm biased because I prefer the Linux kernel-like approach haha
However, in this case, I wonder how well -fsanitize=leak might work. Override free() to show when it is called & print a stack trace, and you get a good look at your system's actual allocation pattern.
As an aside, there's nothing wrong with malloc in these embedded environments, it's the freeing that causes memory fragmentation. If you can also avoid running out of memory, you're good to go, since you essentially have a fancy form of static allocation!
Nope. Consider for examle a microcontroller with 64K of address space, consisting of 32K of low RAM, 8K of ROM/MMIO, and 24K of high RAM. Allocate buffers of size 23K, 15K, and 15K. With a straightforward first-fit allocator[0], you'll put the 23K in low RAM, leaving 9K, put the first 15K in high RAM, leaving 9K there, and fail to allocate the second 15K, because even though you have 18K free, it's fragmented into two 9K regions.
If you'd allocated that memory statically, you could have put the 23K in high RAM, and the two 15Ks in low RAM, with 2K low and 1K high left over.
It's debatable whether the fragmentation is 'caused' by malloc itself or by the ROM region in the middle of the address space, but you never called free, so it's not caused by free.
0: Less naive allocation strategies take more work to 'trap' like this, but I can work out a example for best-fit or whatever if you're sceptical that this isn't just a problem specific to first-fit.
Really? That is the best alternative compared to:
- create a linker warning against malloc, calloc, realloc, ...
- get the symbols of the compiled image, and fail the build if the above are referenced
- other ideas: eliminating the allocator code from the image? (Why have it there if it's not called?)
He explains how to detect the symbols later in the article.
> - other ideas: eliminating the allocator code from the image? (Why have it there if it's not called?)
Because you want to detect if it is called indirectly by some function you're calling.
> create a linker warning against malloc, calloc, realloc, ...
This prints something on a screen. It does not prevent the usage.
> get the symbols of the compiled image, and fail the build if the above are referenced
It was used, and now you've detected its usage. It did not prevent the usage.
> eliminating the allocator code from the image? (Why have it there if it's not called?)
This requires attention, and a deep knowledge of all the code. It doesn't prevent the usage, since you’re free to type “malloc()” with your fingers.
Sometimes you need an explosive guarantee!
-Werror=...?
> It was used, and now you've detected its usage. It did not prevent the usage. foo_image: $(OBJS)
....
if $(NM) $@ | grep -s -E 'malloc|...' ; then \
echo "dynamic allocation not allowed" ; \
exit 1 ; \
fiThat said, the specific use of a function called sbrk seems odd and maybe archaic, since it has no useful role if the heap is fixed-sized anyway. But it looks like newlib (the libc being used here) uses _sbrk as part of an abstraction that supports many different environments [1], including not just bare metal but also running as a userland program under Linux and other kernels. So maybe it makes sense.
[1] https://github.com/eblot/newlib/search?q=_sbrk&type=code
I think most things (?) are dynamically-allocated in Python. This kind of manual memory management doesn’t exist there, which is one of the reasons it’s not used for bare-metal programming.
In Rust, you just use no_std for small embedded work.
The problem was how to make sure 3rd party libraries don't allocate.
And as a follow up, why use rust if allocations mean ownership rules are no longer needed?
Ownership still matters, because nothing about ownership cares about heap allocation vs stack allocation.
Could be:
- zig stdlib functions take an allocator as a parameter for dynamic memory datatypes and you can supply a static allocator
- in the near future it will be possible to link c libraries against a modular libc written in zig, so you will be able to use c code that uses malloc in a statically allocation-only context.
The second one should be exciting for embedded c developers because with a little work zig could be worked into a c toolchain so that with otherwise almost no zig code you can use a c library, or, ambitiously a c++ library, that assumes malloc in an embedded application
Sad that C doesn't. Ada does, Rust does, Zig does, plenty of other languages do, C does not, which is hilariously odd considering how often C has to run in places that don't have a heap.
I occasionally see this where I respond to what someone says, and get a reply along the lines of "they could have said this other thing", like that's relevant. It baffles me every time. They didn't say your smarter thing, they said their silly thing.
I guess projecting your smarter ideas on someone else's comment is one of the better mistakes you can make...