Skip to content
tomdionysusPublic

About

Minimal malloc/free heap allocator in C99 for embedded systems and microcontrollers, under 1 KB on Cortex-M, with configurable alignment and optional misuse checks.

Topics

Resources

Code of conduct

Stars

36 stars

Watchers

2 watching

Forks

Repository files navigation

pmalloc

Release CI CodeQL codecov License: MIT

A minimal C library to manage memory with a familiar malloc/free pattern, on embedded systems with no heap of their own, or to sub-allocate within a block of memory given by the OS.

  • Two files, src/pmalloc.h and src/pmalloc.c, in plain C99 with no dependencies.
  • Under 1 KB of code on a Cortex-M (784 bytes on Cortex-M0, -Os).
  • malloc, calloc, realloc and free, with every returned pointer aligned to a configurable boundary.
  • Any number of separate memory regions in one heap.

Getting started

1. Add pmalloc to your project

Copy the files. Add src/pmalloc.h and src/pmalloc.c to your build. This suits most embedded toolchains.

Or use CMake. With pmalloc in a subdirectory, or fetched:

include(FetchContent)
FetchContent_Declare(pmalloc GIT_REPOSITORY https://github.com/tomdionysus/pmalloc.git GIT_TAG 0.3.0)
FetchContent_MakeAvailable(pmalloc)

target_link_libraries(your_target PRIVATE pmalloc::pmalloc)

As a subproject, pmalloc builds only the library, not its tests or examples.

Or install it and use find_package:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build --prefix /your/prefix
find_package(pmalloc 0.3 CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE pmalloc::pmalloc)

2. Give it memory and allocate

#include "pmalloc.h"

static pmalloc_t heap;
static unsigned char memory[16384];  // or a fixed address and size on your board

int main(void) {
  pmalloc_init(&heap);
  pmalloc_addblock(&heap, memory, sizeof(memory));

  char *buffer = pmalloc_malloc(&heap, 256);
  if (buffer == NULL) return 1;  // out of memory

  char *bigger = pmalloc_realloc(&heap, buffer, 512);
  if (bigger != NULL) buffer = bigger;  // on failure, buffer is still valid

  pmalloc_free(&heap, buffer);
  return 0;
}

There are full programs in example: basic and suballocation.

3. Set the alignment, if you need to

Every pointer pmalloc returns is aligned to PMALLOC_ALIGN bytes, which defaults to the size of a pointer. If you store double or uint64_t on a 32-bit target, or SIMD types, raise it:

cc -DPMALLOC_ALIGN=8 -c src/pmalloc.c       # copying the files
cmake -S . -B build -DPMALLOC_ALIGN=16      # with CMake

It must be a power of two, at least the size of a pointer.

4. Turn on checks while you develop

Build with PMALLOC_CHECKS defined (-DPMALLOC_CHECKS=ON with CMake) and pmalloc refuses double frees, pointers it did not return and overlapping regions instead of corrupting the heap, and calls a hook of yours so you can stop on the bug. It costs about 130 bytes of code and a list walk per call, and nothing at all when left off. See PMALLOC_CHECKS.

Documentation

The API reference covers every function, the memory layout, the configuration and the caveats.

Building and testing

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DPMALLOC_WARNINGS_AS_ERRORS=ON
cmake --build build -j
./build/pmalloc_tests

The tests use Unity, vendored in test/vendor/unity, so nothing is downloaded. A Debug build also enables pmalloc_dump_stats.

Option Default Effect
PMALLOC_ALIGN pointer size Alignment of every block and returned pointer
PMALLOC_CHECKS OFF Validate every pointer and region passed in
PMALLOC_BUILD_TESTING ON when top level Build pmalloc_tests
PMALLOC_BUILD_EXAMPLES ON when top level Build the examples
PMALLOC_WARNINGS_AS_ERRORS OFF Treat compiler warnings as errors
PMALLOC_COVERAGE OFF Instrument for coverage with GCC or Clang

To measure coverage locally with GCC and gcovr:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DPMALLOC_COVERAGE=ON
cmake --build build -j
./build/pmalloc_tests
gcovr --root . --filter src/ --object-directory build

Caveats

pmalloc is built for minimalism. Unless built with PMALLOC_CHECKS, it does not defend against misuse: freeing a pointer it did not allocate or freeing twice corrupts the heap, and writing past a block always does. It is not thread safe. Sizes are 32-bit. See Caveats.

Contributing

PRs and comments welcome. Please see the Code Of Conduct for community guidelines. Changes are listed in the changelog.

License

MIT. See LICENSE.txt. The vendored Unity test framework is MIT licensed by its authors; see test/vendor/unity/LICENSE.txt.

About

Minimal malloc/free heap allocator in C99 for embedded systems and microcontrollers, under 1 KB on Cortex-M, with configurable alignment and optional misuse checks.

Topics

Resources

Code of conduct

Stars

36 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages