Skip to content

Allow use of AddressSanitizer on Windows by linking to existing libraries #89369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,9 +1070,12 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
// both executables and dynamic shared objects. Everywhere else the runtimes
// are currently distributed as static liraries which should be linked to
// executables only.
// On Windows there are both static and dynamic runtimes available.
let needs_runtime = match crate_type {
CrateType::Executable => true,
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
sess.target.is_like_osx || sess.target.is_like_windows
}
CrateType::Rlib | CrateType::Staticlib => false,
};

Expand All @@ -1082,23 +1085,28 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d

let sanitizer = sess.opts.debugging_opts.sanitizer;
if sanitizer.contains(SanitizerSet::ADDRESS) {
link_sanitizer_runtime(sess, linker, "asan");
link_sanitizer_runtime(sess, crate_type, linker, "asan");
}
if sanitizer.contains(SanitizerSet::LEAK) {
link_sanitizer_runtime(sess, linker, "lsan");
link_sanitizer_runtime(sess, crate_type, linker, "lsan");
}
if sanitizer.contains(SanitizerSet::MEMORY) {
link_sanitizer_runtime(sess, linker, "msan");
link_sanitizer_runtime(sess, crate_type, linker, "msan");
}
if sanitizer.contains(SanitizerSet::THREAD) {
link_sanitizer_runtime(sess, linker, "tsan");
link_sanitizer_runtime(sess, crate_type, linker, "tsan");
}
if sanitizer.contains(SanitizerSet::HWADDRESS) {
link_sanitizer_runtime(sess, linker, "hwasan");
link_sanitizer_runtime(sess, crate_type, linker, "hwasan");
}
}

fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
fn link_sanitizer_runtime(
sess: &Session,
crate_type: CrateType,
linker: &mut dyn Linker,
name: &str,
) {
fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
let session_tlib =
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
Expand All @@ -1119,7 +1127,26 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
.map(|channel| format!("-{}", channel))
.unwrap_or_default();

if sess.target.is_like_osx {
if sess.target.is_like_windows {
let arch = &sess.target.arch;
if sess.crt_static(Some(crate_type)) {
if crate_type == CrateType::Executable {
linker.link_whole_rlib(&PathBuf::from(format!("clang_rt.{}-{}.lib", name, arch)));
} else {
linker.link_whole_rlib(&PathBuf::from(format!(
"clang_rt.{}_dll_thunk-{}.lib",
name, arch
)));
}
} else {
linker
.link_whole_rlib(&PathBuf::from(format!("clang_rt.{}_dynamic-{}.lib", name, arch)));
linker.link_whole_rlib(&PathBuf::from(format!(
"clang_rt.{}_dynamic_runtime_thunk-{}.lib",
name, arch
)));
}
} else if sess.target.is_like_osx {
// On Apple platforms, the sanitizer is always built as a dylib, and
// LLVM will link to `@rpath/*.dylib`, so we need to specify an
// rpath to the library as well (the rpath should be absolute, see
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1397,7 +1397,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}

// Cannot enable crt-static with sanitizers on Linux
if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
if sess.crt_static(None)
&& !sess.opts.debugging_opts.sanitizer.is_empty()
&& !sess.target.is_like_windows
{
sess.err(
"Sanitizer is incompatible with statically linked libc, \
disable it using `-C target-feature=-crt-static`",
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::spec::Target;
use crate::spec::{SanitizerSet, Target};

pub fn target() -> Target {
let mut base = super::windows_msvc_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.has_elf_tls = true;
base.supported_sanitizers = SanitizerSet::ADDRESS;

Target {
llvm_target: "x86_64-pc-windows-msvc".to_string(),
Expand Down