@@ -6,73 +6,78 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru
66
77This feature allows for use of one of following sanitizers:
88
9- * [ AddressSanitizer] [ clang-asan ] a faster memory error detector. Can
10- detect out-of-bounds access to heap, stack, and globals, use after free, use
11- after return, double free, invalid free, memory leaks.
9+ * [ AddressSanitizer] [ clang-asan ] a fast memory error detector.
1210* [ LeakSanitizer] [ clang-lsan ] a run-time memory leak detector.
1311* [ MemorySanitizer] [ clang-msan ] a detector of uninitialized reads.
1412* [ ThreadSanitizer] [ clang-tsan ] a fast data race detector.
1513
16- To enable a sanitizer compile with ` -Zsanitizer=... ` option, where value is one
17- of ` address ` , ` leak ` , ` memory ` or ` thread ` .
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.
1817
19- # Examples
18+ # AddressSanitizer
2019
21- This sections show various issues that can be detected with sanitizers. For
22- simplicity, the examples are prepared under assumption that optimization level
23- used is zero.
20+ AddressSanitizer is a memory error detector. It can detect the following types
21+ of bugs:
2422
25- ## AddressSanitizer
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
2640
2741Stack buffer overflow:
2842
29- ``` shell
30- $ cat a.rs
43+ ``` rust
3144fn main () {
3245 let xs = [0 , 1 , 2 , 3 ];
3346 let _y = unsafe { * xs . as_ptr (). offset (4 ) };
3447}
35- $ rustc -Zsanitizer=address a.rs
36- $ ./a
37- =================================================================
38- ==10029==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcc15f43d0 at pc 0x55f77dc015c5 bp 0x7ffcc15f4390 sp 0x7ffcc15f4388
39- READ of size 4 at 0x7ffcc15f43d0 thread T0
40- # 0 0x55f77dc015c4 in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa5c4)
41- # 1 0x55f77dc01cdb in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::haa8c76d1faa7b7ca (/tmp/a+0xacdb)
42- # 2 0x55f77dc90f02 in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hfeb9a1aef9ac820d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:48:12
43- # 3 0x55f77dc90f02 in std::panicking::try::do_call::h12f0919717b8e0a6 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:288:39
44- # 4 0x55f77dc926c9 in __rust_maybe_catch_panic /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libpanic_unwind/lib.rs:80:7
45- # 5 0x55f77dc9197c in std::panicking::try::h413b21cdcd6cfd86 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:267:12
46- # 6 0x55f77dc9197c in std::panic::catch_unwind::hc5cc8ef2fd73424d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panic.rs:396:8
47- # 7 0x55f77dc9197c in std::rt::lang_start_internal::h2039f418ab92218f /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:47:24
48- # 8 0x55f77dc01c61 in std::rt::lang_start::ha905d28f6b61d691 (/tmp/a+0xac61)
49- # 9 0x55f77dc0163a in main (/tmp/a+0xa63a)
50- # 10 0x7f9b3cf5bbba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
51- # 11 0x55f77dc01289 in _start (/tmp/a+0xa289)
52-
53- Address 0x7ffcc15f43d0 is located in stack of thread T0 at offset 48 in frame
54- # 0 0x55f77dc0135f in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa35f)
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
5560
5661 This frame has 1 object(s):
57- [32, 48) ' xs' <== Memory access at offset 48 overflows this variable
62+ [32, 48) ' xs' (line 2) <== Memory access at offset 48 overflows this variable
5863HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
5964 (longjmp and C++ exceptions * are* supported)
60- SUMMARY: AddressSanitizer: stack-buffer-overflow (/tmp/a+0xa5c4) in a ::main::hab3bd2a745c2d0ac
65+ SUMMARY: AddressSanitizer: stack-buffer-overflow /.../src/main.rs:3:23 in example ::main::h628ffc6626ed85b2
6166Shadow bytes around the buggy address:
62- 0x1000182b6820 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63- 0x1000182b6830 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
64- 0x1000182b6840 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
65- 0x1000182b6850 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
66- 0x1000182b6860 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
67- => 0x1000182b6870 : 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
68- 0x1000182b6880 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69- 0x1000182b6890 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70- 0x1000182b68a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
71- 0x1000182b68b0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
72- 0x1000182b68c0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
7378Shadow byte legend (one shadow byte represents 8 application bytes):
7479 Addressable: 00
75- Partially addressable: 01 02 03 04 05 06 07
80+ Partially addressable: 01 02 03 04 05 06 07
7681 Heap left redzone: fa
7782 Freed heap region: fd
7883 Stack left redzone: f1
@@ -90,13 +95,12 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
9095 Left alloca redzone: ca
9196 Right alloca redzone: cb
9297 Shadow gap: cc
93- ==10029 ==ABORTING
98+ ==37882 ==ABORTING
9499` ` `
95100
96101Use of a stack object after its scope has already ended:
97102
98- ` ` ` shell
99- $ cat b.rs
103+ ` ` ` rust
100104static mut P: * mut usize = std::ptr::null_mut ();
101105
102106fn main () {
@@ -108,42 +112,38 @@ fn main() {
108112 std::ptr::write_volatile(P, 123);
109113 }
110114}
111- $ rustc -Zsanitizer=address b.rs
112- $./b
115+ ` ` `
116+
117+ ` ` ` shell
118+ $ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
119+ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
113120=================================================================
114- ==424427==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff67be6be0 at pc 0x5647a3ea4658 bp 0x7fff67be6b90 sp 0x7fff67be6b88
115- WRITE of size 8 at 0x7fff67be6be0 thread T0
116- # 0 0x5647a3ea4657 in core::ptr::write_volatile::h4b04601757d0376d (/tmp/b+0xb8657)
117- # 1 0x5647a3ea4432 in b::main::h5574a756e615c9cf (/tmp/b+0xb8432)
118- # 2 0x5647a3ea480b in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd57e7ee01866077e (/tmp/b+0xb880b)
119- # 3 0x5647a3eab412 in std::panicking::try::do_call::he0421ca82dd11ba3 (.llvm.8083791802951296215) (/tmp/b+0xbf412)
120- # 4 0x5647a3eacb26 in __rust_maybe_catch_panic (/tmp/b+0xc0b26)
121- # 5 0x5647a3ea5b66 in std::rt::lang_start_internal::h19bc96b28f670a64 (/tmp/b+0xb9b66)
122- # 6 0x5647a3ea4788 in std::rt::lang_start::h642d10b4b6965fb8 (/tmp/b+0xb8788)
123- # 7 0x5647a3ea449a in main (/tmp/b+0xb849a)
124- # 8 0x7fd1d18b3bba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
125- # 9 0x5647a3df7299 in _start (/tmp/b+0xb299)
126-
127- Address 0x7fff67be6be0 is located in stack of thread T0 at offset 32 in frame
128- # 0 0x5647a3ea433f in b::main::h5574a756e615c9cf (/tmp/b+0xb833f)
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
129129
130130 This frame has 1 object(s):
131- [32, 40) ' x' <== Memory access at offset 32 is inside this variable
131+ [32, 40) ' x' (line 6) <== Memory access at offset 32 is inside this variable
132132HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
133133 (longjmp and C++ exceptions * are* supported)
134- SUMMARY: AddressSanitizer: stack-use-after-scope (/tmp/b+0xb8657) in core::ptr::write_volatile::h4b04601757d0376d
134+ SUMMARY: AddressSanitizer: stack-use-after-scope /.../src/rust/src/libcore/ptr/mod.rs:1048:5 in core::ptr::write_volatile::he21f1df5a82f329a
135135Shadow bytes around the buggy address:
136- 0x10006cf74d20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
137- 0x10006cf74d30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
138- 0x10006cf74d40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
139- 0x10006cf74d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
140- 0x10006cf74d60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
141- => 0x10006cf74d70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1[f8]f3 f3 f3
142- 0x10006cf74d80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
143- 0x10006cf74d90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
144- 0x10006cf74da0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
145- 0x10006cf74db0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
146- 0x10006cf74dc0: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
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
147147Shadow byte legend (one shadow byte represents 8 application bytes):
148148 Addressable: 00
149149 Partially addressable: 01 02 03 04 05 06 07
@@ -164,17 +164,26 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
164164 Left alloca redzone: ca
165165 Right alloca redzone: cb
166166 Shadow gap: cc
167- ==424427 ==ABORTING
167+ ==39249 ==ABORTING
168168` ` `
169169
170- # # MemorySanitizer
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
171180
172- Use of uninitialized memory. Note that we are using ` -Zbuild-std` to instrument
173- the standard library, and passing ` -Zsanitizer-track-origins` to track the
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
174184origins of uninitialized memory:
175185
176- ` ` ` shell
177- $ cat src/main.rs
186+ ` ` ` rust
178187use std::mem::MaybeUninit;
179188
180189fn main () {
@@ -184,7 +193,9 @@ fn main() {
184193 println! (" {}" , a[2]);
185194 }
186195}
196+ ` ` `
187197
198+ ` ` ` shell
188199$ export \
189200 CC= clang \
190201 CXX= clang++ \
@@ -193,7 +204,7 @@ $ export \
193204 RUSTFLAGS= ' -Zsanitizer=memory -Zsanitizer-memory-track-origins' \
194205 RUSTDOCFLAGS= ' -Zsanitizer=memory -Zsanitizer-memory-track-origins'
195206$ cargo clean
196- $ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
207+ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
197208== 9416== WARNING: MemorySanitizer: use-of-uninitialized-value
198209 # 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
199210...
@@ -205,6 +216,55 @@ $ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
205216 # 0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
206217` ` `
207218
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+ ` ` `
208268
209269# Instrumentation of external dependencies and std
210270
@@ -231,6 +291,10 @@ In more practical terms when using cargo always remember to pass `--target`
231291flag, so that rustflags will not be applied to build scripts and procedural
232292macros.
233293
294+ # Symbolizing the Reports
295+
296+ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PATH`.
297+
234298# Additional Information
235299
236300* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
0 commit comments