diff --git a/src/flags.rs b/src/flags.rs index 7da6772bb..eeabb5b5a 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -19,6 +19,7 @@ pub(crate) struct RustcCodegenFlags<'a> { no_redzone: Option, soft_float: Option, dwarf_version: Option, + stack_protector: Option<&'a str>, } impl<'this> RustcCodegenFlags<'this> { @@ -161,6 +162,12 @@ impl<'this> RustcCodegenFlags<'this> { "-Zdwarf-version must have a value", ))?); } + // https://github.com/rust-lang/rust/issues/114903 + // FIXME: Drop the -Z variant and update the doc link once the option is stabilized + "-Zstack-protector" | "-Cstack-protector" => { + self.stack_protector = + Some(flag_ok_or(value, "-Zstack-protector must have a value")?); + } _ => {} } Ok(()) @@ -267,6 +274,23 @@ impl<'this> RustcCodegenFlags<'this> { if let Some(value) = self.dwarf_version { push_if_supported(format!("-gdwarf-{value}").into()); } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fstack-protector + // https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fstack-protector + if let Some(value) = self.stack_protector { + // don't need to propagate stack-protector on MSVC since /GS is already the default + // https://learn.microsoft.com/en-us/cpp/build/reference/gs-buffer-security-check?view=msvc-170 + // + // Do NOT `stack-protector=none` since it weakens security for C code, + // and `-Zstack-protector=basic` is deprecated and will be removed soon. + let cc_flag = match value { + "strong" => Some("-fstack-protector-strong"), + "all" => Some("-fstack-protector-all"), + _ => None, + }; + if let Some(cc_flag) = cc_flag { + push_if_supported(cc_flag.into()); + } + } } // Compiler-exclusive flags @@ -379,6 +403,16 @@ mod tests { check("-L\u{1f}-Clto", &expected); } + #[test] + fn stack_protector() { + let expected = RustcCodegenFlags { + stack_protector: Some("strong"), + ..RustcCodegenFlags::default() + }; + check("-Zstack-protector=strong", &expected); + check("-Cstack-protector=strong", &expected); + } + #[test] fn three_valid_prefixes() { let expected = RustcCodegenFlags { @@ -408,6 +442,7 @@ mod tests { "-Csoft-float=yes", "-Zbranch-protection=bti,pac-ret,leaf", "-Zdwarf-version=5", + "-Zstack-protector=strong", // Set flags we don't recognise but rustc supports next // rustc flags "--cfg", @@ -515,6 +550,7 @@ mod tests { soft_float: Some(true), branch_protection: Some("bti,pac-ret,leaf"), dwarf_version: Some(5), + stack_protector: Some("strong"), }, ); } diff --git a/tests/rustflags.rs b/tests/rustflags.rs index 0e594f26a..3ec1c8eef 100644 --- a/tests/rustflags.rs +++ b/tests/rustflags.rs @@ -14,12 +14,13 @@ fn inherits_rustflags() { test.cmd(0) .must_not_have("-fno-omit-frame-pointer") .must_not_have("-mcmodel=small") - .must_not_have("-msoft-float"); + .must_not_have("-msoft-float") + .must_not_have("-fstack-protector-strong"); // Correctly inherits flags from rustc std::env::set_var( "CARGO_ENCODED_RUSTFLAGS", - "-Cforce-frame-pointers=true\u{1f}-Ccode-model=small\u{1f}-Csoft-float\u{1f}-Cdwarf-version=5", + "-Cforce-frame-pointers=true\u{1f}-Ccode-model=small\u{1f}-Csoft-float\u{1f}-Cdwarf-version=5\u{1f}-Zstack-protector=strong", ); let test = Test::gnu(); test.gcc().file("foo.c").compile("foo"); @@ -27,5 +28,20 @@ fn inherits_rustflags() { .must_have("-fno-omit-frame-pointer") .must_have("-mcmodel=small") .must_have("-msoft-float") - .must_have("-gdwarf-5"); + .must_have("-gdwarf-5") + .must_have("-fstack-protector-strong"); + + // Do *not* propagate -Zstack-protector=none + std::env::set_var( + "CARGO_ENCODED_RUSTFLAGS", + "-Cforce-frame-pointers=true\u{1f}-Ccode-model=small\u{1f}-Csoft-float\u{1f}-Cdwarf-version=5\u{1f}-Zstack-protector=none", + ); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + test.cmd(0) + .must_have("-fno-omit-frame-pointer") + .must_have("-mcmodel=small") + .must_have("-msoft-float") + .must_have("-gdwarf-5") + .must_not_have("-fno-stack-protector"); }