about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-07-17 17:02:18 +0000
committerbors <bors@rust-lang.org>2017-07-17 17:02:18 +0000
commit2652ce6771b114189cdc1f9bd026a10af0a714e0 (patch)
tree88279d8bbad4f84310d3421b2a1a9aa2e4e7533d /src
parent028569ab1b339bcc00814e1c7fb71a5cea5ccb0f (diff)
parent0af5c002a25688e826f5821b495e415f6f941bb4 (diff)
Auto merge of #42711 - Firstyear:san-on-dylib, r=alexcrichton
Add support for dylibs with Address Sanitizer

Many applications use address sanitizer to assert correct behaviour of their programs. When using Rust with C, it's much more important to assert correct programs with tools like asan/lsan due to the unsafe nature of the access across an ffi boundary. However, previously only rust bin types could use asan. This posed a challenge for existing C applications that link or dlopen .so when the C application is compiled with asan.

This PR enables asan to be linked to the dylib and cdylib crate type. We alter the test to check the proc-macro crate does not work with -Z sanitizer=address. Finally, we add a test that compiles a shared object in rust, then another rust program links it and demonstrates a crash through the call to the library.

This PR is nearly complete, but I do require advice on the change to fix the -lasan that currently exists in the dylib test. This is required because the link statement is not being added correctly to the rustc build when -Z sanitizer=address is added (and I'm not 100% sure why)

Thanks,
Diffstat (limited to 'src')
-rw-r--r--src/librustc_metadata/creader.rs57
-rw-r--r--src/test/run-make/sanitizer-address/overflow.rs2
-rw-r--r--src/test/run-make/sanitizer-cdylib-link/Makefile19
-rw-r--r--src/test/run-make/sanitizer-cdylib-link/library.rs15
-rw-r--r--src/test/run-make/sanitizer-cdylib-link/program.rs17
-rw-r--r--src/test/run-make/sanitizer-dylib-link/Makefile19
-rw-r--r--src/test/run-make/sanitizer-dylib-link/library.rs15
-rw-r--r--src/test/run-make/sanitizer-dylib-link/program.rs17
-rw-r--r--src/test/run-make/sanitizer-dylib/Makefile8
-rw-r--r--src/test/run-make/sanitizer-invalid-cratetype/Makefile18
-rw-r--r--src/test/run-make/sanitizer-invalid-cratetype/hello.rs (renamed from src/test/run-make/sanitizer-dylib/hello.rs)0
-rw-r--r--src/test/run-make/sanitizer-staticlib-link/Makefile18
-rw-r--r--src/test/run-make/sanitizer-staticlib-link/library.rs15
-rw-r--r--src/test/run-make/sanitizer-staticlib-link/program.c8
14 files changed, 205 insertions, 23 deletions
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index ac39da48ac1..d15843b4f31 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -856,21 +856,48 @@ impl<'a> CrateLoader<'a> {
                 return
             }
 
-            if !self.sess.crate_types.borrow().iter().all(|ct| {
-                match *ct {
-                    // Link the runtime
-                    config::CrateTypeExecutable => true,
-                    // This crate will be compiled with the required
-                    // instrumentation pass
-                    config::CrateTypeRlib => false,
-                    _ => {
-                        self.sess.err(&format!("Only executables and rlibs can be \
-                                                compiled with `-Z sanitizer`"));
-                        false
+            // firstyear 2017 - during testing I was unable to access an OSX machine
+            // to make this work on different crate types. As a result, today I have
+            // only been able to test and support linux as a target.
+            if self.sess.target.target.llvm_target == "x86_64-unknown-linux-gnu" {
+                if !self.sess.crate_types.borrow().iter().all(|ct| {
+                    match *ct {
+                        // Link the runtime
+                        config::CrateTypeStaticlib |
+                        config::CrateTypeExecutable => true,
+                        // This crate will be compiled with the required
+                        // instrumentation pass
+                        config::CrateTypeRlib |
+                        config::CrateTypeDylib |
+                        config::CrateTypeCdylib =>
+                            false,
+                        _ => {
+                            self.sess.err(&format!("Only executables, staticlibs, \
+                                cdylibs, dylibs and rlibs can be compiled with \
+                                `-Z sanitizer`"));
+                            false
+                        }
                     }
+                }) {
+                    return
+                }
+            } else {
+                if !self.sess.crate_types.borrow().iter().all(|ct| {
+                    match *ct {
+                        // Link the runtime
+                        config::CrateTypeExecutable => true,
+                        // This crate will be compiled with the required
+                        // instrumentation pass
+                        config::CrateTypeRlib => false,
+                        _ => {
+                            self.sess.err(&format!("Only executables and rlibs can be \
+                                                    compiled with `-Z sanitizer`"));
+                            false
+                        }
+                    }
+                }) {
+                    return
                 }
-            }) {
-                return
             }
 
             let mut uses_std = false;
@@ -890,7 +917,7 @@ impl<'a> CrateLoader<'a> {
                 info!("loading sanitizer: {}", name);
 
                 let symbol = Symbol::intern(name);
-                let dep_kind = DepKind::Implicit;
+                let dep_kind = DepKind::Explicit;
                 let (_, data) =
                     self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP,
                                        PathKind::Crate, dep_kind);
@@ -900,6 +927,8 @@ impl<'a> CrateLoader<'a> {
                     self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
                                            name));
                 }
+            } else {
+                self.sess.err(&format!("Must link std to be compiled with `-Z sanitizer`"));
             }
         }
     }
