Skip to content

Commit 0c285fb

Browse files
committed
expand osx sanitizer support (lsan, dylib, cdylib, staticlib)
1 parent 2b78e10 commit 0c285fb

File tree

17 files changed

+120
-122
lines changed

17 files changed

+120
-122
lines changed

src/bootstrap/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ fn copy_apple_sanitizer_dylibs(
285285
platform: &str,
286286
into: &Path,
287287
) {
288-
for &sanitizer in &["asan", "tsan"] {
288+
for &sanitizer in &["asan", "lsan", "tsan"] {
289289
let filename = format!("lib__rustc__clang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
290290
let mut src_path = native_dir.join(sanitizer);
291291
src_path.push("build");

src/librustc/middle/dependency_format.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList {
210210
// quite yet, so do so here.
211211
activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret,
212212
&|cnum| tcx.is_panic_runtime(cnum));
213+
activate_injected_dep(*sess.injected_sanitizer_runtime.get(), &mut ret,
214+
&|cnum| tcx.is_sanitizer_runtime(cnum));
213215

214216
// When dylib B links to dylib A, then when using B we must also link to A.
215217
// It could be the case, however, that the rlib for A is present (hence we
@@ -285,11 +287,13 @@ fn attempt_static(tcx: TyCtxt<'_>) -> Option<DependencyList> {
285287
}
286288
}).collect::<Vec<_>>();
287289

288-
// Our allocator/panic runtime may not have been linked above if it wasn't
289-
// explicitly linked, which is the case for any injected dependency. Handle
290-
// that here and activate them.
290+
// Our allocator/panic/sanitizer runtime may not have been linked above if
291+
// it wasn't explicitly linked, which is the case for any injected
292+
// dependency. Handle that here and activate them.
291293
activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret,
292294
&|cnum| tcx.is_panic_runtime(cnum));
295+
activate_injected_dep(*sess.injected_sanitizer_runtime.get(), &mut ret,
296+
&|cnum| tcx.is_sanitizer_runtime(cnum));
293297

294298
Some(ret)
295299
}

src/librustc/session/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,12 @@ pub struct Session {
111111
/// The maximum number of stackframes allowed in const eval.
112112
pub const_eval_stack_frame_limit: usize,
113113

114-
/// The metadata::creader module may inject an allocator/panic_runtime
115-
/// dependency if it didn't already find one, and this tracks what was
116-
/// injected.
114+
/// The metadata::creader module may inject an allocator/panic_runtime/
115+
/// sanitizer dependency if it didn't already find one, and this tracks what
116+
/// was injected.
117117
pub allocator_kind: Once<Option<AllocatorKind>>,
118118
pub injected_panic_runtime: Once<Option<CrateNum>>,
119+
pub injected_sanitizer_runtime: Once<Option<CrateNum>>,
119120

120121
/// Map from imported macro spans (which consist of
121122
/// the localized span for the macro body) to the
@@ -1249,6 +1250,7 @@ fn build_session_(
12491250
next_node_id: OneThread::new(Cell::new(NodeId::from_u32(1))),
12501251
allocator_kind: Once::new(),
12511252
injected_panic_runtime: Once::new(),
1253+
injected_sanitizer_runtime: Once::new(),
12521254
imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
12531255
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
12541256
cgu_reuse_tracker,

src/librustc_lsan/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ fn main() {
2020
.out_dir(&native.out_dir)
2121
.build_target(&target)
2222
.build();
23+
native.fixup_sanitizer_lib_name("lsan");
2324
}
2425
println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
2526
}

src/librustc_metadata/creader.rs

Lines changed: 65 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -762,105 +762,78 @@ impl<'a> CrateLoader<'a> {
762762
}
763763

764764
fn inject_sanitizer_runtime(&mut self) {
765-
if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer {
766-
// Sanitizers can only be used on some tested platforms with
767-
// executables linked to `std`
768-
const ASAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu",
769-
"x86_64-apple-darwin"];
770-
const TSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu",
771-
"x86_64-apple-darwin"];
772-
const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
773-
const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
774-
775-
let supported_targets = match *sanitizer {
776-
Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
777-
Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
778-
Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
779-
Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
780-
};
781-
if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) {
782-
self.sess.err(&format!("{:?}Sanitizer only works with the `{}` target",
783-
sanitizer,
784-
supported_targets.join("` or `")
785-
));
765+
// Sanitizers can only be used on some tested platforms with
766+
// executables linked to `std`
767+
const ASAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu",
768+
"x86_64-apple-darwin"];
769+
const TSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu",
770+
"x86_64-apple-darwin"];
771+
const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu",
772+
"x86_64-apple-darwin"];
773+
const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
774+
775+
let sanitizer = match self.sess.opts.debugging_opts.sanitizer {
776+
Some(ref sanitizer) => sanitizer,
777+
None => {
778+
self.sess.injected_sanitizer_runtime.set(None);
786779
return
787780
}
781+
};
788782

