Skip to content

Commit e88f071

Browse files
committed
Document sanitizers in unstable-book
1 parent ae57259 commit e88f071

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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 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.
12+
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
13+
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
14+
* [ThreadSanitizer][clang-tsan] a fast data race detector.
15+
16+
To enable a sanitizer compile with `-Zsanitizer=...` option, where value is one
17+
of `address`, `leak`, `memory` or `thread`.
18+
19+
# Examples
20+
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.
24+
25+
## AddressSanitizer
26+
27+
Stack buffer overflow:
28+
29+
```shell
30+
$ cat a.rs
31+
fn main() {
32+
let xs = [0, 1, 2, 3];
33+
let _y = unsafe { *xs.as_ptr().offset(4) };
34+
}
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)
55+
56+
This frame has 1 object(s):
57+
[32, 48) 'xs' <== Memory access at offset 48 overflows this variable
58+
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
59+
(longjmp and C++ exceptions *are* supported)
60+
SUMMARY: AddressSanitizer: stack-buffer-overflow (/tmp/a+0xa5c4) in a::main::hab3bd2a745c2d0ac
61+
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
73+
Shadow byte legend (one shadow byte represents 8 application bytes):
74+
Addressable: 00
75+
Partially addressable: 01 02 03 04 05 06 07
76+
Heap left redzone: fa
77+
Freed heap region: fd
78+
Stack left redzone: f1
79+
Stack mid redzone: f2
80+
Stack right redzone: f3
81+
Stack after return: f5
82+
Stack use after scope: f8
83+
Global redzone: f9
84+
Global init order: f6
85+
Poisoned by user: f7
86+
Container overflow: fc
87+
Array cookie: ac
88+
Intra object redzone: bb
89+
ASan internal: fe
90+
Left alloca redzone: ca
91+
Right alloca redzone: cb
92+
Shadow gap: cc
93+
==10029==ABORTING
94+
```
95+
96+
## MemorySanitizer
97+
98+
Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument
99+
standard library, and passing `-msan-track-origins=2` to the LLVM to track
100+
origins of uninitialized memory:
101+
102+
```shell
103+
$ cat src/main.rs
104+
use std::mem::MaybeUninit;
105+
106+
fn main() {
107+
unsafe {
108+
let a = MaybeUninit::<[usize; 4]>::uninit();
109+
let a = a.assume_init();
110+
println!("{}", a[2]);
111+
}
112+
}
113+
114+
$ env RUSTFLAGS="-Zsanitizer=memory -Cllvm-args=-msan-track-origins=2" cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
115+
==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
116+
#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
117+
...
118+
Uninitialized value was stored to memory at
119+
#0 0x560c04ae898a in __msan_memcpy.part.0 $RUST/src/llvm-project/compiler-rt/lib/msan/msan_interceptors.cc:1558:3
120+
#1 0x560c04b2bf88 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:6:16
121+
122+
Uninitialized value was created by an allocation of 'a' in the stack frame of function '_ZN6memory4main17hd2333c1899d997f5E'
123+
#0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
124+
```
125+
126+
127+
# Instrumentation of external dependencies and std
128+
129+
The sanitizers to varying degrees work correctly with partially instrumented
130+
code. On the one extreme is LeakSanitizer that doesn't use any compile time
131+
instrumentation, on the other is MemorySanitizer that requires that all program
132+
code to be instrumented (failing to achieve that will inevitably result in
133+
false positives).
134+
135+
It is strongly recommended to combine sanitizers with recompiled and
136+
instrumented standard library, for example using [cargo `-Zbuild-std`
137+
functionality][build-std].
138+
139+
[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
140+
141+
# Build scripts and procedural macros
142+
143+
Use of sanitizers together with build scripts and procedural macros is
144+
technically possible, but in almost all cases it would be best avoided. This
145+
is especially true for procedural macros which would require an instrumented
146+
version of rustc.
147+
148+
In more practical terms when using cargo always remember to pass `--target`
149+
flag, so that rustflags will not be applied to build scripts and procedural
150+
macros.
151+
152+
# Additional Information
153+
154+
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
155+
* [AddressSanitizer in Clang][clang-asan]
156+
* [LeakSanitizer in Clang][clang-lsan]
157+
* [MemorySanitizer in Clang][clang-msan]
158+
* [ThreadSanitizer in Clang][clang-tsan]
159+
160+
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
161+
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
162+
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
163+
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html

0 commit comments

Comments
 (0)