LeakSanitizer#
Introduction#
LeakSanitizer is a run-time memory leak detector. It can be combined with AddressSanitizer to get both memory error and leak detection, or used in a stand-alone mode. LSan adds almost no performance overhead until the very end of the process, at which point there is an extra leak detection phase.
Usage#
AddressSanitizer: integrates LeakSanitizer and enables it by default on supported platforms.
$ cat memory-leak.c
#include <stdlib.h>
void *p;
int main() {
p = malloc(7);
p = 0; // The memory is leaked here.
return 0;
}
% clang -fsanitize=address -g memory-leak.c ; ASAN_OPTIONS=detect_leaks=1 ./a.out
==23646==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 7 byte(s) in 1 object(s) allocated from:
#0 0x4af01b in __interceptor_malloc /projects/compiler-rt/lib/asan/asan_malloc_linux.cc:52:3
#1 0x4da26a in main memory-leak.c:4:7
#2 0x7f076fd9cec4 in __libc_start_main libc-start.c:287
SUMMARY: AddressSanitizer: 7 byte(s) leaked in 1 allocation(s).
To use LeakSanitizer in stand-alone mode, link your program with
-fsanitize=leak flag. Make sure to use clang (not ld) for the
link step, so that it would link in proper LeakSanitizer run-time library
into the final executable.
Suppressions#
LeakSanitizer reports can be suppressed if you encounter leaks in third-party libraries or known locations that cannot be fixed immediately.
Suppression Format#
Each suppression rule is specified on its own line in the form:
leak:<pattern>
A memory leak is suppressed if <pattern> matches any function name, source
file name, or library/module name in the symbolized stack trace of the leak
report. Wildcards (*) are supported, and lines starting with # are treated
as comments.
Example suppression rules:
# Suppress leak by function name (supports wildcards)
leak:MyKnownLeakyFunction
leak:*LeakyNamespace::*
# Suppress leak by source file name
leak:third_party/leaky_library.cpp
# Suppress leak by shared library / module name
leak:libcrypto.so
Runtime Suppressions#
To specify a suppressions file at runtime, pass its path via the suppressions
flag in the LSAN_OPTIONS environment variable:
$ LSAN_OPTIONS="suppressions=MyLSan.supp" ./a.out
(When running LeakSanitizer as part of AddressSanitizer, LSAN_OPTIONS is still
used to pass LeakSanitizer-specific flags and suppressions.)
Compile-time Default Suppressions#
You can embed default suppressions directly into your executable at compile/link
time by defining the __lsan_default_suppressions function in your source code:
#include <sanitizer/lsan_interface.h>
extern "C" const char *__lsan_default_suppressions() {
return "leak:MyKnownLeakyFunction\n"
"leak:third_party/leaky_library.cpp\n"
"leak:libcrypto.so\n";
}
Both default suppressions and suppressions passed in the file via
LSAN_OPTIONS="suppressions=..." will be parsed and applied.
Programmatic Disabling#
LeakSanitizer provides fine-grained programmatic control over leak detection
via <sanitizer/lsan_interface.h>:
Disable around specific code blocks: Allocations made between calls to
__lsan_disable()and__lsan_enable()will not be reported as leaks. This disabling is thread-local and only affects allocations made by the calling thread. In C++, you can use the RAII wrapper__lsan::ScopedDisabler:#include <sanitizer/lsan_interface.h> void foo() { __lsan::ScopedDisabler disabler; // Allocations made here will not be reported as leaks. leaky_third_party_init(); }
Ignore specific objects:
__lsan_ignore_object(const void *p)marks the heap object pointed to byp(and anything reachable from it) as a non-leak.Register custom root regions:
__lsan_register_root_region(const void *p, size_t size)and__lsan_unregister_root_region(const void *p, size_t size)register memory areas (such as custom memory pools or mapped regions) to be scanned for live pointers during leak checking.Explicit leak checking:
__lsan_do_leak_check()triggers an immediate leak check. If leaks are detected and theexitcodeflag is non-zero (default), the process terminates; otherwise, it returns normally. Calling this function disables subsequent automatic leak checks at process exit.__lsan_do_recoverable_leak_check()performs a leak check and returns0if no leaks were detected (or if leak detection is disabled), and1if leaks were found. It prints a report without terminating the process or disabling the end-of-process check.Disable leak checking entirely: Define
__lsan_is_turned_off()to return1to disable leak checking for the program.
Flags and Options#
Runtime flags can be passed to LeakSanitizer via the LSAN_OPTIONS environment
variable:
$ LSAN_OPTIONS="print_suppressions=0:report_objects=1" ./a.out
To see the full list of available flags, run an instrumented binary with
LSAN_OPTIONS="help=1".
Flags passed via the LSAN_OPTIONS environment variable take precedence over
compile-time default options.
Compile-time Default Options#
Default options can also be specified at compile/link time by defining
__lsan_default_options:
#include <sanitizer/lsan_interface.h>
extern "C" const char *__lsan_default_options() {
return "print_suppressions=0:report_objects=1";
}
Security Considerations#
LeakSanitizer is a bug detection tool and its runtime is not meant to be linked against production executables. While it may be useful for testing, LeakSanitizer’s runtime was not developed with security-sensitive constraints in mind and may compromise the security of the resulting executable.
Supported Platforms#
Android
Fuchsia
Linux
macOS
NetBSD
More Information#
https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer