about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-01-29 07:44:36 +0000
committerbors <bors@rust-lang.org>2020-01-29 07:44:36 +0000
commitedb368491551a77d77a48446d4ee88b35490c565 (patch)
tree711d4b5a6e40ef4281b2a4b3f5c9cb9aa8c41f5f
parent343432a74d1b92e4d3e71de4271e68304e046da3 (diff)
parent47fd27a637b7311c81437f138932ddb426350ab7 (diff)
downloadrust-edb368491551a77d77a48446d4ee88b35490c565.tar.gz
rust-edb368491551a77d77a48446d4ee88b35490c565.zip
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.
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md74
-rw-r--r--src/librustc_codegen_llvm/builder.rs15
-rw-r--r--src/rustllvm/PassWrapper.cpp3
-rw-r--r--src/test/ui/sanitize/address.rs (renamed from src/test/ui/sanitizer-address.rs)0
-rw-r--r--src/test/ui/sanitize/cfg.rs (renamed from src/test/ui/sanitize-cfg.rs)0
-rw-r--r--src/test/ui/sanitize/leak.rs (renamed from src/test/ui/sanitizer-leak.rs)0
-rw-r--r--src/test/ui/sanitize/memory.rs (renamed from src/test/ui/sanitizer-memory.rs)0
-rw-r--r--src/test/ui/sanitize/unsupported-target.rs (renamed from src/test/ui/sanitizer-unsupported-target.rs)0
-rw-r--r--src/test/ui/sanitize/unsupported-target.stderr (renamed from src/test/ui/sanitizer-unsupported-target.stderr)0
-rw-r--r--src/test/ui/sanitize/use-after-scope.rs18
10 files changed, 105 insertions, 5 deletions
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index cbb90bd3bb3..64bff2a6fe0 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -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
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 357b0b6c451..c59b81eb4cc 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -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;
@@ -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;
         }
 
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index eaa845a279f..fad70369807 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -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) {
diff --git a/src/test/ui/sanitizer-address.rs b/src/test/ui/sanitize/address.rs
index d27a30a2dc5..d27a30a2dc5 100644
--- a/src/test/ui/sanitizer-address.rs
+++ b/src/test/ui/sanitize/address.rs
diff --git a/src/test/ui/sanitize-cfg.rs b/src/test/ui/sanitize/cfg.rs
index 9c198543a86..9c198543a86 100644
--- a/src/test/ui/sanitize-cfg.rs
+++ b/src/test/ui/sanitize/cfg.rs
diff --git a/src/test/ui/sanitizer-leak.rs b/src/test/ui/sanitize/leak.rs
index 5c2f2cb4e86..5c2f2cb4e86 100644
--- a/src/test/ui/sanitizer-leak.rs
+++ b/src/test/ui/sanitize/leak.rs
diff --git a/src/test/ui/sanitizer-memory.rs b/src/test/ui/sanitize/memory.rs
index 3e1cf4509a3..3e1cf4509a3 100644
--- a/src/test/ui/sanitizer-memory.rs
+++ b/src/test/ui/sanitize/memory.rs
diff --git a/src/test/ui/sanitizer-unsupported-target.rs b/src/test/ui/sanitize/unsupported-target.rs
index 444333c3f01..444333c3f01 100644
--- a/src/test/ui/sanitizer-unsupported-target.rs
+++ b/src/test/ui/sanitize/unsupported-target.rs
diff --git a/src/test/ui/sanitizer-unsupported-target.stderr b/src/test/ui/sanitize/unsupported-target.stderr
index 38be58dd4b3..38be58dd4b3 100644
--- a/src/test/ui/sanitizer-unsupported-target.stderr
+++ b/src/test/ui/sanitize/unsupported-target.stderr
diff --git a/src/test/ui/sanitize/use-after-scope.rs b/src/test/ui/sanitize/use-after-scope.rs
new file mode 100644
index 00000000000..6a2067e157a
--- /dev/null
+++ b/src/test/ui/sanitize/use-after-scope.rs
@@ -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);
+    }
+}