Skip to content

Commit 2652ce6

Browse files
committed
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,
2 parents 028569a + 0af5c00 commit 2652ce6

File tree

14 files changed

+205
-23
lines changed

14 files changed

+205
-23
lines changed

src/librustc_metadata/creader.rs

+43-14
Original file line numberDiff line numberDiff line change
@@ -856,21 +856,48 @@ impl<'a> CrateLoader<'a> {
856856
return
857857
}
858858

859-
if !self.sess.crate_types.borrow().iter().all(|ct| {
860-
match *ct {
861-
// Link the runtime
862-
config::CrateTypeExecutable => true,
863-
// This crate will be compiled with the required
864-
// instrumentation pass
865-
config::CrateTypeRlib => false,
866-
_ => {
867-
self.sess.err(&format!("Only executables and rlibs can be \
868-
compiled with `-Z sanitizer`"));
869-
false
859+
// firstyear 2017 - during testing I was unable to access an OSX machine
860+
// to make this work on different crate types. As a result, today I have
861+
// only been able to test and support linux as a target.
862+
if self.sess.target.target.llvm_target == "x86_64-unknown-linux-gnu" {
863+
if !self.sess.crate_types.borrow().iter().all(|ct| {
864+
match *ct {
865+
// Link the runtime
866+
config::CrateTypeStaticlib |
867+
config::CrateTypeExecutable => true,
868+
// This crate will be compiled with the required
869+
// instrumentation pass
870+
config::CrateTypeRlib |
871+
config::CrateTypeDylib |
872+
config::CrateTypeCdylib =>
873+
false,
874+
_ => {
875+
self.sess.err(&format!("Only executables, staticlibs, \
876+
cdylibs, dylibs and rlibs can be compiled with \
877+
`-Z sanitizer`"));
878+
false
879+
}
870880
}
881+
}) {
882+
return
883+
}
884+
} else {
885+
if !self.sess.crate_types.borrow().iter().all(|ct| {
886+
match *ct {
887+
// Link the runtime
888+
config::CrateTypeExecutable => true,
889+
// This crate will be compiled with the required
890+
// instrumentation pass
891+
config::CrateTypeRlib => false,
892+
_ => {
893+
self.sess.err(&format!("Only executables and rlibs can be \
894+
compiled with `-Z sanitizer`"));
895+
false
896+
}
897+
}
898+
}) {
899+
return
871900
}
872-
}) {
873-
return
874901
}
875902

876903
let mut uses_std = false;
@@ -890,7 +917,7 @@ impl<'a> CrateLoader<'a> {
890917
info!("loading sanitizer: {}", name);
891918

892919
let symbol = Symbol::intern(name);
893-
let dep_kind = DepKind::Implicit;
920+
let dep_kind = DepKind::Explicit;
894921
let (_, data) =
895922
self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP,
896923
PathKind::Crate, dep_kind);
@@ -900,6 +927,8 @@ impl<'a> CrateLoader<'a> {
900927
self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
901928
name));
902929
}
930+
} else {
931+
self.sess.err(&format!("Must link std to be compiled with `-Z sanitizer`"));
903932
}
904933
}
905934
}

src/test/run-make/sanitizer-address/overflow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010

1111
fn main() {
1212
let xs = [0, 1, 2, 3];
13-
let y = unsafe { *xs.as_ptr().offset(4) };
13+
let _y = unsafe { *xs.as_ptr().offset(4) };
1414
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-include ../tools.mk
2+
3+
# This test builds a shared object, then an executable that links it as a native
4+
# rust library (constrast to an rlib). The shared library and executable both
5+
# are compiled with address sanitizer, and we assert that a fault in the cdylib
6+
# is correctly detected.
7+
8+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
9+
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
10+
EXTRA_RUSTFLAG=
11+
endif
12+
13+
all:
14+
ifeq ($(ASAN_SUPPORT),1)
15+
$(RUSTC) -g -Z sanitizer=address --crate-type cdylib --target $(TARGET) library.rs
16+
$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -llibrary program.rs
17+
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
18+
endif
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[no_mangle]
12+
pub extern fn overflow() {
13+
let xs = [0, 1, 2, 3];
14+
let _y = unsafe { *xs.as_ptr().offset(4) };
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern {
12+
fn overflow();
13+
}
14+
15+
fn main() {
16+
unsafe { overflow() }
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-include ../tools.mk
2+
3+
# This test builds a shared object, then an executable that links it as a native
4+
# rust library (constrast to an rlib). The shared library and executable both
5+
# are compiled with address sanitizer, and we assert that a fault in the dylib
6+
# is correctly detected.
7+
8+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
9+
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
10+
EXTRA_RUSTFLAG=
11+
endif
12+
13+
all:
14+
ifeq ($(ASAN_SUPPORT),1)
15+
$(RUSTC) -g -Z sanitizer=address --crate-type dylib --target $(TARGET) library.rs
16+
$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -llibrary program.rs
17+
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
18+
endif
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[no_mangle]
12+
pub extern fn overflow() {
13+
let xs = [0, 1, 2, 3];
14+
let _y = unsafe { *xs.as_ptr().offset(4) };
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern {
12+
fn overflow();
13+
}
14+
15+
fn main() {
16+
unsafe { overflow() }
17+
}

src/test/run-make/sanitizer-dylib/Makefile

-8
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-include ../tools.mk
2+
3+
# NOTE the address sanitizer only supports x86_64 linux and macOS
4+
5+
ifeq ($(TARGET),x86_64-apple-darwin)
6+
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
7+
EXTRA_RUSTFLAG=-C rpath
8+
else
9+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
10+
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
11+
EXTRA_RUSTFLAG=
12+
endif
13+
endif
14+
15+
all:
16+
ifeq ($(ASAN_SUPPORT),1)
17+
$(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | grep -q -- '-Z sanitizer'
18+
endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-include ../tools.mk
2+
3+
# This test builds a staticlib, then an executable that links to it.
4+
# The staticlib and executable both are compiled with address sanitizer,
5+
# and we assert that a fault in the staticlib is correctly detected.
6+
7+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
8+
ASAN_SUPPORT=$(SANITIZER_SUPPORT)
9+
EXTRA_RUSTFLAG=
10+
endif
11+
12+
all:
13+
ifeq ($(ASAN_SUPPORT),1)
14+
$(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs
15+
$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
16+
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | grep -q stack-buffer-overflow
17+
endif
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[no_mangle]
12+
pub extern fn overflow() {
13+
let xs = [0, 1, 2, 3];
14+
let _y = unsafe { *xs.as_ptr().offset(4) };
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// ignore-license
2+
void overflow();
3+
4+
int main() {
5+
overflow();
6+
return 0;
7+
}
8+

0 commit comments

Comments
 (0)