diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 000b2748e4f93..d4c39efef6968 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1194,7 +1194,9 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d let needs_runtime = !sess.target.is_like_android && 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_msvc + } CrateType::Rlib | CrateType::Staticlib => false, }; @@ -1254,6 +1256,10 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { let rpath = path.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); linker.link_dylib(&filename, false, true); + } else if sess.target.is_like_msvc { + // MSVC provides the `/INFERASANLIBS` argument to automatically find the + // compatible ASAN library. + linker.arg("/INFERASANLIBS"); } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index e9648d0d6222c..dd005858aa6d3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1574,7 +1574,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.unstable_opts.sanitizer.is_empty() { + if sess.crt_static(None) + && !sess.opts.unstable_opts.sanitizer.is_empty() + && !sess.target.is_like_msvc + { sess.emit_err(errors::CannotEnableCrtStaticLinux); } diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs index ba80c23196e1d..5abc3017bf80c 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs @@ -1,9 +1,10 @@ -use crate::spec::{base, LinkerFlavor, Lld, Target}; +use crate::spec::{base, LinkerFlavor, Lld, SanitizerSet, Target}; pub fn target() -> Target { let mut base = base::windows_msvc::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); + base.supported_sanitizers = SanitizerSet::ADDRESS; base.add_pre_link_args( LinkerFlavor::Msvc(Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs index 7d6276a0c2d57..3a4da91c2443f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs @@ -1,10 +1,11 @@ -use crate::spec::{base, Target}; +use crate::spec::{base, SanitizerSet, Target}; pub fn target() -> Target { let mut base = base::windows_msvc::opts(); base.cpu = "x86-64".into(); base.plt_by_default = false; base.max_atomic_width = Some(64); + base.supported_sanitizers = SanitizerSet::ADDRESS; Target { llvm_target: "x86_64-pc-windows-msvc".into(), diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 77a4f2c4cb201..04639974d35b5 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1939,6 +1939,30 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } } + // Special setup to enable running with sanitizers enabled on MSVC. + if !builder.config.dry_run() + && matches!(suite, "run-make" | "run-make-fulldeps") + && target.contains("msvc") + && builder.config.sanitizers_enabled(target) + { + // Ingore interception failures: not all dlls in the process will have been built with + // address sanitizer enabled (e.g., ntdll.dll). + cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1"); + // Add the address sanitizer runtime to the PATH. + let asan_runtime_path = + builder.cc.borrow()[&target].path().parent().unwrap().to_path_buf(); + let old_path = cmd + .get_envs() + .find_map(|(k, v)| (k == "PATH").then_some(v)) + .flatten() + .map_or_else(|| env::var_os("PATH").unwrap_or_default(), |v| v.to_owned()); + let new_path = env::join_paths( + env::split_paths(&old_path).chain(std::iter::once(asan_runtime_path)), + ) + .expect("Could not add ASAN runtime path to PATH"); + cmd.env("PATH", new_path); + } + // Some UI tests trigger behavior in rustc where it reads $CARGO and changes behavior if it exists. // To make the tests work that rely on it not being set, make sure it is not set. cmd.env_remove("CARGO");