@@ -6,73 +6,78 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru
6
6
7
7
This feature allows for use of one of following sanitizers:
8
8
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.
12
10
* [ LeakSanitizer] [ clang-lsan ] a run-time memory leak detector.
13
11
* [ MemorySanitizer] [ clang-msan ] a detector of uninitialized reads.
14
12
* [ ThreadSanitizer] [ clang-tsan ] a fast data race detector.
15
13
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.
18
17
19
- # Examples
18
+ # AddressSanitizer
20
19
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:
24
22
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
26
40
27
41
Stack buffer overflow:
28
42
29
- ``` shell
30
- $ cat a.rs
43
+ ``` rust
31
44
fn main () {
32
45
let xs = [0 , 1 , 2 , 3 ];
33
46
let _y = unsafe { * xs . as_ptr (). offset (4 ) };
34
47
}
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
55
60
56
61
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
58
63
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
59
64
(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
61
66
Shadow 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
73
78
Shadow byte legend (one shadow byte represents 8 application bytes):
74
79
Addressable: 00
75
- Partially addressable: 01 02 03 04 05 06 07
80
+ Partially addressable: 01 02 03 04 05 06 07
76
81
Heap left redzone: fa
77
82
Freed heap region: fd
78
83
Stack left redzone: f1
@@ -90,13 +95,12 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
90
95
Left alloca redzone: ca
91
96
Right alloca redzone: cb
92
97
Shadow gap: cc
93
- ==10029 ==ABORTING
98
+ ==37882 ==ABORTING
94
99
` ` `
95
100
96
101
Use of a stack object after its scope has already ended:
97
102
98
- ` ` ` shell
99
- $ cat b.rs
103
+ ` ` ` rust
100
104
static mut P: * mut usize = std::ptr::null_mut ();
101
105
102
106
fn main () {
@@ -108,42 +112,38 @@ fn main() {
108
112
std::ptr::write_volatile(P, 123);
109
113
}
110
114
}
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
113
120
=================================================================
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
129
129
130
130
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
132
132
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
133
133
(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
135
135
Shadow 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
147
147
Shadow byte legend (one shadow byte represents 8 application bytes):
148
148
Addressable: 00
149
149
Partially addressable: 01 02 03 04 05 06 07
@@ -164,17 +164,26 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
164
164
Left alloca redzone: ca
165
165
Right alloca redzone: cb
166
166
Shadow gap: cc
167
- ==424427 ==ABORTING
167
+ ==39249 ==ABORTING
168
168
` ` `
169
169
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
171
180
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
174
184
origins of uninitialized memory:
175
185
176
- ` ` ` shell
177
- $ cat src/main.rs
186
+ ` ` ` rust
178
187
use std::mem::MaybeUninit;
179
188
180
189
fn main () {
@@ -184,7 +193,9 @@ fn main() {
184
193
println! (" {}" , a[2]);
185
194
}
186
195
}
196
+ ` ` `
187
197
198
+ ` ` ` shell
188
199
$ export \
189
200
CC= clang \
190
201
CXX= clang++ \
@@ -193,7 +204,7 @@ $ export \
193
204
RUSTFLAGS= ' -Zsanitizer=memory -Zsanitizer-memory-track-origins' \
194
205
RUSTDOCFLAGS= ' -Zsanitizer=memory -Zsanitizer-memory-track-origins'
195
206
$ cargo clean
196
- $ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
207
+ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
197
208
== 9416== WARNING: MemorySanitizer: use-of-uninitialized-value
198
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
199
210
...
@@ -205,6 +216,55 @@ $ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
205
216
# 0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
206
217
` ` `
207
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
+ ` ` `
208
268
209
269
# Instrumentation of external dependencies and std
210
270
@@ -231,6 +291,10 @@ In more practical terms when using cargo always remember to pass `--target`
231
291
flag, so that rustflags will not be applied to build scripts and procedural
232
292
macros.
233
293
294
+ # Symbolizing the Reports
295
+
296
+ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PATH`.
297
+
234
298
# Additional Information
235
299
236
300
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
0 commit comments