Skip to content

Commit edb3684

Browse files
committed
Auto merge of #68572 - tmiasko:sanitizer-use-after-scope, r=nikic
Detect use-after-scope bugs with AddressSanitizer Enable use-after-scope checks by default when using AddressSanitizer. They allow to detect incorrect use of stack objects after their scope have already ended. The detection is based on LLVM lifetime intrinsics. To facilitate the use of this functionality, the lifetime intrinsics are now emitted regardless of optimization level if enabled sanitizer makes use of them.
2 parents 343432a + 47fd27a commit edb3684

File tree

10 files changed

+105
-5
lines changed

10 files changed

+105
-5
lines changed

src/doc/unstable-book/src/compiler-flags/sanitizer.md

+74
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,80 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
9393
==10029==ABORTING
9494
```
9595
96+
Use of a stack object after its scope has already ended:
97+
98+
```shell
99+
$ cat b.rs
100+
static mut P: *mut usize = std::ptr::null_mut();
101+
102+
fn main() {
103+
unsafe {
104+
{
105+
let mut x = 0;
106+
P = &mut x;
107+
}
108+
std::ptr::write_volatile(P, 123);
109+
}
110+
}
111+
$ rustc -Zsanitizer=address b.rs
112+
$./b
113+
=================================================================
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)
129+
130+
This frame has 1 object(s):
131+
[32, 40) 'x' <== Memory access at offset 32 is inside this variable
132+
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
133+
(longjmp and C++ exceptions *are* supported)
134+
SUMMARY: AddressSanitizer: stack-use-after-scope (/tmp/b+0xb8657) in core::ptr::write_volatile::h4b04601757d0376d
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
147+
Shadow byte legend (one shadow byte represents 8 application bytes):
148+
Addressable: 00
149+
Partially addressable: 01 02 03 04 05 06 07
150+
Heap left redzone: fa
151+
Freed heap region: fd
152+
Stack left redzone: f1
153+
Stack mid redzone: f2
154+
Stack right redzone: f3
155+
Stack after return: f5
156+
Stack use after scope: f8
157+
Global redzone: f9
158+
Global init order: f6
159+
Poisoned by user: f7
160+
Container overflow: fc
161+
Array cookie: ac
162+
Intra object redzone: bb
163+
ASan internal: fe
164+
Left alloca redzone: ca
165+
Right alloca redzone: cb
166+
Shadow gap: cc
167+
==424427==ABORTING
168+
```
169+
96170
## MemorySanitizer
97171
98172
Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument

src/librustc_codegen_llvm/builder.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
77
use crate::value::Value;
88
use libc::{c_char, c_uint};
99
use log::debug;
10-
use rustc::session::config;
10+
use rustc::session::config::{self, Sanitizer};
1111
use rustc::ty::layout::{self, Align, Size, TyLayout};
1212
use rustc::ty::{self, Ty, TyCtxt};
1313
use rustc_codegen_ssa::base::to_immediate;
@@ -1232,12 +1232,19 @@ impl Builder<'a, 'll, 'tcx> {
12321232
}
12331233

12341234
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
1235-
if self.cx.sess().opts.optimize == config::OptLevel::No {
1235+
let size = size.bytes();
1236+
if size == 0 {
12361237
return;
12371238
}
12381239

1239-
let size = size.bytes();
1240-
if size == 0 {
1240+
let opts = &self.cx.sess().opts;
1241+
let emit = match opts.debugging_opts.sanitizer {
1242+
// Some sanitizer use lifetime intrinsics. When they are in use,
1243+
// emit lifetime intrinsics regardless of optimization level.
1244+
Some(Sanitizer::Address) | Some(Sanitizer::Memory) => true,
1245+
_ => opts.optimize != config::OptLevel::No,
1246+
};
1247+
if !emit {
12411248
return;
12421249
}
12431250

src/rustllvm/PassWrapper.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
8787

8888
extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
8989
const bool CompileKernel = false;
90+
const bool UseAfterScope = true;
9091

91-
return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover));
92+
return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
9293
}
9394

9495
extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// needs-sanitizer-support
2+
// only-x86_64
3+
//
4+
// compile-flags: -Zsanitizer=address
5+
// run-fail
6+
// error-pattern: ERROR: AddressSanitizer: stack-use-after-scope
7+
8+
static mut P: *mut usize = std::ptr::null_mut();
9+
10+
fn main() {
11+
unsafe {
12+
{
13+
let mut x = 0;
14+
P = &mut x;
15+
}
16+
std::ptr::write_volatile(P, 123);
17+
}
18+
}

0 commit comments

Comments
 (0)