789-
// firstyear 2017 - during testing I was unable to access an OSX machine
790-
// to make this work on different crate types. As a result, today I have
791-
// only been able to test and support linux as a target.
792-
if self.sess.opts.target_triple.triple() == "x86_64-unknown-linux-gnu" {
793-
if !self.sess.crate_types.borrow().iter().all(|ct| {
794-
match *ct {
795-
// Link the runtime
796-
config::CrateType::Staticlib |
797-
config::CrateType::Executable => true,
798-
// This crate will be compiled with the required
799-
// instrumentation pass
800-
config::CrateType::Rlib |
801-
config::CrateType::Dylib |
802-
config::CrateType::Cdylib =>
803-
false,
804-
_ => {
805-
self.sess.err(&format!("Only executables, staticlibs, \
806-
cdylibs, dylibs and rlibs can be compiled with \
807-
`-Z sanitizer`"));
808-
false
809-
}
810-
}
811-
}) {
812-
return
813-
}
814-
} else {
815-
if !self.sess.crate_types.borrow().iter().all(|ct| {
816-
match *ct {
817-
// Link the runtime
818-
config::CrateType::Executable => true,
819-
// This crate will be compiled with the required
820-
// instrumentation pass
821-
config::CrateType::Rlib => false,
822-
_ => {
823-
self.sess.err(&format!("Only executables and rlibs can be \
824-
compiled with `-Z sanitizer`"));
825-
false
826-
}
827-
}
828-
}) {
829-
return
830-
}
783+
let supported_targets = match *sanitizer {
784+
Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
785+
Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
786+
Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
787+
Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
788+
};
789+
if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) {
790+
self.sess.err(&format!("{:?}Sanitizer only works with the `{}` target",
791+
sanitizer,
792+
supported_targets.join("` or `")
793+
));
794+
return
795+
}
796+
797+
let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
798+
*ct != config::CrateType::Rlib
799+
});
800+
if !any_non_rlib {
801+
info!("sanitizer runtime injection skipped, only generating rlib");
802+
self.sess.injected_sanitizer_runtime.set(None);
803+
return
804+
}
805+
806+
let mut uses_std = false;
807+
self.cstore.iter_crate_data(|_, data| {
808+
if data.name == sym::std {
809+
uses_std = true;
831810
}
811+
});
832812

833-
let mut uses_std = false;
834-
self.cstore.iter_crate_data(|_, data| {
835-
if data.name == sym::std {
836-
uses_std = true;
837-
}
838-
});
813+
if uses_std {
814+
let name = match *sanitizer {
815+
Sanitizer::Address => "rustc_asan",
816+
Sanitizer::Leak => "rustc_lsan",
817+
Sanitizer::Memory => "rustc_msan",
818+
Sanitizer::Thread => "rustc_tsan",
819+
};
820+
info!("loading sanitizer: {}", name);
839821

840-
if uses_std {
841-
let name = match *sanitizer {
842-
Sanitizer::Address => "rustc_asan",
843-
Sanitizer::Leak => "rustc_lsan",
844-
Sanitizer::Memory => "rustc_msan",
845-
Sanitizer::Thread => "rustc_tsan",
846-
};
847-
info!("loading sanitizer: {}", name);
848-
849-
let symbol = Symbol::intern(name);
850-
let dep_kind = DepKind::Explicit;
851-
let (_, data) =
852-
self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP,
853-
PathKind::Crate, dep_kind)
854-
.unwrap_or_else(|err| err.report());
855-
856-
// Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
857-
if !data.root.sanitizer_runtime {
858-
self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
859-
name));
860-
}
861-
} else {
862-
self.sess.err("Must link std to be compiled with `-Z sanitizer`");
822+
let symbol = Symbol::intern(name);
823+
let dep_kind = DepKind::Implicit;
824+
let (cnum, data) =
825+
self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP,
826+
PathKind::Crate, dep_kind)
827+
.unwrap_or_else(|err| err.report());
828+
829+
// Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
830+
if !data.root.sanitizer_runtime {
831+
self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
832+
name));
863833
}
834+
self.sess.injected_sanitizer_runtime.set(Some(cnum));
835+
} else {
836+
self.sess.err("Must link std to be compiled with `-Z sanitizer`");
864837
}
865838
}
866839

src/libstd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ rand = "0.6.1"
4242

4343
[target.x86_64-apple-darwin.dependencies]
4444
rustc_asan = { path = "../librustc_asan" }
45+
rustc_lsan = { path = "../librustc_lsan" }
4546
rustc_tsan = { path = "../librustc_tsan" }
4647

