Many projects have several levels of assertion-checking macros.
- Checks that are too expensive to be coded into the production application, but which can be compiled in by a switch
- Checks that are still done in the production application, which crash the application if they fail
- Checks that generate a warning message in the production application, but the application continues
Another common strategy is to have code that can be controlled from the command line that shows in detail the behavior of a subsystem as it executes. The command line support can be very specific about what traces are being emitted.
In addition to Assertions, for complex data structures there can be algorithms that check that they are at least consistent. This is especially useful in C code where the data structures are often maintained using inline code rather than calling methods - for instance to add an item to a linked list.
The following exist
There is support in include/base.h for debugging memory leaks.
Start by uncommenting #define DEBUG_MEMLEAK, and rebuilding. This causes all the malloc et. al. and free et. al. to go through instrumented code, including passing their FILE and LINE. This makes it possible to associate every allocation with this information.
In utils/mgh_malloc.c, this instrumentation is conditionalized on DEBUG_MEMLEAK to track all allocations. Every time the total allocated memory crosses the next threshold, it outputs a summary showing where all the currently allocated memory was allocated, with the increasing ones at the end.
After the fixes that prompted this addition, the size stabilized before the first CORRECTING DEFECT of mris_fix_topology, and no further summaries are emitted.
The special command line needed to build this is
make CCLD="g++ -Wl,--wrap=free -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=realloc -Wl,--wrap=posix_memalign"