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