1 | ================ |
2 | MemorySanitizer |
3 | ================ |
4 | |
5 | .. contents:: |
6 | :local: |
7 | |
8 | Introduction |
9 | ============ |
10 | |
11 | MemorySanitizer is a detector of uninitialized reads. It consists of a |
12 | compiler instrumentation module and a run-time library. |
13 | |
14 | Typical slowdown introduced by MemorySanitizer is **3x**. |
15 | |
16 | How to build |
17 | ============ |
18 | |
19 | Build LLVM/Clang with `CMake <https://llvm.org/docs/CMake.html>`_. |
20 | |
21 | Usage |
22 | ===== |
23 | |
24 | Simply compile and link your program with ``-fsanitize=memory`` flag. |
25 | The MemorySanitizer run-time library should be linked to the final |
26 | executable, so make sure to use ``clang`` (not ``ld``) for the final |
27 | link step. When linking shared libraries, the MemorySanitizer run-time |
28 | is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it |
29 | with MemorySanitizer). To get a reasonable performance add ``-O1`` or |
30 | higher. To get meaningful stack traces in error messages add |
31 | ``-fno-omit-frame-pointer``. To get perfect stack traces you may need |
32 | to disable inlining (just use ``-O1``) and tail call elimination |
33 | (``-fno-optimize-sibling-calls``). |
34 | |
35 | .. code-block:: console |
36 | |
37 | % cat umr.cc |
38 | #include <stdio.h> |
39 | |
40 | int main(int argc, char** argv) { |
41 | int* a = new int[10]; |
42 | a[5] = 0; |
43 | if (a[argc]) |
44 | printf("xx\n"); |
45 | return 0; |
46 | } |
47 | |
48 | % clang -fsanitize=memory -fno-omit-frame-pointer -g -O2 umr.cc |
49 | |
50 | If a bug is detected, the program will print an error message to |
51 | stderr and exit with a non-zero exit code. |
52 | |
53 | .. code-block:: console |
54 | |
55 | % ./a.out |
56 | WARNING: MemorySanitizer: use-of-uninitialized-value |
57 | #0 0x7f45944b418a in main umr.cc:6 |
58 | #1 0x7f45938b676c in __libc_start_main libc-start.c:226 |
59 | |
60 | By default, MemorySanitizer exits on the first detected error. If you |
61 | find the error report hard to understand, try enabling |
62 | :ref:`origin tracking <msan-origins>`. |
63 | |
64 | ``__has_feature(memory_sanitizer)`` |
65 | ------------------------------------ |
66 | |
67 | In some cases one may need to execute different code depending on |
68 | whether MemorySanitizer is enabled. :ref:`\_\_has\_feature |
69 | <langext-__has_feature-__has_extension>` can be used for this purpose. |
70 | |
71 | .. code-block:: c |
72 | |
73 | #if defined(__has_feature) |
74 | # if __has_feature(memory_sanitizer) |
75 | // code that builds only under MemorySanitizer |
76 | # endif |
77 | #endif |
78 | |
79 | ``__attribute__((no_sanitize("memory")))`` |
80 | ----------------------------------------------- |
81 | |
82 | Some code should not be checked by MemorySanitizer. One may use the function |
83 | attribute ``no_sanitize("memory")`` to disable uninitialized checks in a |
84 | particular function. MemorySanitizer may still instrument such functions to |
85 | avoid false positives. This attribute may not be supported by other compilers, |
86 | so we suggest to use it together with ``__has_feature(memory_sanitizer)``. |
87 | |
88 | Blacklist |
89 | --------- |
90 | |
91 | MemorySanitizer supports ``src`` and ``fun`` entity types in |
92 | :doc:`SanitizerSpecialCaseList`, that can be used to relax MemorySanitizer |
93 | checks for certain source files and functions. All "Use of uninitialized value" |
94 | warnings will be suppressed and all values loaded from memory will be |
95 | considered fully initialized. |
96 | |
97 | Report symbolization |
98 | ==================== |
99 | |
100 | MemorySanitizer uses an external symbolizer to print files and line numbers in |
101 | reports. Make sure that ``llvm-symbolizer`` binary is in ``PATH``, |
102 | or set environment variable ``MSAN_SYMBOLIZER_PATH`` to point to it. |
103 | |
104 | .. _msan-origins: |
105 | |
106 | Origin Tracking |
107 | =============== |
108 | |
109 | MemorySanitizer can track origins of uninitialized values, similar to |
110 | Valgrind's --track-origins option. This feature is enabled by |
111 | ``-fsanitize-memory-track-origins=2`` (or simply |
112 | ``-fsanitize-memory-track-origins``) Clang option. With the code from |
113 | the example above, |
114 | |
115 | .. code-block:: console |
116 | |
117 | % cat umr2.cc |
118 | #include <stdio.h> |
119 | |
120 | int main(int argc, char** argv) { |
121 | int* a = new int[10]; |
122 | a[5] = 0; |
123 | volatile int b = a[argc]; |
124 | if (b) |
125 | printf("xx\n"); |
126 | return 0; |
127 | } |
128 | |
129 | % clang -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O2 umr2.cc |
130 | % ./a.out |
131 | WARNING: MemorySanitizer: use-of-uninitialized-value |
132 | #0 0x7f7893912f0b in main umr2.cc:7 |
133 | #1 0x7f789249b76c in __libc_start_main libc-start.c:226 |
134 | |
135 | Uninitialized value was stored to memory at |
136 | #0 0x7f78938b5c25 in __msan_chain_origin msan.cc:484 |
137 | #1 0x7f7893912ecd in main umr2.cc:6 |
138 | |
139 | Uninitialized value was created by a heap allocation |
140 | #0 0x7f7893901cbd in operator new[](unsigned long) msan_new_delete.cc:44 |
141 | #1 0x7f7893912e06 in main umr2.cc:4 |
142 | |
143 | By default, MemorySanitizer collects both allocation points and all |
144 | intermediate stores the uninitialized value went through. Origin |
145 | tracking has proved to be very useful for debugging MemorySanitizer |
146 | reports. It slows down program execution by a factor of 1.5x-2x on top |
147 | of the usual MemorySanitizer slowdown and increases memory overhead. |
148 | |
149 | Clang option ``-fsanitize-memory-track-origins=1`` enables a slightly |
150 | faster mode when MemorySanitizer collects only allocation points but |
151 | not intermediate stores. |
152 | |
153 | Use-after-destruction detection |
154 | =============================== |
155 | |
156 | You can enable experimental use-after-destruction detection in MemorySanitizer. |
157 | After invocation of the destructor, the object will be considered no longer |
158 | readable, and using underlying memory will lead to error reports in runtime. |
159 | |
160 | This feature is still experimental, in order to enable it at runtime you need |
161 | to: |
162 | |
163 | #. Pass addition Clang option ``-fsanitize-memory-use-after-dtor`` during |
164 | compilation. |
165 | #. Set environment variable `MSAN_OPTIONS=poison_in_dtor=1` before running |
166 | the program. |
167 | |
168 | Handling external code |
169 | ====================== |
170 | |
171 | MemorySanitizer requires that all program code is instrumented. This |
172 | also includes any libraries that the program depends on, even libc. |
173 | Failing to achieve this may result in false reports. |
174 | For the same reason you may need to replace all inline assembly code that writes to memory |
175 | with a pure C/C++ code. |
176 | |
177 | Full MemorySanitizer instrumentation is very difficult to achieve. To |
178 | make it easier, MemorySanitizer runtime library includes 70+ |
179 | interceptors for the most common libc functions. They make it possible |
180 | to run MemorySanitizer-instrumented programs linked with |
181 | uninstrumented libc. For example, the authors were able to bootstrap |
182 | MemorySanitizer-instrumented Clang compiler by linking it with |
183 | self-built instrumented libc++ (as a replacement for libstdc++). |
184 | |
185 | Supported Platforms |
186 | =================== |
187 | |
188 | MemorySanitizer is supported on the following OS: |
189 | |
190 | * Linux |
191 | * NetBSD |
192 | * FreeBSD |
193 | |
194 | Limitations |
195 | =========== |
196 | |
197 | * MemorySanitizer uses 2x more real memory than a native run, 3x with |
198 | origin tracking. |
199 | * MemorySanitizer maps (but not reserves) 64 Terabytes of virtual |
200 | address space. This means that tools like ``ulimit`` may not work as |
201 | usually expected. |
202 | * Static linking is not supported. |
203 | * Older versions of MSan (LLVM 3.7 and older) didn't work with |
204 | non-position-independent executables, and could fail on some Linux |
205 | kernel versions with disabled ASLR. Refer to documentation for older versions |
206 | for more details. |
207 | |
208 | Current Status |
209 | ============== |
210 | |
211 | MemorySanitizer is known to work on large real-world programs |
212 | (like Clang/LLVM itself) that can be recompiled from source, including all |
213 | dependent libraries. |
214 | |
215 | More Information |
216 | ================ |
217 | |
218 | `<https://github.com/google/sanitizers/wiki/MemorySanitizer>`_ |
219 | |