From 0af5c002a25688e826f5821b495e415f6f941bb4 Mon Sep 17 00:00:00 2001 From: William Brown Date: Sat, 17 Jun 2017 13:42:56 +1000 Subject: [PATCH] Add support for dylibs with Address Sanitizer. This supports cdylibs and staticlibs on gnu-linux targets. --- src/librustc_metadata/creader.rs | 57 ++++++++++++++----- .../run-make/sanitizer-address/overflow.rs | 2 +- .../run-make/sanitizer-cdylib-link/Makefile | 19 +++++++ .../run-make/sanitizer-cdylib-link/library.rs | 15 +++++ .../run-make/sanitizer-cdylib-link/program.rs | 17 ++++++ .../run-make/sanitizer-dylib-link/Makefile | 19 +++++++ .../run-make/sanitizer-dylib-link/library.rs | 15 +++++ .../run-make/sanitizer-dylib-link/program.rs | 17 ++++++ src/test/run-make/sanitizer-dylib/Makefile | 8 --- .../sanitizer-invalid-cratetype/Makefile | 18 ++++++ .../hello.rs | 0 .../sanitizer-staticlib-link/Makefile | 18 ++++++ .../sanitizer-staticlib-link/library.rs | 15 +++++ .../sanitizer-staticlib-link/program.c | 8 +++ 14 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 src/test/run-make/sanitizer-cdylib-link/Makefile create mode 100644 src/test/run-make/sanitizer-cdylib-link/library.rs create mode 100644 src/test/run-make/sanitizer-cdylib-link/program.rs create mode 100644 src/test/run-make/sanitizer-dylib-link/Makefile create mode 100644 src/test/run-make/sanitizer-dylib-link/library.rs create mode 100644 src/test/run-make/sanitizer-dylib-link/program.rs delete mode 100644 src/test/run-make/sanitizer-dylib/Makefile create mode 100644 src/test/run-make/sanitizer-invalid-cratetype/Makefile rename src/test/run-make/{sanitizer-dylib => sanitizer-invalid-cratetype}/hello.rs (100%) create mode 100644 src/test/run-make/sanitizer-staticlib-link/Makefile create mode 100644 src/test/run-make/sanitizer-staticlib-link/library.rs create mode 100644 src/test/run-make/sanitizer-staticlib-link/program.c diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index ac39da48ac1fc..d15843b4f318b 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 e35c3873f7eb5..1f3c64c8c322d 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 0000000000000..9b0470fb277a9 --- /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 0000000000000..4ceef5d3f5272 --- /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 or the MIT license +// , 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 0000000000000..9f52817c85100 --- /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 or the MIT license +// , 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 0000000000000..d75241f09710a --- /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 0000000000000..4ceef5d3f5272 --- /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 or the MIT license +// , 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 0000000000000..9f52817c85100 --- /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 or the MIT license +// , 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 835d5b0d9d8cd..0000000000000 --- 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 0000000000000..d03bbf84c1d11 --- /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 similarity index 100% rename from src/test/run-make/sanitizer-dylib/hello.rs rename to 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 0000000000000..f92dc52b44575 --- /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 0000000000000..4ceef5d3f5272 --- /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 or the MIT license +// , 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 0000000000000..abd5d508e7295 --- /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; +} +