Read a GNU malloc Trace with mtrace
You will compile a small C program with debug information, collect its GNU malloc trace, and ask mtrace to identify memory that was not freed. Allow about fifteen minutes. You need a shell, a C compiler, GNU C Library tracing support, and permission to write a temporary directory. This is a diagnostic workflow: it does not change system services or install anything.
The route
Jump straight to the step you need, or tick off Done means at the end.
The examples describe the Linux man-pages 6.7 interface. On the inspected host, package manpages is version 6.7-2; the manual page is installed, but the mtrace executable is not on PATH. Treat that as a real prerequisite failure, not as evidence that the test program has no leak.
1. Check the interpreter before creating a trace
mtrace is a Perl script according to the local manual. It interprets a trace file produced by the C library's mtrace(3) function. Check the executable and its help output first:
$ command -v mtrace
/usr/bin/mtrace
$ mtrace --version
GNU mtrace (GNU libc) ...
The exact version text depends on the GNU C Library installation. The command above is representative output from a host where the tool is installed, not output from this inspected host. On the inspected host, command -v mtrace returns status 1 and prints nothing. Stop there and install or enable the GNU C Library debugging tooling through your normal package-management process. Do not copy a script from an untrusted website into /usr/bin.
Once the command exists, record its location and version:
$ command -v mtrace
$ mtrace --version
Checkpoint
Continue only when the interpreter runs and the command's version output is visible.
2. Create a deliberately leaky test
Use a private working directory so the trace and executable are easy to remove. The program calls mtrace(), allocates memory, and intentionally leaves it allocated at exit. Compile with -g; the extra debug information lets the interpreter attach source locations to reports.
$ work=/tmp/mtrace-demo
$ mkdir -p "$work"
$ cd "$work"
$ cat > demo.c <<'EOF'
#include <mcheck.h>
#include <stdlib.h>
int
main(void)
{
mtrace();
malloc(128);
return 0;
}
EOF
$ cc -g demo.c -o demo
The source is intentionally a test fixture. Do not use this pattern as production code. The compiler may warn about ignoring the return value; that warning does not prevent the tracing demonstration from working.
Verify the binary is present and contains debug information if file is available:
$ file demo
demo: ELF 64-bit ... with debug_info, not stripped
The architecture wording will differ. The useful part is that compilation succeeded and the binary is not stripped.
3. Run the program with a fresh trace file
Set MALLOC_TRACE to a writable pathname and run the program. The C library opens that pathname when mtrace() is called and truncates an existing file. Use a new file in the private directory so an older trace cannot confuse the result.
$ trace="$work/trace.log"
$ rm -f "$trace"
$ MALLOC_TRACE="$trace" ./demo
$ test -s "$trace" && echo "trace created"
trace created
There is no need for sudo. If the pathname is invalid or not writable, the C library installs no tracing hooks and the program can still exit successfully. That is why checking the trace file is essential.
Do not point MALLOC_TRACE at a valuable existing file. The tracing function truncates the named file. The test above only removes a file inside /tmp/mtrace-demo, but the removal is still irreversible for that file.
Checkpoint
The trace pathname exists and is non-empty. If it does not, fix the pathname or permissions before interpreting anything.
4. Interpret the trace with the matching binary
Pass the executable first and the trace file second. Supplying the binary is what allows mtrace to add source file and line information when the executable contains suitable debug data.
$ mtrace ./demo "$trace"
Memory not freed:
-----------------
Address Size Caller
0x... 0x80 at .../demo.c:10
Addresses and the exact table spacing vary. The useful result is the Memory not freed section and a caller pointing at the allocation. A clean test produces a message such as No memory leaks. The interpreter can also report attempts to free memory that was never allocated. Read those diagnostics as events recorded by the trace, not as a complete proof of memory safety.
For this deliberately leaky program, line 10 should be the malloc(128) call after accounting for the exact file layout. If the report has no source line, check that you passed the correct executable and compiled it with -g. A trace made by one binary should not be interpreted with a different rebuilt binary.
5. Apply the workflow to a real program
Put mtrace(); early in the program's normal startup path, compile a diagnostic build with debug information, and run the smallest input that reproduces the suspected leak:
$ cc -g -O0 src/app.c -o build/app
$ trace=/tmp/app-mtrace.log
$ rm -f "$trace"
$ MALLOC_TRACE="$trace" build/app --input /path/to/reproducible-input
$ test -s "$trace" && mtrace build/app "$trace"
Use an absolute trace pathname when a launcher changes the working directory. Keep the trace private if the program handles sensitive input, because it records allocation activity and can contain file or source-location details. Remove it after review:
$ rm -f /tmp/app-mtrace.log
That deletion is irreversible. Preserve the file instead when another engineer needs to reproduce or review the finding.
6. Diagnose misleading results
- No trace file: check
MALLOC_TRACE, directory permissions, and whether the program actually callsmtrace(). A successful program exit is not enough. - No source locations: use the exact executable that generated the trace and rebuild with
-g. The manpage warns that reported line numbers are not always precise and can refer to a nearby non-blank line. - No leaks reported: check that the input exercised the suspected path and that the trace is non-empty. The tool only reports activity recorded after tracing was enabled.
- Different behaviour under tracing: tracing adds a performance cost. Compare with an ordinary run only after the diagnostic run is complete, and do not leave
MALLOC_TRACEenabled in normal service operation. - Set-user-ID or set-group-ID program: the C library ignores
MALLOC_TRACEfor such programs. Do not weaken file ownership or permission checks to force tracing; reproduce the issue in a non-privileged diagnostic build instead.
Done means
mtrace --versionruns, and you know which GNU C Library tool you are using.- The test binary was compiled with debug information and the trace was made by that same binary.
MALLOC_TRACEpointed to a fresh, writable file, which you verified was non-empty.- You interpreted the trace with
mtrace binary tracefileand checked the reported allocation path. - Temporary traces and test binaries are either retained deliberately for review or removed from the private work directory.