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