]> git.proxmox.com Git - rustc.git/blob - src/doc/unstable-book/src/compiler-flags/sanitizer.md
New upstream version 1.44.1+dfsg1
[rustc.git] / src / doc / unstable-book / src / compiler-flags / sanitizer.md
1 # `sanitizer`
2
3 The tracking issue for this feature is: [#39699](https://github.com/rust-lang/rust/issues/39699).
4
5 ------------------------
6
7 This feature allows for use of one of following sanitizers:
8
9 * [AddressSanitizer][clang-asan] a fast memory error detector.
10 * [LeakSanitizer][clang-lsan] a run-time memory leak detector.
11 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
12 * [ThreadSanitizer][clang-tsan] a fast data race detector.
13
14 To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
15 `-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be
16 enabled at a time.
17
18 # AddressSanitizer
19
20 AddressSanitizer is a memory error detector. It can detect the following types
21 of bugs:
22
23 * Out of bound accesses to heap, stack and globals
24 * Use after free
25 * Use after return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
26 * Use after scope
27 * Double-free, invalid free
28 * Memory leaks
29
30 AddressSanitizer is supported on the following targets:
31
32 * `x86_64-apple-darwin`
33 * `x86_64-unknown-linux-gnu`
34
35 AddressSanitizer works with non-instrumented code although it will impede its
36 ability to detect some bugs. It is not expected to produce false positive
37 reports.
38
39 ## Examples
40
41 Stack buffer overflow:
42
43 ```rust
44 fn main() {
45 let xs = [0, 1, 2, 3];
46 let _y = unsafe { *xs.as_ptr().offset(4) };
47 }
48 ```
49
50 ```shell
51 $ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
52 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
53 ==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250 at pc 0x5609a841fb20 bp 0x7ffe400e6210 sp 0x7ffe400e6208
54 READ of size 4 at 0x7ffe400e6250 thread T0
55 #0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
56 ...
57
58 Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
59 #0 0x5609a841f8af in example::main::h628ffc6626ed85b2 /.../src/main.rs:1
60
61 This frame has 1 object(s):
62 [32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable
63 HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
64 (longjmp and C++ exceptions *are* supported)
65 SUMMARY: AddressSanitizer: stack-buffer-overflow /.../src/main.rs:3:23 in example::main::h628ffc6626ed85b2
66 Shadow bytes around the buggy address:
67 0x100048014bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
68 0x100048014c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69 0x100048014c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70 0x100048014c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
71 0x100048014c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
72 =>0x100048014c40: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
73 0x100048014c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
74 0x100048014c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
75 0x100048014c70: f1 f1 f1 f1 00 00 f3 f3 00 00 00 00 00 00 00 00
76 0x100048014c80: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
77 0x100048014c90: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
78 Shadow byte legend (one shadow byte represents 8 application bytes):
79 Addressable: 00
80 Partially addressable: 01 02 03 04 05 06 07
81 Heap left redzone: fa
82 Freed heap region: fd
83 Stack left redzone: f1
84 Stack mid redzone: f2
85 Stack right redzone: f3
86 Stack after return: f5
87 Stack use after scope: f8
88 Global redzone: f9
89 Global init order: f6
90 Poisoned by user: f7
91 Container overflow: fc
92 Array cookie: ac
93 Intra object redzone: bb
94 ASan internal: fe
95 Left alloca redzone: ca
96 Right alloca redzone: cb
97 Shadow gap: cc
98 ==37882==ABORTING
99 ```
100
101 Use of a stack object after its scope has already ended:
102
103 ```rust
104 static mut P: *mut usize = std::ptr::null_mut();
105
106 fn main() {
107 unsafe {
108 {
109 let mut x = 0;
110 P = &mut x;
111 }
112 std::ptr::write_volatile(P, 123);
113 }
114 }
115 ```
116
117 ```shell
118 $ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
119 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
120 =================================================================
121 ==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0 at pc 0x55c98b262a8e bp 0x7ffc7ed3e050 sp 0x7ffc7ed3e048
122 WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0
123 #0 0x55c98b262a8d in core::ptr::write_volatile::he21f1df5a82f329a /.../src/rust/src/libcore/ptr/mod.rs:1048:5
124 #1 0x55c98b262cd2 in example::main::h628ffc6626ed85b2 /.../src/main.rs:9:9
125 ...
126
127 Address 0x7ffc7ed3e1a0 is located in stack of thread T0 at offset 32 in frame
128 #0 0x55c98b262bdf in example::main::h628ffc6626ed85b2 /.../src/main.rs:3
129
130 This frame has 1 object(s):
131 [32, 40) 'x' (line 6) <== Memory access at offset 32 is inside this variable
132 HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
133 (longjmp and C++ exceptions *are* supported)
134 SUMMARY: AddressSanitizer: stack-use-after-scope /.../src/rust/src/libcore/ptr/mod.rs:1048:5 in core::ptr::write_volatile::he21f1df5a82f329a
135 Shadow bytes around the buggy address:
136 0x10000fd9fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
137 0x10000fd9fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
138 0x10000fd9fc00: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
139 0x10000fd9fc10: f8 f8 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
140 0x10000fd9fc20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
141 =>0x10000fd9fc30: f1 f1 f1 f1[f8]f3 f3 f3 00 00 00 00 00 00 00 00
142 0x10000fd9fc40: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
143 0x10000fd9fc50: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
144 0x10000fd9fc60: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3
145 0x10000fd9fc70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
146 0x10000fd9fc80: 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3 00 00 00 00
147 Shadow byte legend (one shadow byte represents 8 application bytes):
148 Addressable: 00
149 Partially addressable: 01 02 03 04 05 06 07
150 Heap left redzone: fa
151 Freed heap region: fd
152 Stack left redzone: f1
153 Stack mid redzone: f2
154 Stack right redzone: f3
155 Stack after return: f5
156 Stack use after scope: f8
157 Global redzone: f9
158 Global init order: f6
159 Poisoned by user: f7
160 Container overflow: fc
161 Array cookie: ac
162 Intra object redzone: bb
163 ASan internal: fe
164 Left alloca redzone: ca
165 Right alloca redzone: cb
166 Shadow gap: cc
167 ==39249==ABORTING
168 ```
169
170 # MemorySanitizer
171
172 MemorySanitizer is detector of uninitialized reads. It is only supported on the
173 `x86_64-unknown-linux-gnu` target.
174
175 MemorySanitizer requires all program code to be instrumented. C/C++ dependencies
176 need to be recompiled using Clang with `-fsanitize=memory` option. Failing to
177 achieve that will result in false positive reports.
178
179 ## Example
180
181 Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
182 instruments the standard library, and is strictly necessary for the correct
183 operation of the tool. The `-Zsanitizer-track-origins` enables tracking of the
184 origins of uninitialized memory:
185
186 ```rust
187 use std::mem::MaybeUninit;
188
189 fn main() {
190 unsafe {
191 let a = MaybeUninit::<[usize; 4]>::uninit();
192 let a = a.assume_init();
193 println!("{}", a[2]);
194 }
195 }
196 ```
197
198 ```shell
199 $ export \
200 CC=clang \
201 CXX=clang++ \
202 CFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \
203 CXXFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \
204 RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
205 RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
206 $ cargo clean
207 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
208 ==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
209 #0 0x560c04f7488a in core::fmt::num::imp::fmt_u64::haa293b0b098501ca $RUST/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/src/libcore/fmt/num.rs:202:16
210 ...
211 Uninitialized value was stored to memory at
212 #0 0x560c04ae898a in __msan_memcpy.part.0 $RUST/src/llvm-project/compiler-rt/lib/msan/msan_interceptors.cc:1558:3
213 #1 0x560c04b2bf88 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:6:16
214
215 Uninitialized value was created by an allocation of 'a' in the stack frame of function '_ZN6memory4main17hd2333c1899d997f5E'
216 #0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
217 ```
218
219 # ThreadSanitizer
220
221 ThreadSanitizer is a data race detection tool. It is supported on the following
222 targets:
223
224 * `x86_64-apple-darwin`
225 * `x86_64-unknown-linux-gnu`
226
227 To work correctly ThreadSanitizer needs to be "aware" of all synchronization
228 operations in a program. It generally achieves that through combination of
229 library interception (for example synchronization performed through
230 `pthread_mutex_lock` / `pthread_mutex_unlock`) and compile time instrumentation
231 (e.g. atomic operations). Using it without instrumenting all the program code
232 can lead to false positive reports.
233
234 ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`,
235 nor synchronization performed using inline assembly code.
236
237 ## Example
238
239 ```rust
240 static mut A: usize = 0;
241
242 fn main() {
243 let t = std::thread::spawn(|| {
244 unsafe { A += 1 };
245 });
246 unsafe { A += 1 };
247
248 t.join().unwrap();
249 }
250 ```
251
252 ```shell
253 $ export RUSTFLAGS=-Zsanitizer=thread RUSTDOCFLAGS=-Zsanitizer=thread
254 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
255 ==================
256 WARNING: ThreadSanitizer: data race (pid=10574)
257 Read of size 8 at 0x5632dfe3d030 by thread T1:
258 #0 example::main::_$u7b$$u7b$closure$u7d$$u7d$::h23f64b0b2f8c9484 ../src/main.rs:5:18 (example+0x86cec)
259 ...
260
261 Previous write of size 8 at 0x5632dfe3d030 by main thread:
262 #0 example::main::h628ffc6626ed85b2 /.../src/main.rs:7:14 (example+0x868c8)
263 ...
264 #11 main <null> (example+0x86a1a)
265
266 Location is global 'example::A::h43ac149ddf992709' of size 8 at 0x5632dfe3d030 (example+0x000000bd9030)
267 ```
268
269 # Instrumentation of external dependencies and std
270
271 The sanitizers to varying degrees work correctly with partially instrumented
272 code. On the one extreme is LeakSanitizer that doesn't use any compile time
273 instrumentation, on the other is MemorySanitizer that requires that all program
274 code to be instrumented (failing to achieve that will inevitably result in
275 false positives).
276
277 It is strongly recommended to combine sanitizers with recompiled and
278 instrumented standard library, for example using [cargo `-Zbuild-std`
279 functionality][build-std].
280
281 [build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
282
283 # Build scripts and procedural macros
284
285 Use of sanitizers together with build scripts and procedural macros is
286 technically possible, but in almost all cases it would be best avoided. This
287 is especially true for procedural macros which would require an instrumented
288 version of rustc.
289
290 In more practical terms when using cargo always remember to pass `--target`
291 flag, so that rustflags will not be applied to build scripts and procedural
292 macros.
293
294 # Symbolizing the Reports
295
296 Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PATH`.
297
298 # Additional Information
299
300 * [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
301 * [AddressSanitizer in Clang][clang-asan]
302 * [LeakSanitizer in Clang][clang-lsan]
303 * [MemorySanitizer in Clang][clang-msan]
304 * [ThreadSanitizer in Clang][clang-tsan]
305
306 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
307 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
308 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
309 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html