diff --git a/src/test/run-make/sanitizer-address/overflow.rs b/src/test/run-make/sanitizer-address/overflow.rs
index e35c3873f7e..1f3c64c8c32 100644
--- a/src/test/run-make/sanitizer-address/overflow.rs
+++ b/src/test/run-make/sanitizer-address/overflow.rs
@@ -10,5 +10,5 @@
 
 fn main() {
     let xs = [0, 1, 2, 3];
-    let y = unsafe { *xs.as_ptr().offset(4) };
+    let _y = unsafe { *xs.as_ptr().offset(4) };
 }
diff --git a/src/test/run-make/sanitizer-cdylib-link/Makefile b/src/test/run-make/sanitizer-cdylib-link/Makefile
new file mode 100644
index 00000000000..9b0470fb277
--- /dev/null
+++ b/src/test/run-make/sanitizer-cdylib-link/Makefile
@@ -0,0 +1,19 @@
+-include ../tools.mk
+
+# This test builds a shared object, then an executable that links it as a native
+# rust library (constrast to an rlib). The shared library and executable both
+# are compiled with address sanitizer, and we assert that a fault in the cdylib
+# is correctly detected.
+
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+ASAN_SUPPORT=$(SANITIZER_SUPPORT)
+EXTRA_RUSTFLAG=
+endif
+
+all:
+ifeq ($(ASAN_SUPPORT),1)
+	$(RUSTC) -g -Z sanitizer=address --crate-type cdylib --target $(TARGET) library.rs
+	$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -llibrary program.rs
+	LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
+endif
+
diff --git a/src/test/run-make/sanitizer-cdylib-link/library.rs b/src/test/run-make/sanitizer-cdylib-link/library.rs
new file mode 100644
index 00000000000..4ceef5d3f52
--- /dev/null
+++ b/src/test/run-make/sanitizer-cdylib-link/library.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_mangle]
+pub extern fn overflow() {
+    let xs = [0, 1, 2, 3];
+    let _y = unsafe { *xs.as_ptr().offset(4) };
+}
diff --git a/src/test/run-make/sanitizer-cdylib-link/program.rs b/src/test/run-make/sanitizer-cdylib-link/program.rs
new file mode 100644
index 00000000000..9f52817c851
--- /dev/null
+++ b/src/test/run-make/sanitizer-cdylib-link/program.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern {
+    fn overflow();
+}
+
+fn main() {
+    unsafe { overflow() }
+}
diff --git a/src/test/run-make/sanitizer-dylib-link/Makefile b/src/test/run-make/sanitizer-dylib-link/Makefile
new file mode 100644
index 00000000000..d75241f0971
--- /dev/null
+++ b/src/test/run-make/sanitizer-dylib-link/Makefile
@@ -0,0 +1,19 @@
+-include ../tools.mk
+
+# This test builds a shared object, then an executable that links it as a native
+# rust library (constrast to an rlib). The shared library and executable both
+# are compiled with address sanitizer, and we assert that a fault in the dylib
+# is correctly detected.
+
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+ASAN_SUPPORT=$(SANITIZER_SUPPORT)
+EXTRA_RUSTFLAG=
+endif
+
+all:
+ifeq ($(ASAN_SUPPORT),1)
+	$(RUSTC) -g -Z sanitizer=address --crate-type dylib --target $(TARGET) library.rs
+	$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -llibrary program.rs
+	LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
+endif
+
diff --git a/src/test/run-make/sanitizer-dylib-link/library.rs b/src/test/run-make/sanitizer-dylib-link/library.rs
new file mode 100644
index 00000000000..4ceef5d3f52
--- /dev/null
+++ b/src/test/run-make/sanitizer-dylib-link/library.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_mangle]
+pub extern fn overflow() {
+    let xs = [0, 1, 2, 3];
+    let _y = unsafe { *xs.as_ptr().offset(4) };
+}
diff --git a/src/test/run-make/sanitizer-dylib-link/program.rs b/src/test/run-make/sanitizer-dylib-link/program.rs
new file mode 100644
index 00000000000..9f52817c851
--- /dev/null
+++ b/src/test/run-make/sanitizer-dylib-link/program.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern {
+    fn overflow();
+}
+
+fn main() {
+    unsafe { overflow() }
+}
diff --git a/src/test/run-make/sanitizer-dylib/Makefile b/src/test/run-make/sanitizer-dylib/Makefile
deleted file mode 100644
index 835d5b0d9d8..00000000000
--- a/src/test/run-make/sanitizer-dylib/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
--include ../tools.mk
-
-ifeq ($(TARGET),x86_64-unknown-linux-gnu)
-all:
-	$(RUSTC) -Z sanitizer=leak --crate-type dylib --target $(TARGET) hello.rs 2>&1 | grep -q 'Only executables and rlibs can be compiled with `-Z sanitizer`'
-else
-all:
-endif
diff --git a/src/test/run-make/sanitizer-invalid-cratetype/Makefile b/src/test/run-make/sanitizer-invalid-cratetype/Makefile
new file mode 100644
index 00000000000..d03bbf84c1d
--- /dev/null
+++ b/src/test/run-make/sanitizer-invalid-cratetype/Makefile
@@ -0,0 +1,18 @@
+-include ../tools.mk
+
+# NOTE the address sanitizer only supports x86_64 linux and macOS
+
+ifeq ($(TARGET),x86_64-apple-darwin)
+ASAN_SUPPORT=$(SANITIZER_SUPPORT)
+EXTRA_RUSTFLAG=-C rpath
+else
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+ASAN_SUPPORT=$(SANITIZER_SUPPORT)
+EXTRA_RUSTFLAG=
+endif
+endif
+
+all:
+ifeq ($(ASAN_SUPPORT),1)
+	$(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | grep -q -- '-Z sanitizer'
+endif
diff --git a/src/test/run-make/sanitizer-dylib/hello.rs b/src/test/run-make/sanitizer-invalid-cratetype/hello.rs
index 41782851a1a..41782851a1a 100644
--- a/src/test/run-make/sanitizer-dylib/hello.rs
+++ b/src/test/run-make/sanitizer-invalid-cratetype/hello.rs
diff --git a/src/test/run-make/sanitizer-staticlib-link/Makefile b/src/test/run-make/sanitizer-staticlib-link/Makefile
new file mode 100644
index 00000000000..f92dc52b445
--- /dev/null
+++ b/src/test/run-make/sanitizer-staticlib-link/Makefile
@@ -0,0 +1,18 @@
+-include ../tools.mk
+
+# This test builds a staticlib, then an executable that links to it.
+# The staticlib and executable both  are compiled with address sanitizer, 
+# and we assert that a fault in the staticlib is correctly detected.
+
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+ASAN_SUPPORT=$(SANITIZER_SUPPORT)
+EXTRA_RUSTFLAG=
+endif
+
+all:
+ifeq ($(ASAN_SUPPORT),1)
+	$(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs
+	$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
+	LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
+endif
+
diff --git a/src/test/run-make/sanitizer-staticlib-link/library.rs b/src/test/run-make/sanitizer-staticlib-link/library.rs
new file mode 100644
index 00000000000..4ceef5d3f52
--- /dev/null
+++ b/src/test/run-make/sanitizer-staticlib-link/library.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_mangle]
+pub extern fn overflow() {
+    let xs = [0, 1, 2, 3];
+    let _y = unsafe { *xs.as_ptr().offset(4) };
+}
diff --git a/src/test/run-make/sanitizer-staticlib-link/program.c b/src/test/run-make/sanitizer-staticlib-link/program.c
new file mode 100644
index 00000000000..abd5d508e72
--- /dev/null
+++ b/src/test/run-make/sanitizer-staticlib-link/program.c
@@ -0,0 +1,8 @@
+// ignore-license
+void overflow();
+
+int main() {
+    overflow();
+    return 0;
+}
+