4748
[target.x86_64-unknown-linux-gnu.dependencies]

src/test/run-make-fulldeps/sanitizer-address/Makefile

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55
LOG := $(TMPDIR)/log.txt
66

77
# NOTE the address sanitizer only supports x86_64 linux and macOS
8-
9-
ifeq ($(TARGET),x86_64-apple-darwin)
10-
EXTRA_RUSTFLAG=-C rpath
11-
else
128
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
13-
149
# Apparently there are very specific Linux kernels, notably the one that's
1510
# currently on Travis CI, which contain a buggy commit that triggers failures in
1611
# the ASan implementation, detailed at google/sanitizers#837. As noted in
@@ -20,7 +15,6 @@ ifeq ($(TARGET),x86_64-unknown-linux-gnu)
2015
# flags again.
2116
EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic
2217
endif
23-
endif
2418

2519
all:
2620
$(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) librustc_asan
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# needs-sanitizer-support
2+
# only-x86_64
3+
-include ../tools.mk
4+
5+
ifeq ($(TARGET),x86_64-apple-darwin)
6+
# sanitizers are always built as dylibs on osx
7+
EXTRACFLAGS=-L$(TARGET_RPATH_DIR) -l__rustc__clang_rt.asan_osx_dynamic
8+
LD_LIBRARY_PATH="$(TARGET_RPATH_DIR):$(TMPDIR)"
9+
else
10+
LD_LIBRARY_PATH=$(TMPDIR)
11+
endif
12+
13+
# This test builds a staticlib, then an executable that links to it.
14+
# The staticlib is compiled with address sanitizer, and we assert that a fault
15+
# in the staticlib is correctly detected.
16+
17+
all:
18+
$(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs
19+
$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
20+
LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[no_mangle]
2+
pub extern fn overflow() {
3+
let xs = [0, 1, 2, 3];
4+
let _y = unsafe { *xs.as_ptr().offset(4) };
5+
}

src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# needs-sanitizer-support
22
# only-x86_64
3-
# only-linux
43

54
-include ../tools.mk
65

@@ -12,7 +11,9 @@ LOG := $(TMPDIR)/log.txt
1211
# is correctly detected.
1312

1413
# See comment in sanitizer-address/Makefile for why this is here
14+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
1515
EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic
16+
endif
1617

1718
all:
1819
$(RUSTC) -g -Z sanitizer=address --crate-type cdylib --target $(TARGET) $(EXTRA_RUSTFLAG) library.rs

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# needs-sanitizer-support
22
# only-x86_64
3-
# only-linux
43

54
-include ../tools.mk
65

@@ -12,7 +11,9 @@ LOG := $(TMPDIR)/log.txt
1211
# is correctly detected.
1312

1413
# See comment in sanitizer-address/Makefile for why this is here
14+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
1515
EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic
16+
endif
1617

1718
all:
1819
$(RUSTC) -g -Z sanitizer=address --crate-type dylib --target $(TARGET) $(EXTRA_RUSTFLAG) library.rs

src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@
33
-include ../tools.mk
44

55
# NOTE the address sanitizer only supports x86_64 linux and macOS
6-
7-
ifeq ($(TARGET),x86_64-apple-darwin)
8-
EXTRA_RUSTFLAG=-C rpath
9-
else
106
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
117
EXTRA_RUSTFLAG=
128
endif
13-
endif
149

1510
all:
1611
$(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | $(CGREP) '-Z sanitizer'

src/test/run-make-fulldeps/sanitizer-invalid-target/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
all:
44
$(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | \
5-
$(CGREP) 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` target'
5+
$(CGREP) 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target'

src/test/run-make-fulldeps/sanitizer-leak/Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
-include ../tools.mk
22

33
# needs-sanitizer-support
4-
# only-linux
54
# only-x86_64
6-
# ignore-test
7-
# FIXME(#46126) ThinLTO for libstd broke this test
85

96
all:
107
$(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) librustc_lsan
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
# needs-sanitizer-support
22
# only-x86_64
3-
# only-linux
4-
53
-include ../tools.mk
64

75
# This test builds a staticlib, then an executable that links to it.
8-
# The staticlib and executable both are compiled with address sanitizer,
9-
# and we assert that a fault in the staticlib is correctly detected.
6+
# The staticlib and executable are compiled with address sanitizer, and we
7+
# assert that a fault in the staticlib is correctly detected.
108

119
all:
1210
$(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs
13-
$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
11+
$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) $(EXTRA_RUSTFLAG) -llibrary program.rs
1412
LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow
15-
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extern {
2+
fn overflow();
3+
}
4+
5+
fn main() {
6+
unsafe { overflow() }
7+
}

0 commit comments

Comments
 (0)