Daniel Brahneborg

February 23, 2026

Reducing the risk for memory leaks in C

In addition to the neat cleanup() in gcc, there is a way of thinking about memory usage in C that helps making memory leaks less likely to appear at all. In Rust, the concept of lifetimes of variables is very central, and we can take that concept and simplify it a bit. Basically, the lifetimes now fall into three groups.

  1. Global variables, either in the DATA section of allocated on the heap. When a Unix process exits, all resources are automatically released, so calling free() right before exit() is mostly only meaningful if you want to get the "no leaks are possible" message from Valgrind. This, of course, also makes it easier to spot real leaks.
  2. Data created at one point and used later, maybe by another thread, or when the program has to process an unknown amount of data. This data has to be allocated on the stack, and managed carefully. If this type of data can be avoided, please do it.
  3. Temporary data that is both allocated and released within the same call stack. In existing programs the data may be allocated a few calls down and then released at the top, or the other way around. In the latter case it's quite difficult making sure the data never leaks.

Case 1 is trivial. Allocate in the beginning, release at the end. For more modularity you can use __attribute__((constructor)) and __attribute__((destructor)).

Case 2 is the most difficult, so we want to move as many as possible of these to case 3.

For case 3, you modify the code so the allocation and release are done in the same function. By using cleanup(), these two steps now end up on the lines right next after each other. Unless the data is very large, the allocation can then be replaced by storing the data on the stack. Additionally, pointers to other structures are replaced (when possible) by the structure itself. This way, memory leaks become impossible. For other types of resources such as files and mutexes etc, you just use cleanup().

Memory that is not allocated cannot leak, and as malloc() is relatively slow, with fewer allocations the program becomes slightly faster. You also just have to worry about memory leaks for the limited pieces of data in case 2, instead of all of it.

/Daniel