Skip to content

mhahnFr/LeakSanitizer

Repository files navigation

LeakSanitizer

Tool to track down memory leaks.

It can be used in conjunction with code written in almost any programming language that compiles down to native machine code.
Officially supported languages are currently:

  • C
  • C++
  • Objective-C
  • Swift

This tool is available for both Linux and macOS.

Usage

Installation

Get started by downloading a release.
Simply move the headers and the library anywhere you like.

Alternatively, you can build the LeakSanitizer from source:

git clone --recurse-submodules https://github.com/mhahnFr/LeakSanitizer.git && cd LeakSanitizer && make

It is automatically installed in the directory where the LeakSanitizer was cloned in. To install it in a specific directory, use the following command:

make INSTALL_PATH=/usr/local install

Adapt the value of the INSTALL_PATH argument to your needs.

Tip

To create a portable build (just like a downloaded release), use the following command:

make release

Build dependencies

The LeakSanitizer adheres to the standard of C++17.

Additionally, the following command line tools are necessary to successfully build the LeakSanitizer:

  • GNU compatible make command line tool
  • The uname command line tool (POSIX.2)
  • The cat command line tool (POSIX.2)

All dependencies introduced by the CallstackLibrary are needed as well.

Uninstallation

To uninstall the LeakSanitizer, simply remove its headers and its library from the installation directory.
This can be done by the following command:

make INSTALL_PATH=/usr/local uninstall

Adapt the value of the INSTALL_PATH argument to your needs.

Usage, take II

Use this tool by preloading its runtime library or by linking against it (recommended).

Linking (recommended)

Add the runtime library of the LeakSanitizer to your linking arguments.

Tip

Example for standard C/C++ compilers:

-L<path/to/LeakSanitizer> -llsan

Preloading

Add the runtime library to the preload environment variable of your dynamic linker:

  • Linux:
LD_PRELOAD=<path/to/LeakSanitizer>/liblsan.so
  • macOS:
DYLD_INSERT_LIBRARIES=<path/to/LeakSanitizer>/liblsan.dylib

Leak detection

Once this sanitizer is bundled with your application the detected memory leaks are printed upon termination.

Example:

// test.c

#include <string.h>
#include <stdlib.h>

char* global;

void foo2(void) {
    global = strdup("Global variable");
}

void bar2(void) {
    void* a = malloc(1023);
    a = strdup("Hello World!");
    a = NULL;
    a = malloc(1000);
    free(a);
    
    foo2();
}

void foo(void) { bar2(); }
void bar(void) { foo();  }

int main(void) {
    bar();
}

Compiled and linked on macOS with the command

cc -g test.c -L<path/to/LeakSanitizer> -llsan

this example creates the following output:

Compiled and linked on Fedora with the command

gcc -g test.c -L<path/to/LeakSanitizer> -llsan

the example above creates the following output:

Tip

Indirect memory leaks can be displayed by setting LSAN_INDIRECT_LEAKS to true:

LSAN_INDIRECT_LEAKS=true

Reachable memory leaks (those to which a pointer was found) can be hidden by setting LSAN_REACHABLE_LEAKS to false:

LSAN_REACHABLE_LEAKS=false

Source file line numbers

To add source file line information to the output (as shown above), simply compile your target with debug symbols.

Tip

Usually, the appropriate compilation option is -g.

Currently, debug symbols in the following formats are supported:

  • DWARF in ELF binary files
  • DWARF in Mach-O debug maps (using Mach-O object files)
  • .dSYM Mach-O bundles

The DWARF parser supports DWARF in version 2, 3, 4 and 5.

Behaviour

Since version 1.6 the behaviour of this sanitizer can be adjusted by setting certain environment variables.
The following variables are currently supported:

