Skip to content

Commit ca1c595

Browse files
committed
MSVC: Add support for linking against the "spectre-mitigated" CRT
Issue Details: Since VS 2017, MSVC has shipped a set of "spectre-mitigated" CRT static libs: https://devblogs.microsoft.com/cppblog/spectre-mitigations-in-msvc/ Typically these are used by opening a VS Command Prompt in "spectre mode" (https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#vcvarsall-syntax) which then sets the `LIB` environment variable to point to the directory with the spectre-mitigated libs. However, since `cc` builds its own `LIB` environment variable, it uses the non-spectre-mitigated libs even when invoked from a VS Command Prompt in "spectre mode". This causes issues when trying to build a spectre-mitigated binary using Rust, as `rustc` uses `cc` for linking. Fix Details: When `cc` detects that the `VSCMD_ARG_VCVARS_SPECTRE` environment variable is set to `spectre` (either by being run from a VS Command Prompt in "spectre mode", or users may explicitly set this themselves), it will use the spectre-mitigated lib directory when building its `LIB` environment variable.
1 parent 994dc90 commit ca1c595

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

dev-tools/cc-test/build.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@ fn main() {
8383
cc::Build::new().file("src/windows.c").compile("windows");
8484
}
8585

86-
// Test that the `windows_registry` module will set PATH by looking for
87-
// nmake which runs vanilla cl, and then also test it after we remove all
88-
// the relevant env vars from our own process.
8986
if target.contains("msvc") {
9087
let cc_frontend = if compiler.is_like_msvc() {
9188
"MSVC"
@@ -95,6 +92,9 @@ fn main() {
9592
unimplemented!("Unknown compiler that targets msvc but isn't clang-like or msvc-like")
9693
};
9794

95+
// Test that the `windows_registry` module will set PATH by looking for
96+
// nmake which runs vanilla cl, and then also test it after we remove all
97+
// the relevant env vars from our own process.
9898
let out = out.join("tmp");
9999
fs::create_dir(&out).unwrap();
100100
println!("nmake 1");
@@ -130,6 +130,28 @@ fn main() {
130130
assert!(status.success());
131131
println!("cargo:rustc-link-lib=msvc");
132132
println!("cargo:rustc-link-search={}", out.display());
133+
134+
// Test that the `windows_registry` module detects if we're in a "spectre
135+
// mode" VS environment.
136+
fn has_spectre(target: &str) -> bool {
137+
cc::windows_registry::find_tool(target, "cl.exe")
138+
.unwrap()
139+
.env()
140+
.iter()
141+
.any(|(k, v)| (k == "LIB") && v.to_str().unwrap().contains(r"\lib\spectre\"))
142+
}
143+
144+
std::env::set_var("VSCMD_ARG_VCVARS_SPECTRE", "spectre");
145+
assert!(
146+
has_spectre(&target),
147+
"LIB should use spectre-mitigated libs when VSCMD_ARG_VCVARS_SPECTRE is set"
148+
);
149+
150+
std::env::remove_var("VSCMD_ARG_VCVARS_SPECTRE");
151+
assert!(
152+
!has_spectre(&target),
153+
"LIB should not use spectre-mitigated libs when VSCMD_ARG_VCVARS_SPECTRE is not set"
154+
);
133155
}
134156

135157
// This tests whether we can build a library but not link it to the main

src/windows/find_tools.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,13 @@ mod impl_ {
575575
// architecture, because it contains dlls like mspdb140.dll compiled for
576576
// the host architecture.
577577
let host_dylib_path = host_path.join(host.to_lowercase());
578-
let lib_path = path.join("lib").join(target);
579-
let alt_lib_path = (target == "arm64ec").then(|| path.join("lib").join("arm64ec"));
578+
let lib_fragment = if use_spectre_mitigated_libs() {
579+
r"lib\spectre"
580+
} else {
581+
"lib"
582+
};
583+
let lib_path = path.join(lib_fragment).join(target);
584+
let alt_lib_path = (target == "arm64ec").then(|| path.join(lib_fragment).join("arm64ec"));
580585
let include_path = path.join("include");
581586
Some((
582587
path,
@@ -625,6 +630,10 @@ mod impl_ {
625630
Some(version)
626631
}
627632

633+
fn use_spectre_mitigated_libs() -> bool {
634+
env::var("VSCMD_ARG_VCVARS_SPECTRE").as_deref() == Ok("spectre")
635+
}
636+
628637
fn atl_paths(target: TargetArch<'_>, path: &Path) -> Option<(PathBuf, PathBuf)> {
629638
let atl_path = path.join("atlmfc");
630639
let sub = lib_subdir(target)?;

0 commit comments

Comments
 (0)