]> git.proxmox.com Git - rustc.git/blob - src/doc/unstable-book/src/compiler-flags/sanitizer.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / unstable-book / src / compiler-flags / sanitizer.md
1 # `sanitizer`
2
3 The tracking issues for this feature are:
4
5 * [#39699](https://github.com/rust-lang/rust/issues/39699).
6 * [#89653](https://github.com/rust-lang/rust/issues/89653).
7
8 ------------------------
9
10 This feature allows for use of one of following sanitizers:
11
12 * [AddressSanitizer][clang-asan] a fast memory error detector.
13 * [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides
14 forward-edge control flow protection.
15 * [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
16 AddressSanitizer, but based on partial hardware assistance.
17 * [LeakSanitizer][clang-lsan] a run-time memory leak detector.
18 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
19 * [MemTagSanitizer][clang-memtag] fast memory error detector based on
20 Armv8.5-A Memory Tagging Extension.
21 * [ThreadSanitizer][clang-tsan] a fast data race detector.
22
23 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
24 `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
25 `-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example:
26 ```shell
27 $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
28 ```
29
30 # AddressSanitizer
31
32 AddressSanitizer is a memory error detector. It can detect the following types
33 of bugs:
34
35 * Out of bound accesses to heap, stack and globals
36 * Use after free
37 * Use after return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
38 * Use after scope
39 * Double-free, invalid free
40 * Memory leaks
41
42 The memory leak detection is enabled by default on Linux, and can be enabled
43 with runtime flag `ASAN_OPTIONS=detect_leaks=1` on macOS.
44
45 AddressSanitizer is supported on the following targets:
46
47 * `aarch64-apple-darwin`
48 * `aarch64-fuchsia`
49 * `aarch64-unknown-linux-gnu`
50 * `x86_64-apple-darwin`
51 * `x86_64-fuchsia`
52 * `x86_64-unknown-freebsd`
53 * `x86_64-unknown-linux-gnu`
54
55 AddressSanitizer works with non-instrumented code although it will impede its
56 ability to detect some bugs. It is not expected to produce false positive
57 reports.
58
59 ## Examples
60
61 Stack buffer overflow:
62
63 ```rust
64 fn main() {
65 let xs = [0, 1, 2, 3];
66 let _y = unsafe { *xs.as_ptr().offset(4) };
67 }
68 ```
69
70 ```shell
71 $ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
72 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
73 ==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250 at pc 0x5609a841fb20 bp 0x7ffe400e6210 sp 0x7ffe400e6208
74 READ of size 4 at 0x7ffe400e6250 thread T0
75 #0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
76 ...
77
78 Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
79 #0 0x5609a841f8af in example::main::h628ffc6626ed85b2 /.../src/main.rs:1
80
81 This frame has 1 object(s):
82 [32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable
83 HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
84 (longjmp and C++ exceptions *are* supported)
85 SUMMARY: AddressSanitizer: stack-buffer-overflow /.../src/main.rs:3:23 in example::main::h628ffc6626ed85b2
86 Shadow bytes around the buggy address:
87 0x100048014bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
88 0x100048014c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
89 0x100048014c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90 0x100048014c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
91 0x100048014c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
92 =>0x100048014c40: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
93 0x100048014c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
94 0x100048014c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
95 0x100048014c70: f1 f1 f1 f1 00 00 f3 f3 00 00 00 00 00 00 00 00
96 0x100048014c80: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
97 0x100048014c90: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
98 Shadow byte legend (one shadow byte represents 8 application bytes):
99 Addressable: 00
100 Partially addressable: 01 02 03 04 05 06 07
101 Heap left redzone: fa
102 Freed heap region: fd
103 Stack left redzone: f1
104 Stack mid redzone: f2
105 Stack right redzone: f3
106 Stack after return: f5
107 Stack use after scope: f8
108 Global redzone: f9
109 Global init order: f6
110 Poisoned by user: f7
111 Container overflow: fc
112 Array cookie: ac
113 Intra object redzone: bb
114 ASan internal: fe
115 Left alloca redzone: ca
116 Right alloca redzone: cb
117 Shadow gap: cc
118 ==37882==ABORTING
119 ```
120
121 Use of a stack object after its scope has already ended:
122
123 ```rust
124 static mut P: *mut usize = std::ptr::null_mut();
125
126 fn main() {
127 unsafe {
128 {
129 let mut x = 0;
130 P = &mut x;
131 }
132 std::ptr::write_volatile(P, 123);
133 }
134 }
135 ```
136
137 ```shell
138 $ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
139 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
140 =================================================================
141 ==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0 at pc 0x55c98b262a8e bp 0x7ffc7ed3e050 sp 0x7ffc7ed3e048
142 WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0
143 #0 0x55c98b262a8d in core::ptr::write_volatile::he21f1df5a82f329a /.../src/rust/src/libcore/ptr/mod.rs:1048:5
144 #1 0x55c98b262cd2 in example::main::h628ffc6626ed85b2 /.../src/main.rs:9:9
145 ...
146
147 Address 0x7ffc7ed3e1a0 is located in stack of thread T0 at offset 32 in frame
148 #0 0x55c98b262bdf in example::main::h628ffc6626ed85b2 /.../src/main.rs:3
149
150 This frame has 1 object(s):
151 [32, 40) 'x' (line 6) <== Memory access at offset 32 is inside this variable
152 HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
153 (longjmp and C++ exceptions *are* supported)
154 SUMMARY: AddressSanitizer: stack-use-after-scope /.../src/rust/src/libcore/ptr/mod.rs:1048:5 in core::ptr::write_volatile::he21f1df5a82f329a
155 Shadow bytes around the buggy address:
156 0x10000fd9fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
157 0x10000fd9fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
158 0x10000fd9fc00: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
159 0x10000fd9fc10: f8 f8 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
160 0x10000fd9fc20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
161 =>0x10000fd9fc30: f1 f1 f1 f1[f8]f3 f3 f3 00 00 00 00 00 00 00 00
162 0x10000fd9fc40: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
163 0x10000fd9fc50: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
164 0x10000fd9fc60: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3
165 0x10000fd9fc70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
166 0x10000fd9fc80: 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3 00 00 00 00
167 Shadow byte legend (one shadow byte represents 8 application bytes):
168 Addressable: 00
169 Partially addressable: 01 02 03 04 05 06 07
170 Heap left redzone: fa
171 Freed heap region: fd
172 Stack left redzone: f1
173 Stack mid redzone: f2
174 Stack right redzone: f3
175 Stack after return: f5
176 Stack use after scope: f8
177 Global redzone: f9
178 Global init order: f6
179 Poisoned by user: f7
180 Container overflow: fc
181 Array cookie: ac
182 Intra object redzone: bb
183 ASan internal: fe
184 Left alloca redzone: ca
185 Right alloca redzone: cb
186 Shadow gap: cc
187 ==39249==ABORTING
188 ```
189
190 # ControlFlowIntegrity
191
192 The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
193 provides forward-edge control flow protection for Rust-compiled code only by
194 aggregating function pointers in groups identified by their number of arguments.
195
196 Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
197 binaries" (i.e., for when C or C++ and Rust -compiled code share the same
198 virtual address space) will be provided in later work by defining and using
199 compatible type identifiers (see Type metadata in the design document in the
200 tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
201
202 LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
203
204 ## Example
205
206 ```text
207 #![feature(naked_functions)]
208
209 use std::arch::asm;
210 use std::mem;
211
212 fn add_one(x: i32) -> i32 {
213 x + 1
214 }
215
216 #[naked]
217 pub extern "C" fn add_two(x: i32) {
218 // x + 2 preceded by a landing pad/nop block
219 unsafe {
220 asm!(
221 "
222 nop
223 nop
224 nop
225 nop
226 nop
227 nop
228 nop
229 nop
230 nop
231 lea rax, [rdi+2]
232 ret
233 ",
234 options(noreturn)
235 );
236 }
237 }
238
239 fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
240 f(arg) + f(arg)
241 }
242
243 fn main() {
244 let answer = do_twice(add_one, 5);
245
246 println!("The answer is: {answer}");
247
248 println!("With CFI enabled, you should not see the next answer");
249 let f: fn(i32) -> i32 = unsafe {
250 // Offsets 0-8 make it land in the landing pad/nop block, and offsets 1-8 are
251 // invalid branch/call destinations (i.e., within the body of the function).
252 mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
253 };
254 let next_answer = do_twice(f, 5);
255
256 println!("The next answer is: {next_answer}");
257 }
258 ```
259 Fig. 1. Modified example from the [Advanced Functions and
260 Closures][rust-book-ch19-05] chapter of the [The Rust Programming
261 Language][rust-book] book.
262
263 [//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
264
265 ```shell
266 $ rustc rust_cfi.rs -o rust_cfi
267 $ ./rust_cfi
268 The answer is: 12
269 With CFI enabled, you should not see the next answer
270 The next answer is: 14
271 $
272 ```
273 Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
274
275 [//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
276
277 ```shell
278 $ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
279 $ ./rust_cfi
280 The answer is: 12
281 With CFI enabled, you should not see the next answer
282 Illegal instruction
283 $
284 ```
285 Fig. 3. Build and execution of the modified example with LLVM CFI enabled.
286
287 When LLVM CFI is enabled, if there are any attempts to change/hijack control
288 flow using an indirect branch/call to an invalid destination, the execution is
289 terminated (see Fig. 3).
290
291 ```rust
292 use std::mem;
293
294 fn add_one(x: i32) -> i32 {
295 x + 1
296 }
297
298 fn add_two(x: i32, _y: i32) -> i32 {
299 x + 2
300 }
301
302 fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
303 f(arg) + f(arg)
304 }
305
306 fn main() {
307 let answer = do_twice(add_one, 5);
308
309 println!("The answer is: {answer}");
310
311 println!("With CFI enabled, you should not see the next answer");
312 let f: fn(i32) -> i32 =
313 unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
314 let next_answer = do_twice(f, 5);
315
316 println!("The next answer is: {next_answer}");
317 }
318 ```
319 Fig. 4. Another modified example from the [Advanced Functions and
320 Closures][rust-book-ch19-05] chapter of the [The Rust Programming
321 Language][rust-book] book.
322
323 [//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
324
325 ```shell
326 $ rustc rust_cfi.rs -o rust_cfi
327 $ ./rust_cfi
328 The answer is: 12
329 With CFI enabled, you should not see the next answer
330 The next answer is: 14
331 $
332 ```
333 Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
334
335 [//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
336
337 ```shell
338 $ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
339 $ ./rust_cfi
340 The answer is: 12
341 With CFI enabled, you should not see the next answer
342 Illegal instruction
343 $
344 ```
345 Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
346
347 When LLVM CFI is enabled, if there are any attempts to change/hijack control
348 flow using an indirect branch/call to a function with different number of
349 arguments than intended/passed in the call/branch site, the execution is also
350 terminated (see Fig. 6).
351
352 Forward-edge control flow protection not only by aggregating function pointers
353 in groups identified by their number of arguments, but also their argument
354 types, will also be provided in later work by defining and using compatible type
355 identifiers (see Type metadata in the design document in the tracking
356 issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
357
358 [rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
359 [rust-book]: https://doc.rust-lang.org/book/title-page.html
360
361 # HWAddressSanitizer
362
363 HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much
364 less memory.
365
366 HWAddressSanitizer is supported on the following targets:
367
368 * `aarch64-linux-android`
369 * `aarch64-unknown-linux-gnu`
370
371 HWAddressSanitizer requires `tagged-globals` target feature to instrument
372 globals. To enable this target feature compile with `-C
373 target-feature=+tagged-globals`
374
375 ## Example
376
377 Heap buffer overflow:
378
379 ```rust
380 fn main() {
381 let xs = vec![0, 1, 2, 3];
382 let _y = unsafe { *xs.as_ptr().offset(4) };
383 }
384 ```
385
386 ```shell
387 $ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C
388 linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target
389 aarch64-unknown-linux-gnu
390 ```
391
392 ```shell
393 $ ./main
394 ==241==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefdeffff0050 at pc 0xaaaae0ae4a98
395 READ of size 4 at 0xefdeffff0050 tags: 2c/00 (ptr/mem) in thread T0
396 #0 0xaaaae0ae4a94 (/.../main+0x54a94)
397 ...
398
399 [0xefdeffff0040,0xefdeffff0060) is a small allocated heap chunk; size: 32 offset: 16
400 0xefdeffff0050 is located 0 bytes to the right of 16-byte region [0xefdeffff0040,0xefdeffff0050)
401 allocated here:
402 #0 0xaaaae0acb80c (/.../main+0x3b80c)
403 ...
404
405 Thread: T0 0xeffe00002000 stack: [0xffffc28ad000,0xffffc30ad000) sz: 8388608 tls: [0xffffaa10a020,0xffffaa10a7d0)
406 Memory tags around the buggy address (one tag corresponds to 16 bytes):
407 0xfefcefffef80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
408 0xfefcefffef90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
409 0xfefcefffefa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
410 0xfefcefffefb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
411 0xfefcefffefc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
412 0xfefcefffefd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
413 0xfefcefffefe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
414 0xfefcefffeff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
415 =>0xfefceffff000: d7 d7 05 00 2c [00] 00 00 00 00 00 00 00 00 00 00
416 0xfefceffff010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
417 0xfefceffff020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
418 0xfefceffff030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
419 0xfefceffff040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
420 0xfefceffff050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
421 0xfefceffff060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
422 0xfefceffff070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
423 0xfefceffff080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
424 Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
425 0xfefcefffeff0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
426 =>0xfefceffff000: .. .. 8c .. .. [..] .. .. .. .. .. .. .. .. .. ..
427 0xfefceffff010: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
428 See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags
429 Registers where the failure occurred (pc 0xaaaae0ae4a98):
430 x0 2c00efdeffff0050 x1 0000000000000004 x2 0000000000000004 x3 0000000000000000
431 x4 0000fffefc30ac37 x5 000000000000005d x6 00000ffffc30ac37 x7 0000efff00000000
432 x8 2c00efdeffff0050 x9 0200efff00000000 x10 0000000000000000 x11 0200efff00000000
433 x12 0200effe00000310 x13 0200effe00000310 x14 0000000000000008 x15 5d00ffffc30ac360
434 x16 0000aaaae0ad062c x17 0000000000000003 x18 0000000000000001 x19 0000ffffc30ac658
435 x20 4e00ffffc30ac6e0 x21 0000aaaae0ac5e10 x22 0000000000000000 x23 0000000000000000
436 x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000
437 x28 0000000000000000 x29 0000ffffc30ac5a0 x30 0000aaaae0ae4a98
438 SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94)
439 ```
440
441 # LeakSanitizer
442
443 LeakSanitizer is run-time memory leak detector.
444
445 LeakSanitizer is supported on the following targets:
446
447 * `aarch64-apple-darwin`
448 * `aarch64-unknown-linux-gnu`
449 * `x86_64-apple-darwin`
450 * `x86_64-unknown-linux-gnu`
451
452 # MemorySanitizer
453
454 MemorySanitizer is detector of uninitialized reads.
455
456 MemorySanitizer is supported on the following targets:
457
458 * `aarch64-unknown-linux-gnu`
459 * `x86_64-unknown-freebsd`
460 * `x86_64-unknown-linux-gnu`
461
462 MemorySanitizer requires all program code to be instrumented. C/C++ dependencies
463 need to be recompiled using Clang with `-fsanitize=memory` option. Failing to
464 achieve that will result in false positive reports.
465
466 ## Example
467
468 Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
469 instruments the standard library, and is strictly necessary for the correct
470 operation of the tool. The `-Zsanitizer-memory-track-origins` enables tracking
471 of the origins of uninitialized memory:
472
473 ```rust
474 use std::mem::MaybeUninit;
475
476 fn main() {
477 unsafe {
478 let a = MaybeUninit::<[usize; 4]>::uninit();
479 let a = a.assume_init();
480 println!("{}", a[2]);
481 }
482 }
483 ```
484
485 ```shell
486 $ export \
487 RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
488 RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
489 $ cargo clean
490 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
491 ==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
492 #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
493 ...
494 Uninitialized value was stored to memory at
495 #0 0x560c04ae898a in __msan_memcpy.part.0 $RUST/src/llvm-project/compiler-rt/lib/msan/msan_interceptors.cc:1558:3
496 #1 0x560c04b2bf88 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:6:16
497
498 Uninitialized value was created by an allocation of 'a' in the stack frame of function '_ZN6memory4main17hd2333c1899d997f5E'
499 #0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
500 ```
501
502 # MemTagSanitizer
503
504 MemTagSanitizer detects a similar class of errors as AddressSanitizer and HardwareAddressSanitizer, but with lower overhead suitable for use as hardening for production binaries.
505
506 MemTagSanitizer is supported on the following targets:
507
508 * `aarch64-linux-android`
509 * `aarch64-unknown-linux-gnu`
510
511 MemTagSanitizer requires hardware support and the `mte` target feature.
512 To enable this target feature compile with `-C target-feature="+mte"`.
513
514 More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
515
516 # ThreadSanitizer
517
518 ThreadSanitizer is a data race detection tool. It is supported on the following
519 targets:
520
521 * `aarch64-apple-darwin`
522 * `aarch64-unknown-linux-gnu`
523 * `x86_64-apple-darwin`
524 * `x86_64-unknown-freebsd`
525 * `x86_64-unknown-linux-gnu`
526
527 To work correctly ThreadSanitizer needs to be "aware" of all synchronization
528 operations in a program. It generally achieves that through combination of
529 library interception (for example synchronization performed through
530 `pthread_mutex_lock` / `pthread_mutex_unlock`) and compile time instrumentation
531 (e.g. atomic operations). Using it without instrumenting all the program code
532 can lead to false positive reports.
533
534 ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`,
535 nor synchronization performed using inline assembly code.
536
537 ## Example
538
539 ```rust
540 static mut A: usize = 0;
541
542 fn main() {
543 let t = std::thread::spawn(|| {
544 unsafe { A += 1 };
545 });
546 unsafe { A += 1 };
547
548 t.join().unwrap();
549 }
550 ```
551
552 ```shell
553 $ export RUSTFLAGS=-Zsanitizer=thread RUSTDOCFLAGS=-Zsanitizer=thread
554 $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
555 ==================
556 WARNING: ThreadSanitizer: data race (pid=10574)
557 Read of size 8 at 0x5632dfe3d030 by thread T1:
558 #0 example::main::_$u7b$$u7b$closure$u7d$$u7d$::h23f64b0b2f8c9484 ../src/main.rs:5:18 (example+0x86cec)
559 ...
560
561 Previous write of size 8 at 0x5632dfe3d030 by main thread:
562 #0 example::main::h628ffc6626ed85b2 /.../src/main.rs:7:14 (example+0x868c8)
563 ...
564 #11 main <null> (example+0x86a1a)
565
566 Location is global 'example::A::h43ac149ddf992709' of size 8 at 0x5632dfe3d030 (example+0x000000bd9030)
567 ```
568
569 # Instrumentation of external dependencies and std
570
571 The sanitizers to varying degrees work correctly with partially instrumented
572 code. On the one extreme is LeakSanitizer that doesn't use any compile time
573 instrumentation, on the other is MemorySanitizer that requires that all program
574 code to be instrumented (failing to achieve that will inevitably result in
575 false positives).
576
577 It is strongly recommended to combine sanitizers with recompiled and
578 instrumented standard library, for example using [cargo `-Zbuild-std`
579 functionality][build-std].
580
581 [build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
582
583 # Build scripts and procedural macros
584
585 Use of sanitizers together with build scripts and procedural macros is
586 technically possible, but in almost all cases it would be best avoided. This
587 is especially true for procedural macros which would require an instrumented
588 version of rustc.
589
590 In more practical terms when using cargo always remember to pass `--target`
591 flag, so that rustflags will not be applied to build scripts and procedural
592 macros.
593
594 # Symbolizing the Reports
595
596 Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PATH`.
597
598 # Additional Information
599
600 * [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
601 * [AddressSanitizer in Clang][clang-asan]
602 * [ControlFlowIntegrity in Clang][clang-cfi]
603 * [HWAddressSanitizer in Clang][clang-hwasan]
604 * [LeakSanitizer in Clang][clang-lsan]
605 * [MemorySanitizer in Clang][clang-msan]
606 * [ThreadSanitizer in Clang][clang-tsan]
607
608 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
609 [clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
610 [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
611 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
612 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
613 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html