Name Description Since Type Default value
LSAN_HUMAN_PRINT Print human-readably formatted v1.6 Boolean true
LSAN_PRINT_COUT Print to the default output stream v1.6 Boolean false
LSAN_PRINT_FORMATTED Print using ANSI escape codes v1.6 Boolean true
LSAN_INVALID_CRASH Terminate if an invalid action is detected v1.6 Boolean true
LSAN_INVALID_FREE Detect invalid deallocations v1.6 Boolean true
LSAN_FREE_NULL Issue a warning if NULL is freed v1.6 Boolean false
LSAN_STATS_ACTIVE Enable the statistical bookkeeping v1.6 Boolean false
LSAN_CALLSTACK_SIZE The amount of frames to be printed in a callstack v1.6 Number 20
LSAN_PRINT_EXIT_POINT Print the callstack of the exit point v1.7 Boolean false
LSAN_PRINT_BINARIES Print the binary file names v1.8 Boolean true
LSAN_PRINT_FUNCTIONS Always print the function names v1.8 Boolean true
LSAN_RELATIVE_PATHS Allow relative paths to be printed v1.8 Boolean true
LSAN_ZERO_ALLOCATION Issue a warning when 0 byte are allocated v1.8 Boolean false
LSAN_AUTO_STATS Time interval between the automatically statistics printing v1.11 Time interval None
LSAN_SUPPRESSION_DEVELOPER Activates more suppression developer output v1.11 Boolean false
LSAN_INDIRECT_LEAKS Whether to print indirectly leaked allocations v1.11 Boolean false
LSAN_REACHABLE_LEAKS Whether to print leaks to whose a pointer was found v1.11 Boolean true
LSAN_SUPPRESSION_FILES List of additional suppression files to be considered v1.11 File list None
LSAN_SYSTEM_LIBRARY_FILES List of additional system library files to be considered v1.11 File list None

Tip

LSAN_AUTO_STATS should be assigned a number with a time unit directly after the number.
The following time units are available:

  • ns: nanoseconds
  • us: microseconds
  • ms: milliseconds
  • s: seconds
  • m: minutes
  • h: hours

The default unit when none is given is seconds.

More on the environment variables here.

Leak suppression system

Use the memory leak suppression system introduced in version 1.11 to "remove" internal memory leaks created by the runtime libraries you additionally use.

Add your additional suppression files to the environment variable LSAN_SUPPRESSION_FILES.

Tip

Example:

LSAN_SUPPRESSION_FILES='someLibrarySuppressions.json:otherIgnoredLeaks.json'

Follow the full documentation of the suppression system in order to write your own suppression files.

Signals

This sanitizer comes with handlers for the following signals:

Signal Action
SIGUSR1 Prints the statistics if enabled using LSAN_STATS_ACTIVE or LSAN_AUTO_STATS.
SIGUSR2 Prints the current callstack.
Any deadly signal is caught and the stacktrace of the cash is printed.

More about the signal handlers here.

Statistics

The statistics of the tracked memory can be queried at runtime. To do so activate the statistical bookkeeping by either setting the environment variable LSAN_STATS_ACTIVE to true or by using LSAN_AUTO_STATS.
The statistics then can be queried using the following API:

Function Description
__lsan_getTotalMallocs() Returns the total count of allocations registered.
__lsan_getTotalBytes() Returns the total count of allocated bytes.
__lsan_getTotalFrees() Returns the total count of registered allocations that have been deallocated.
__lsan_getCurrentMallocCount() Returns the count of currently active allocations.
__lsan_getCurrentByteCount() Returns the amount of currently allocated bytes.
__lsan_getMallocPeek() Returns the highest amount of allocations at the same time.
__lsan_getBytePeek() Returns the highest amount of bytes allocated at the same time.
__lsan_printStats() Prints the statistics to the output stream specified by LSAN_PRINT_COUT.
__lsan_printFStats() Prints the fragmentation statistics to the output stream specified by LSAN_PRINT_COUT.

More on the statistics here.

Behind the scenes or: How does it work?

In order to track the memory allocations this sanitizer replaces the common allocation management functions such as malloc, calloc, realloc and free. Every allocation and deallocation is registered and a stacktrace is created for it.
The allocations created by the LeakSanitizer are ignored.

The signal handlers and the wrapper functions are installed once the sanitizer has been loaded by the dynamic linker.

When the exit handler registered using atexit is invoked the allocated memory is examined and the detected memory leaks are printed.
The stacktraces are managed using the CallstackLibrary.

Final notes

If you experience any problems with the LeakSanitizer or if you have ideas to further improve it do not hesitate to open an issue or to open a pull request.

This project is licensed under the terms of the GNU GPL in version 3 or later.

© Copyright 2022 - 2025 mhahnFr and contributors