Skip to content

Detect use-after-scope bugs with AddressSanitizer #68572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/sanitizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,80 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
==10029==ABORTING
```

Use of a stack object after its scope has already ended:

```shell
$ cat b.rs
static mut P: *mut usize = std::ptr::null_mut();

fn main() {
unsafe {
{
let mut x = 0;
P = &mut x;
}
std::ptr::write_volatile(P, 123);
}
}
$ rustc -Zsanitizer=address b.rs
$./b
=================================================================
==424427==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff67be6be0 at pc 0x5647a3ea4658 bp 0x7fff67be6b90 sp 0x7fff67be6b88
WRITE of size 8 at 0x7fff67be6be0 thread T0
#0 0x5647a3ea4657 in core::ptr::write_volatile::h4b04601757d0376d (/tmp/b+0xb8657)
#1 0x5647a3ea4432 in b::main::h5574a756e615c9cf (/tmp/b+0xb8432)
#2 0x5647a3ea480b in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd57e7ee01866077e (/tmp/b+0xb880b)
#3 0x5647a3eab412 in std::panicking::try::do_call::he0421ca82dd11ba3 (.llvm.8083791802951296215) (/tmp/b+0xbf412)
#4 0x5647a3eacb26 in __rust_maybe_catch_panic (/tmp/b+0xc0b26)
#5 0x5647a3ea5b66 in std::rt::lang_start_internal::h19bc96b28f670a64 (/tmp/b+0xb9b66)
#6 0x5647a3ea4788 in std::rt::lang_start::h642d10b4b6965fb8 (/tmp/b+0xb8788)
#7 0x5647a3ea449a in main (/tmp/b+0xb849a)
#8 0x7fd1d18b3bba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
#9 0x5647a3df7299 in _start (/tmp/b+0xb299)

Address 0x7fff67be6be0 is located in stack of thread T0 at offset 32 in frame
#0 0x5647a3ea433f in b::main::h5574a756e615c9cf (/tmp/b+0xb833f)

This frame has 1 object(s):
[32, 40) 'x' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope (/tmp/b+0xb8657) in core::ptr::write_volatile::h4b04601757d0376d
Shadow bytes around the buggy address:
0x10006cf74d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10006cf74d70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1[f8]f3 f3 f3
0x10006cf74d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006cf74dc0: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==424427==ABORTING
```

## MemorySanitizer

Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument
Expand Down
15 changes: 11 additions & 4 deletions src/librustc_codegen_llvm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use libc::{c_char, c_uint};
use log::debug;
use rustc::session::config;
use rustc::session::config::{self, Sanitizer};
use rustc::ty::layout::{self, Align, Size, TyLayout};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_codegen_ssa::base::to_immediate;
Expand Down Expand Up @@ -1232,12 +1232,19 @@ impl Builder<'a, 'll, 'tcx> {
}

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

let size = size.bytes();
if size == 0 {
let opts = &self.cx.sess().opts;
let emit = match opts.debugging_opts.sanitizer {
// Some sanitizer use lifetime intrinsics. When they are in use,
// emit lifetime intrinsics regardless of optimization level.
Some(Sanitizer::Address) | Some(Sanitizer::Memory) => true,
_ => opts.optimize != config::OptLevel::No,
};
if !emit {
return;
}

Expand Down
3 changes: 2 additions & 1 deletion src/rustllvm/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {

extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
const bool CompileKernel = false;
const bool UseAfterScope = true;

return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover));
return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
}

extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/sanitizer-use-after-scope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// needs-sanitizer-support
// only-x86_64
//
// compile-flags: -Zsanitizer=address
// run-fail
// error-pattern: ERROR: AddressSanitizer: stack-use-after-scope

static mut P: *mut usize = std::ptr::null_mut();

fn main() {
unsafe {
{
let mut x = 0;
P = &mut x;
}
std::ptr::write_volatile(P, 123);
}
}