Startup Memory Allocation in PoprC
Arbitrary limits are bad
I’ve written PoprC in an embedded style of C, where malloc()
is avoided. This has a lot of benefits: no dynamic allocation overhead, repeatable addresses which can be used as identifiers, and the ability to use watchpoints when debugging, as well as being able to easily iterate over arrays.
It does have one large drawback, though: because memory is statically allocated, the sizes cannot change. I generally try to set the limits around 2x a reasonable amount, but while this works okay for development, I know it’s not acceptable for end use.
Startup “static” allocation
To address this, I implemented an easy way to perform “static” allocation on startup (in static_alloc.c
. The idea is to perform all allocations with arbitrary limits on startup, which allows the opportunity to adjust the sizes based on flags or a configuration file.
Doing this manually would be annoying, so I used the code generation system that I’ve used elsewhere to collect macros of the form STATIC_ALLOC(name, type, default_size)
. Then, I would translate allocations of the form type name[size]
into that macro throughout PoprC’s source. In addition, there are extended forms of the macro to specify alignment (STATIC_ALLOC_ALIGNED
) and sizes that are dependent on another (STATIC_ALLOC_DEPENDENT
.)
There are a few drawbacks to this system:
- Sizes can’t depend on things not visible in
static_alloc.c
- Types must also be visible in that file.
- Static allocations are in a single namespace, so collisions might be a problem.
- Addresses are no longer static, so some things must be set up on initialization (e.g. in
*_init()
procedures.) - LLDB seems to have more difficulty with
malloc
’ed pointers for some reason.
All of these limitations were fairly easy to work with.
A nice added feature for debugging is the compiler can identify pointers in the allocated region, which is most of the pointers I’m interested in during debugging. I can type pp (some pointer)
in LLDB now to display a description of the form variable[offset]
(see print_static_alloc()
.)
Future work
Some allocations aren’t needed all of the time. I would like to implement a way to perform temporary allocations in an area allocated on startup (using static_alloc.c
) which is large enough to hold the maximum temporary allocation. This would be like a statically allocated union where the fields can be declared anywhere.
I have yet to implement reading allocation sizes from a configuration file, so PoprC is just using the default sizes. After implementing this, it would be good to have assertion messages that indicate which size needs to be adjusted.