Skip to content

Commit

Permalink
MSVC: Add support for linking against the "spectre-mitigated" CRT
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dpaoliello committed Apr 12, 2022
1 parent fba7fed commit 3553066
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
26 changes: 23 additions & 3 deletions cc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ fn main() {
cc::Build::new().file("src/windows.c").compile("windows");
}

// Test that the `windows_registry` module will set PATH by looking for
// nmake which runs vanilla cl, and then also test it after we remove all
// the relevant env vars from our own process.
if target.contains("msvc") {
// Test that the `windows_registry` module will set PATH by looking for
// nmake which runs vanilla cl, and then also test it after we remove all
// the relevant env vars from our own process.
let out = out.join("tmp");
fs::create_dir(&out).unwrap();
println!("nmake 1");
Expand Down Expand Up @@ -91,6 +91,26 @@ fn main() {
assert!(status.success());
println!("cargo:rustc-link-lib=msvc");
println!("cargo:rustc-link-search={}", out.display());

// Test that the `windows_registry` module detects if we're in a "spectre
// mode" VS environment.
fn has_spectre(target: &str) -> bool {
cc::windows_registry::find_tool(target, "cl.exe").unwrap().env().iter().any(|(k, v)| {
(k == "LIB") && v.to_str().map_or(false, |s| s.contains(r"\lib\spectre\"))
})
}

std::env::set_var("VSCMD_ARG_VCVARS_SPECTRE", "spectre");
assert!(
has_spectre(&target),
"LIB should use spectre-mitigated libs when VSCMD_ARG_VCVARS_SPECTRE is set"
);

std::env::remove_var("VSCMD_ARG_VCVARS_SPECTRE");
assert!(
!has_spectre(&target),
"LIB should not use spectre-mitigated libs when VSCMD_ARG_VCVARS_SPECTRE is not set"
);
}

// This tests whether we can build a library but not link it to the main
Expand Down
12 changes: 11 additions & 1 deletion src/windows_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,11 +488,21 @@ mod impl_ {
.join("bin")
.join(&format!("Host{}", host))
.join(&host.to_lowercase());
let lib_path = path.join("lib").join(&target);
let lib_path = path
.join(if use_spectre_mitigated_libs() {
r"lib\spectre"
} else {
"lib"
})
.join(&target);
let include_path = path.join("include");
Some((bin_path, host_dylib_path, lib_path, include_path))
}

fn use_spectre_mitigated_libs() -> bool {
env::var("VSCMD_ARG_VCVARS_SPECTRE").map_or(false, |var| var == "spectre")
}

fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> {
let atl_path = path.join("atlmfc");
let sub = lib_subdir(target)?;
Expand Down

0 comments on commit 3553066

Please sign in to comment.