MemorySanitizer¶
Introduction¶
MemorySanitizer is a detector of uninitialized memory use. It consists of acompiler instrumentation module and a run-time library.
Typical slowdown introduced by MemorySanitizer is3x.
Here is a not comprehensive of list cases when MemorySanitizer will report an error:
Uninitialized value was used in a conditional branch.
Uninitialized pointer was used for memory accesses.
Uninitialized value was passed or returned from a function call, which is considered an undefined behavior. The check can be disabled with
-fno-sanitize-memory-param-retval.Uninitialized data was passed into some libc calls.
How to build¶
Build LLVM/Clang withCMake.
Usage¶
Simply compile and link your program with-fsanitize=memory flag.The MemorySanitizer run-time library should be linked to the finalexecutable, so make sure to useclang (notld) for the finallink step. When linking shared libraries, the MemorySanitizer run-timeis not linked, so-Wl,-z,defs may cause link errors (don’t use itwith MemorySanitizer). To get a reasonable performance add-O1 orhigher. To get meaningful stack traces in error messages add-fno-omit-frame-pointer. To get perfect stack traces you may needto disable inlining (just use-O1) and tail call elimination(-fno-optimize-sibling-calls).
%catumr.cc#include<stdio.h>int main(int argc, char** argv) { int* a = new int[10]; a[5] = 0; if (a[argc]) printf("xx\n"); return 0;}%clang-fsanitize=memory-fno-omit-frame-pointer-g-O2umr.cc
If a bug is detected, the program will print an error message tostderr and exit with a non-zero exit code.
%./a.outWARNING: MemorySanitizer: use-of-uninitialized-value #00x7f45944b418ainmainumr.cc:6 #10x7f45938b676cin__libc_start_mainlibc-start.c:226
By default, MemorySanitizer exits on the first detected error. If youfind the error report hard to understand, try enablingorigin tracking.
__has_feature(memory_sanitizer)¶
In some cases one may need to execute different code depending onwhether MemorySanitizer is enabled.__has_feature can be used for this purpose.
#if defined(__has_feature)# if __has_feature(memory_sanitizer)// code that builds only under MemorySanitizer# endif#endif
__attribute__((no_sanitize("memory")))¶
Some code should not be checked by MemorySanitizer. One may use the functionattributeno_sanitize("memory") to disable uninitialized checks in aparticular function. MemorySanitizer may still instrument such functions toavoid false positives. This attribute may not be supported by other compilers,so we suggest to use it together with__has_feature(memory_sanitizer).
__attribute__((disable_sanitizer_instrumentation))¶
Thedisable_sanitizer_instrumentation attribute can be applied to functionsto prevent all kinds of instrumentation. As a result, it may introduce falsepositives and therefore should be used with care, and only if absolutelyrequired; for example for certain code that cannot tolerate any instrumentationand resulting side-effects. This attribute overridesno_sanitize("memory").
Ignorelist¶
MemorySanitizer supportssrc andfun entity types inSanitizer special case list, that can be used to relax MemorySanitizerchecks for certain source files and functions. All “Use of uninitialized value”warnings will be suppressed and all values loaded from memory will beconsidered fully initialized.
Report symbolization¶
MemorySanitizer uses an external symbolizer to print files and line numbers inreports. Make sure thatllvm-symbolizer binary is inPATH,or set environment variableMSAN_SYMBOLIZER_PATH to point to it.
Origin Tracking¶
MemorySanitizer can track origins of uninitialized values, similar toValgrind’s –track-origins option. This feature is enabled by-fsanitize-memory-track-origins=2 (or simply-fsanitize-memory-track-origins) Clang option. With the code fromthe example above,
%catumr2.cc#include<stdio.h>int main(int argc, char** argv) { int* a = new int[10]; a[5] = 0; volatile int b = a[argc]; if (b) printf("xx\n"); return 0;}%clang-fsanitize=memory-fsanitize-memory-track-origins=2-fno-omit-frame-pointer-g-O2umr2.cc%./a.outWARNING: MemorySanitizer: use-of-uninitialized-value #00x7f7893912f0binmainumr2.cc:7 #10x7f789249b76cin__libc_start_mainlibc-start.c:226 Uninitialized value was stored to memory at #00x7f78938b5c25in__msan_chain_originmsan.cc:484 #10x7f7893912ecdinmainumr2.cc:6 Uninitialized value was created by a heap allocation #00x7f7893901cbdinoperatornew[](unsignedlong)msan_new_delete.cc:44 #10x7f7893912e06inmainumr2.cc:4
By default, MemorySanitizer collects both allocation points and allintermediate stores the uninitialized value went through. Origintracking has proved to be very useful for debugging MemorySanitizerreports. It slows down program execution by a factor of 1.5x-2x on topof the usual MemorySanitizer slowdown and increases memory overhead.
Clang option-fsanitize-memory-track-origins=1 enables a slightlyfaster mode when MemorySanitizer collects only allocation points butnot intermediate stores.
Use-after-destruction detection¶
MemorySanitizer includes use-after-destruction detection. After invocation ofthe destructor, the object will be considered no longer readable, and usingunderlying memory will lead to error reports in runtime. Refer to the standardforlifetime definition.
This feature can be disabled with either:
Pass additional Clang option
-fno-sanitize-memory-use-after-dtorduringcompilation.Set environment variableMSAN_OPTIONS=poison_in_dtor=0 before runningthe program.
Handling external code¶
MemorySanitizer requires that all program code is instrumented. Thisalso includes any libraries that the program depends on, even libc.Failing to achieve this may result in false reports.For the same reason you may need to replace all inline assembly code that writes to memorywith a pure C/C++ code.
Full MemorySanitizer instrumentation is very difficult to achieve. Tomake it easier, MemorySanitizer runtime library includes 70+interceptors for the most common libc functions. They make it possibleto run MemorySanitizer-instrumented programs linked withuninstrumented libc. For example, the authors were able to bootstrapMemorySanitizer-instrumented Clang compiler by linking it withself-built instrumented libc++ (as a replacement for libstdc++).
Security Considerations¶
MemorySanitizer is a bug detection tool and its runtime is not meant to belinked against production executables. While it may be useful for testing,MemorySanitizer’s runtime was not developed with security-sensitiveconstraints in mind and may compromise the security of the resulting executable.
Supported Platforms¶
MemorySanitizer is supported on the following OS:
Linux
NetBSD
FreeBSD
Limitations¶
MemorySanitizer uses 2x more real memory than a native run, 3x withorigin tracking.
MemorySanitizer maps (but not reserves) 64 Terabytes of virtualaddress space. This means that tools like
ulimitmay not work asusually expected.Static linking is not supported.
Older versions of MSan (LLVM 3.7 and older) didn’t work withnon-position-independent executables, and could fail on some Linuxkernel versions with disabled ASLR. Refer to documentation for older versionsfor more details.
MemorySanitizer might be incompatible with position-independent executablesfrom FreeBSD 13 but there is a check done at runtime and throws a warningin this case.
Current Status¶
MemorySanitizer is known to work on large real-world programs(like Clang/LLVM itself) that can be recompiled from source, including alldependent libraries.