From 676a5bfb8221c55f3fc3a2e24c339ab924850825 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 8 Sep 2025 16:47:37 +0000 Subject: [PATCH 1/6] Stabilize `-Zstack-protector` as `-Cstack-protector` I propose stabilizing `-Cstack-protector` as `-Zstack-protector`. This PR adds a new `-Cstack-protector` flag, leaving the unstable `-Z` flag as is to ease the transition period. The `-Z` flag will be removed in the future. No RFC/MCP, this flag was added in 84197 and was not deemed large enough to require additional process. The tracking issue for this feature is 114903. The `-Cstack-protector=strong` mode uses the same underlying heuristics as Clang's `-fstack-protector-strong`. These heuristics weren't designed for Rust, and may be over-conservative in some cases - for example, if Rust stores a field's data in an alloca using an LLVM array type, LLVM regard the alloca as meaning that the function has a C array, and enable stack overflow canaries even if the function accesses the alloca in a safe way. Some people thought we should wait on stabilization until there are better heuristics, but I didn't hear about any concrete case where this unduly harms performance, and I think that when a need comes, we can improve the heuristics in LLVM after stabilization. The heuristics do seem to not be under-conservative, so this should not be a security risk. The `-Cstack-protector=basic` mode (`-fstack-protector`) uses heuristics that are specifically designed to catch old-C-style string manipulation. This is not a good fit to Rust, which does not perform much unsafe C-style string manipulation. As far as I can tell, nobody has been asking for it, and few people are using it even in today's C - modern distros (e.g. [Debian]) tend to use `-fstack-protector-strong`. Therefore, `-Cstack-protector=basic` has been **removed**. If anyone is interested in it, they are welcome to add it back as an unstable option. [Debian]: https://wiki.debian.org/Hardening#DEB_BUILD_HARDENING_STACKPROTECTOR_.28gcc.2Fg.2B-.2B-_-fstack-protector-strong.29 Most implementation was done in . The command-line attribute enables the relevant LLVM attribute on all functions in . Each target can indicate that it does not support stack canaries - currently, the GPU platforms `nvptx64-nvidia-cuda` and `amdgcn-amd-amdhsa`. On these platforms, use of `-Cstack-protector` causes an error. The feature has tests that make sure that the LLVM heuristic gives reasonable results for several functions, by checking for `__security_check_cookie` (on Windows) or `__stack_chk_fail` (on Linux). See No call-for-testing has been conducted, but the feature seems to be in use. No reported bugs seem to exist. - bbjornse was the original implementor at 84197 - mrcnski documented it at 111722 - wesleywiser added tests for Windows at 116037 - davidtwco worked on the feature at 121742 - nikic provided support from the LLVM side (on Zulip on and elsewhere), thanks nikic! No FIXMEs related to this feature. This feature cannot cause undefined behavior. No changes to reference/spec, docs added to the codegen docs as part of the stabilization PR. No. None. No support needed for rustdoc, clippy, rust-analyzer, rustfmt or rustup. Cargo could expose this as an option in build profiles but I would expect the decision as to what version should be used would be made for the entire crate graph at build time rather than by individual package authors. `-C stack-protector` is propagated to C compilers using cc-rs via rust-lang/cc-rs issue 1550 --- bootstrap.example.toml | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 29 ++++++++++----- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_session/messages.ftl | 2 +- compiler/rustc_session/src/options.rs | 12 +++++-- compiler/rustc_session/src/session.rs | 17 ++++----- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/doc/rustc/src/codegen-options/index.md | 28 +++++++++++++++ src/doc/rustc/src/exploit-mitigations.md | 2 +- ...otector-heuristics-effect-windows-32bit.rs | 8 ++--- ...otector-heuristics-effect-windows-64bit.rs | 8 ++--- .../stack-protector-heuristics-effect.rs | 8 ++--- .../stack-protector-target-support.rs | 12 +++---- tests/codegen-llvm/stack-protector.rs | 36 ++++++++++++++++--- tests/ui/README.md | 2 +- tests/ui/abi/stack-protector.rs | 2 +- ...l-stack-protector-unsupported.all-z.stderr | 4 +++ ...ail-stack-protector-unsupported.all.stderr | 4 +++ .../fail-stack-protector-unsupported.rs | 30 ++++++++++++++++ ...-stack-protector-unsupported.strong.stderr | 4 +++ ...arn-stack-protector-unsupported.all.stderr | 4 --- ...n-stack-protector-unsupported.basic.stderr | 4 --- .../warn-stack-protector-unsupported.rs | 30 ---------------- ...-stack-protector-unsupported.strong.stderr | 4 --- 24 files changed, 164 insertions(+), 92 deletions(-) create mode 100644 tests/ui/stack-protector/fail-stack-protector-unsupported.all-z.stderr create mode 100644 tests/ui/stack-protector/fail-stack-protector-unsupported.all.stderr create mode 100644 tests/ui/stack-protector/fail-stack-protector-unsupported.rs create mode 100644 tests/ui/stack-protector/fail-stack-protector-unsupported.strong.stderr delete mode 100644 tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr delete mode 100644 tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr delete mode 100644 tests/ui/stack-protector/warn-stack-protector-unsupported.rs delete mode 100644 tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr diff --git a/bootstrap.example.toml b/bootstrap.example.toml index eac9395779798..5b9e66659b77d 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -713,7 +713,7 @@ #rust.frame-pointers = false # Indicates whether stack protectors should be used -# via the unstable option `-Zstack-protector`. +# via `-Cstack-protector`. # # Valid options are : `none`(default),`basic`,`strong`, or `all`. # `strong` and `basic` options may be buggy and are not recommended, see rust-lang/rust#114903. diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6fb23d0984335..de135e43f3fd6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -282,19 +282,32 @@ impl CodegenBackend for LlvmCodegenBackend { Generate stack canaries in all functions. strong - Generate stack canaries in a function if it either: - - has a local variable of `[T; N]` type, regardless of `T` and `N` - - takes the address of a local variable. + Generate stack canaries for all functions, unless the compiler + can prove these functions can't be the source of a stack + buffer overflow (even in the presence of undefined behavior). - (Note that a local variable being borrowed is not equivalent to its - address being taken: e.g. some borrows may be removed by optimization, - while by-value argument passing may be implemented with reference to a - local stack variable in the ABI.) + This provides the same security guarantees as Clang's + `-fstack-protector=strong`. + + The exact rules are unstable and subject to change, but + currently, it generates stack protectors for functions that, + *post-optimization*, contain either arrays (of any size + or type) or address-taken locals. basic - Generate stack canaries in functions with local variables of `[T; N]` + Generate stack canaries in functions that are heuristically + suspected to contain buffer overflows. + + The heuristic is subject to change, but currently it + includes functions with local variables of `[T; N]` type, where `T` is byte-sized and `N` >= 8. + This heuristic originated from C, where it detects + functions that allocate a `char buf[N];` buffer on the + stack, and are therefore likely to have a stack buffer overflow + in the case of a length-calculation error. It is *not* a good + heuristic for Rust code. + none Do not generate stack canaries. "# diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 7730bddc0f12d..09f25b61216e6 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -641,6 +641,7 @@ fn test_codegen_options_tracking_hash() { tracked!(relro_level, Some(RelroLevel::Full)); tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); + tracked!(stack_protector, StackProtector::All); tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); @@ -871,7 +872,6 @@ fn test_unstable_options_tracking_hash() { tracked!(small_data_threshold, Some(16)); tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); - tracked!(stack_protector, StackProtector::All); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tiny_const_eval_limit, true); diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b46e8ab4fdcbe..00a3214c9a41e 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -129,7 +129,7 @@ session_target_requires_unwind_tables = target requires unwind tables, they cann session_target_small_data_threshold_not_supported = `-Z small-data-threshold` is not supported for target {$target_triple} and will be ignored -session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored +session_target_stack_protector_not_supported = `-C stack-protector={$stack_protector}` is not supported for target {$target_triple} session_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag .controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}` diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 69facde693689..95444e101123a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1870,9 +1870,12 @@ pub mod parse { true } - pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool { + pub(crate) fn parse_stack_protector( + slot: &mut Option, + v: Option<&str>, + ) -> bool { match v.and_then(|s| StackProtector::from_str(s).ok()) { - Some(ssp) => *slot = ssp, + Some(ssp) => *slot = Some(ssp), _ => return false, } true @@ -2161,6 +2164,9 @@ options! { #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")] split_debuginfo: Option = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), + #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] + stack_protector: Option = (None, parse_stack_protector, [TRACKED], + "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option = (None, @@ -2635,7 +2641,7 @@ written to standard error output)"), src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] - stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], + stack_protector: Option = (None, parse_stack_protector, [TRACKED], "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], "allow staticlibs to have rust dylib dependencies"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3525c7c1d1a99..6970c79387b1f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -734,11 +734,12 @@ impl Session { } pub fn stack_protector(&self) -> StackProtector { - if self.target.options.supports_stack_protector { - self.opts.unstable_opts.stack_protector - } else { - StackProtector::None - } + // -C stack-protector overwrites -Z stack-protector, default to StackProtector::None + self.opts + .cg + .stack_protector + .or(self.opts.unstable_opts.stack_protector) + .unwrap_or(StackProtector::None) } pub fn must_emit_unwind_tables(&self) -> bool { @@ -1276,10 +1277,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } - if sess.opts.unstable_opts.stack_protector != StackProtector::None { + if sess.stack_protector() != StackProtector::None { if !sess.target.options.supports_stack_protector { - sess.dcx().emit_warn(errors::StackProtectorNotSupportedForTarget { - stack_protector: sess.opts.unstable_opts.stack_protector, + sess.dcx().emit_err(errors::StackProtectorNotSupportedForTarget { + stack_protector: sess.stack_protector(), target_triple: &sess.opts.target_triple, }); } diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 924bb4adb42d0..5c73f7785671d 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -910,7 +910,7 @@ impl Builder<'_> { cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string()); if let Some(stack_protector) = &self.config.rust_stack_protector { - rustflags.arg(&format!("-Zstack-protector={stack_protector}")); + rustflags.arg(&format!("-Cstack-protector={stack_protector}")); } if !matches!(cmd_kind, Kind::Build | Kind::Check | Kind::Clippy | Kind::Fix) && want_rustdoc diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 445b10188e3f8..25f1df903a213 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -672,6 +672,34 @@ Note that all three options are supported on Linux and Apple platforms, Attempting to use an unsupported option requires using the nightly channel with the `-Z unstable-options` flag. +## stack-protector + +The option `-C stack-protector` (currently also supported in the +old style `-Z stack-protector`) controls the generation of +stack-protector canaries. + +This flag controls stack smashing protection strategy. + +Supported values for this option are: +- `none` (default): Disable stack canary generation +- `basic`: Generate stack canaries in functions that are suspected + to have a high chance of containing stack buffer overflows (deprecated). +- `strong`: Generate stack canaries in all functions, unless the compiler + can prove these functions can't be the source of a stack + buffer overflow (even in the presence of undefined behavior). + + This provides the same security guarantees as Clang's + `-fstack-protector=strong`. + + The exact rules are unstable and subject to change, but + currently, it generates stack protectors for functions that, + *post-optimization*, contain either arrays (of any size + or type) or address-taken locals. +- `all`: Generate stack canaries in all functions + +Stack protectors are not supported on many GPU targets, use of stack +protectors on these targets is an error. + ## strip The option `-C strip=val` controls stripping of debuginfo and similar auxiliary diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index c80d7d8743cd9..6b079cb82ee52 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -62,7 +62,7 @@ equivalent. | Stack clashing protection | Yes | Yes | 1.20.0 (2017-08-31) | | Read-only relocations and immediate binding | Yes | Yes | 1.21.0 (2017-10-12) | | Heap corruption protection | Yes | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | -| Stack smashing protection | Yes | No, `-Z stack-protector` | Nightly | +| Stack smashing protection | Yes | No, `-C stack-protector` | ??? | | Forward-edge control flow protection | Yes | No, `-Z sanitizer=cfi` | Nightly | | Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | No, `-Z sanitizer=shadow-call-stack,safestack` | Nightly | diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 3287e018b4044..0d7a5453cc19d 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -3,10 +3,10 @@ //@ only-windows //@ only-msvc //@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong +//@ [basic] compile-flags: -C stack-protector=basic +//@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled #![crate_type = "lib"] diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs index 9a3dabc74dded..db592fc3ec770 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs @@ -3,10 +3,10 @@ //@ only-windows //@ only-msvc //@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong +//@ [basic] compile-flags: -C stack-protector=basic +//@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled #![crate_type = "lib"] diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs index ae281cb95da5f..dd2ecdd7ac290 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs @@ -4,10 +4,10 @@ //@ ignore-msvc stack check code uses different function names //@ ignore-nvptx64 stack protector is not supported //@ ignore-wasm32-bare -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong +//@ [basic] compile-flags: -C stack-protector=basic +//@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled // NOTE: the heuristics for stack smash protection inappropriately rely on types in LLVM IR, diff --git a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs index a937256a60f8c..91753e7d4343c 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs @@ -4,7 +4,7 @@ //@ add-core-stubs //@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 //@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r36 r37 r38 r39 r40 r41 r42 r43 r44 -//@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 +//@ revisions: r45 r46 r47 r48 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 //@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85 //@ assembly-output: emit-asm //@ [r1] compile-flags: --target aarch64-unknown-linux-gnu @@ -99,8 +99,8 @@ //@ [r47] needs-llvm-components: mips //@ [r48] compile-flags: --target mipsel-unknown-linux-musl //@ [r48] needs-llvm-components: mips -//@ [r49] compile-flags: --target nvptx64-nvidia-cuda -//@ [r49] needs-llvm-components: nvptx +//-@ [r49] compile-flags: --target nvptx64-nvidia-cuda [stack protector not supported on CUDA +//- see the test fail-stack-protector-unsupported] //@ [r50] compile-flags: --target powerpc-unknown-linux-gnu //@ [r50] needs-llvm-components: powerpc //@ [r51] compile-flags: --target powerpc64-unknown-linux-gnu @@ -173,7 +173,7 @@ //@ [r84] needs-llvm-components: x86 //@ [r85] compile-flags: --target x86_64-unknown-redox //@ [r85] needs-llvm-components: x86 -//@ compile-flags: -Z stack-protector=all +//@ compile-flags: -C stack-protector=all //@ compile-flags: -C opt-level=2 #![crate_type = "lib"] @@ -193,10 +193,6 @@ pub fn foo() { // r7: callq __security_check_cookie // r13: bl __security_check_cookie - // cuda doesn't support stack-smash protection - // r49-NOT: __security_check_cookie - // r49-NOT: __stack_chk_fail - // Other targets do stack checking within the function, and call a failure function on error // r1: __stack_chk_fail // r2: __stack_chk_fail diff --git a/tests/codegen-llvm/stack-protector.rs b/tests/codegen-llvm/stack-protector.rs index 8ab25b470cda1..686db3f1f4412 100644 --- a/tests/codegen-llvm/stack-protector.rs +++ b/tests/codegen-llvm/stack-protector.rs @@ -1,8 +1,12 @@ -//@ revisions: all strong basic none +//@ revisions: all all-z strong strong-z basic basic-z none strong-c-overrides-z //@ ignore-nvptx64 stack protector not supported -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic +//@ [all] compile-flags: -C stack-protector=all +//@ [all-z] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong +//@ [strong-z] compile-flags: -Z stack-protector=strong +//@ [basic] compile-flags: -C stack-protector=basic +//@ [basic-z] compile-flags: -Z stack-protector=basic +//@ [strong-c-overrides-z] compile-flags: -C stack-protector=strong -Z stack-protector=all #![crate_type = "lib"] @@ -16,18 +20,42 @@ pub fn foo() { // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // all-z-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // all-z: attributes #0 = { {{.*}}sspreq {{.*}} } + // all-z-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } // strong: attributes #0 = { {{.*}}sspstrong {{.*}} } // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong-z: attributes #0 = { {{.*}}sspstrong {{.*}} } + // strong-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + + // strong-c-overrides-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-c-overrides-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong-c-overrides-z: attributes #0 = { {{.*}}sspstrong {{.*}} } + // strong-c-overrides-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-c-overrides-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } // basic: attributes #0 = { {{.*}}ssp {{.*}} } // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // basic-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-z-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // basic-z: attributes #0 = { {{.*}}ssp {{.*}} } + // basic-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-z-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} } diff --git a/tests/ui/README.md b/tests/ui/README.md index 66c1bb905a792..3070bf34f9198 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1285,7 +1285,7 @@ Stability attributes used internally by the standard library: `#[stable()]` and Some tests for pretty printing of rustc_public's IR. -## `tests/ui/stack-protector/`: `-Z stack-protector` command line flag +## `tests/ui/stack-protector/`: `-C stack-protector` command line flag See [Tracking Issue for stabilizing stack smashing protection (i.e., `-Z stack-protector`) #114903](https://github.com/rust-lang/rust/issues/114903). diff --git a/tests/ui/abi/stack-protector.rs b/tests/ui/abi/stack-protector.rs index 29332861977b7..a0a0fc5d8017a 100644 --- a/tests/ui/abi/stack-protector.rs +++ b/tests/ui/abi/stack-protector.rs @@ -1,7 +1,7 @@ //@ run-pass //@ only-x86_64-unknown-linux-gnu //@ revisions: ssp no-ssp -//@ [ssp] compile-flags: -Z stack-protector=all +//@ [ssp] compile-flags: -C stack-protector=all //@ compile-flags: -C opt-level=2 //@ compile-flags: -g diff --git a/tests/ui/stack-protector/fail-stack-protector-unsupported.all-z.stderr b/tests/ui/stack-protector/fail-stack-protector-unsupported.all-z.stderr new file mode 100644 index 0000000000000..9f2876de057fd --- /dev/null +++ b/tests/ui/stack-protector/fail-stack-protector-unsupported.all-z.stderr @@ -0,0 +1,4 @@ +error: `-C stack-protector=all` is not supported for target nvptx64-nvidia-cuda + +error: aborting due to 1 previous error + diff --git a/tests/ui/stack-protector/fail-stack-protector-unsupported.all.stderr b/tests/ui/stack-protector/fail-stack-protector-unsupported.all.stderr new file mode 100644 index 0000000000000..9f2876de057fd --- /dev/null +++ b/tests/ui/stack-protector/fail-stack-protector-unsupported.all.stderr @@ -0,0 +1,4 @@ +error: `-C stack-protector=all` is not supported for target nvptx64-nvidia-cuda + +error: aborting due to 1 previous error + diff --git a/tests/ui/stack-protector/fail-stack-protector-unsupported.rs b/tests/ui/stack-protector/fail-stack-protector-unsupported.rs new file mode 100644 index 0000000000000..c9eb3560eda42 --- /dev/null +++ b/tests/ui/stack-protector/fail-stack-protector-unsupported.rs @@ -0,0 +1,30 @@ +//@ check-fail +//@ revisions: all strong all-z +//@ compile-flags: --target nvptx64-nvidia-cuda +//@ needs-llvm-components: nvptx +//@ [all] compile-flags: -C stack-protector=all +//@ [strong] compile-flags: -C stack-protector=strong +//@ [all-z] compile-flags: -Z stack-protector=all + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +trait Sized: MetaSized {} + +#[lang = "copy"] +trait Copy {} + +pub fn main(){} + +//[all]~? ERROR `-C stack-protector=all` is not supported for target nvptx64-nvidia-cuda +//[all-z]~? ERROR `-C stack-protector=all` is not supported for target nvptx64-nvidia-cuda +//[strong]~? ERROR `-C stack-protector=strong` is not supported for target nvptx64-nvidia-cuda diff --git a/tests/ui/stack-protector/fail-stack-protector-unsupported.strong.stderr b/tests/ui/stack-protector/fail-stack-protector-unsupported.strong.stderr new file mode 100644 index 0000000000000..a92575e597af8 --- /dev/null +++ b/tests/ui/stack-protector/fail-stack-protector-unsupported.strong.stderr @@ -0,0 +1,4 @@ +error: `-C stack-protector=strong` is not supported for target nvptx64-nvidia-cuda + +error: aborting due to 1 previous error + diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr b/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr deleted file mode 100644 index 54887715523c1..0000000000000 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.all.stderr +++ /dev/null @@ -1,4 +0,0 @@ -warning: `-Z stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored - -warning: 1 warning emitted - diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr b/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr deleted file mode 100644 index f7a1ee39fb9af..0000000000000 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr +++ /dev/null @@ -1,4 +0,0 @@ -warning: `-Z stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored - -warning: 1 warning emitted - diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs deleted file mode 100644 index a635976c8427b..0000000000000 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ build-pass -//@ revisions: all strong basic -//@ compile-flags: --target nvptx64-nvidia-cuda -//@ needs-llvm-components: nvptx -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -trait Sized: MetaSized {} - -#[lang = "copy"] -trait Copy {} - -pub fn main(){} - -//[all]~? WARN `-Z stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored -//[strong]~? WARN `-Z stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored -//[basic]~? WARN `-Z stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr b/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr deleted file mode 100644 index ccc2f9f2cc5b8..0000000000000 --- a/tests/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr +++ /dev/null @@ -1,4 +0,0 @@ -warning: `-Z stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored - -warning: 1 warning emitted - From daca88a64ed10e71e341d70b53425355aa49b23b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 9 Sep 2025 11:26:18 +0000 Subject: [PATCH 2/6] remove stack-protector=basic stack-protector=basic is a heuristic designed for C putting this in its own commit to allow for easy reversion if someone wants it --- bootstrap.example.toml | 3 +-- compiler/rustc_codegen_llvm/src/attributes.rs | 1 - compiler/rustc_codegen_llvm/src/lib.rs | 14 ----------- compiler/rustc_interface/src/tests.rs | 3 ++- compiler/rustc_target/src/spec/mod.rs | 6 ----- src/doc/rustc/src/codegen-options/index.md | 2 -- ...otector-heuristics-effect-windows-32bit.rs | 23 +++++-------------- ...otector-heuristics-effect-windows-64bit.rs | 22 ++++-------------- .../stack-protector-heuristics-effect.rs | 21 ++++------------- tests/codegen-llvm/stack-protector.rs | 14 ----------- .../no-stack-protector-basic.rs | 9 ++++++++ .../no-stack-protector-basic.stable.stderr | 2 ++ .../no-stack-protector-basic.unstable.stderr | 2 ++ 13 files changed, 30 insertions(+), 92 deletions(-) create mode 100644 tests/ui/stack-protector/no-stack-protector-basic.rs create mode 100644 tests/ui/stack-protector/no-stack-protector-basic.stable.stderr create mode 100644 tests/ui/stack-protector/no-stack-protector-basic.unstable.stderr diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 5b9e66659b77d..6334a39e355b2 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -715,8 +715,7 @@ # Indicates whether stack protectors should be used # via `-Cstack-protector`. # -# Valid options are : `none`(default),`basic`,`strong`, or `all`. -# `strong` and `basic` options may be buggy and are not recommended, see rust-lang/rust#114903. +# Valid options are : `none`(default), `strong`, or `all`. #rust.stack-protector = "none" # Prints each test name as it is executed, to help debug issues in the test harness itself. diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 573c51a95398b..a16f22d402c8a 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -269,7 +269,6 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { StackProtector::None => return None, StackProtector::All => AttributeKind::StackProtectReq, StackProtector::Strong => AttributeKind::StackProtectStrong, - StackProtector::Basic => AttributeKind::StackProtect, }; Some(sspattr.create_attr(cx.llcx)) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index de135e43f3fd6..53a32c794c523 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -294,20 +294,6 @@ impl CodegenBackend for LlvmCodegenBackend { *post-optimization*, contain either arrays (of any size or type) or address-taken locals. - basic - Generate stack canaries in functions that are heuristically - suspected to contain buffer overflows. - - The heuristic is subject to change, but currently it - includes functions with local variables of `[T; N]` - type, where `T` is byte-sized and `N` >= 8. - - This heuristic originated from C, where it detects - functions that allocate a `char buf[N];` buffer on the - stack, and are therefore likely to have a stack buffer overflow - in the case of a length-calculation error. It is *not* a good - heuristic for Rust code. - none Do not generate stack canaries. "# diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 09f25b61216e6..30fc18ef2e5d6 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -641,7 +641,7 @@ fn test_codegen_options_tracking_hash() { tracked!(relro_level, Some(RelroLevel::Full)); tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); - tracked!(stack_protector, StackProtector::All); + tracked!(stack_protector, Some(StackProtector::All)); tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); @@ -872,6 +872,7 @@ fn test_unstable_options_tracking_hash() { tracked!(small_data_threshold, Some(16)); tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); + tracked!(stack_protector, Some(StackProtector::All)); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tiny_const_eval_limit, true); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 07fb1ce63f7c4..e7a124e67d9eb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1347,12 +1347,6 @@ crate::target_spec_enum! { /// Disable stack canary generation. None = "none", - /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see - /// llvm/docs/LangRef.rst). This triggers stack canary generation in - /// functions which contain an array of a byte-sized type with more than - /// eight elements. - Basic = "basic", - /// On LLVM, mark all generated LLVM functions with the `sspstrong` /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary /// generation in functions which either contain an array, or which take diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 25f1df903a213..78ff3bd777c1e 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -682,8 +682,6 @@ This flag controls stack smashing protection strategy. Supported values for this option are: - `none` (default): Disable stack canary generation -- `basic`: Generate stack canaries in functions that are suspected - to have a high chance of containing stack buffer overflows (deprecated). - `strong`: Generate stack canaries in all functions, unless the compiler can prove these functions can't be the source of a stack buffer overflow (even in the presence of undefined behavior). diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 0d7a5453cc19d..89be2bb5ebc2c 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -1,11 +1,10 @@ -//@ revisions: all strong basic none missing +//@ revisions: all strong none missing //@ assembly-output: emit-asm //@ only-windows //@ only-msvc //@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH //@ [all] compile-flags: -C stack-protector=all //@ [strong] compile-flags: -C stack-protector=strong -//@ [basic] compile-flags: -C stack-protector=basic //@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled @@ -18,7 +17,6 @@ pub fn emptyfn() { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -36,7 +34,6 @@ pub fn array_char(f: fn(*const char)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -52,7 +49,6 @@ pub fn array_u8_1(f: fn(*const u8)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -66,10 +62,10 @@ pub fn array_u8_small(f: fn(*const u8)) { f(&b as *const _); // Small arrays do not lead to stack protection by the 'basic' heuristic. + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -82,10 +78,10 @@ pub fn array_u8_large(f: fn(*const u8)) { // Since `a` is a byte array with size greater than 8, the basic heuristic // will also protect this function. + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -101,10 +97,10 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { // Since `a` is a byte array in the LLVM output, the basic heuristic will // also protect this function. + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -128,10 +124,10 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // } // EOF // ``` + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -159,10 +155,10 @@ pub fn local_string_addr_taken(f: fn(&String)) { // EOF // ``` // + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -191,7 +187,6 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -228,7 +223,6 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -257,7 +251,6 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -297,7 +290,6 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -309,7 +301,6 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -321,7 +312,6 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -353,7 +343,6 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // all-NOT: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs index db592fc3ec770..bbd0a2918532d 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs @@ -1,11 +1,10 @@ -//@ revisions: all strong basic none missing +//@ revisions: all strong none missing //@ assembly-output: emit-asm //@ only-windows //@ only-msvc //@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH //@ [all] compile-flags: -C stack-protector=all //@ [strong] compile-flags: -C stack-protector=strong -//@ [basic] compile-flags: -C stack-protector=basic //@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled @@ -17,7 +16,6 @@ pub fn emptyfn() { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -35,7 +33,6 @@ pub fn array_char(f: fn(*const char)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -51,7 +48,6 @@ pub fn array_u8_1(f: fn(*const u8)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -65,10 +61,10 @@ pub fn array_u8_small(f: fn(*const u8)) { f(&b as *const _); // Small arrays do not lead to stack protection by the 'basic' heuristic. + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -81,10 +77,10 @@ pub fn array_u8_large(f: fn(*const u8)) { // Since `a` is a byte array with size greater than 8, the basic heuristic // will also protect this function. + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -100,10 +96,10 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { // Since `a` is a byte array in the LLVM output, the basic heuristic will // also protect this function. + // (basic is not currently supported, leaving the test anyway). // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -130,7 +126,6 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -158,7 +153,6 @@ pub fn local_string_addr_taken(f: fn(&String)) { // } // EOF // ``` - // // We should have a __security_check_cookie call in `all` and `strong` modes but // LLVM does not support generating stack protectors in functions with funclet @@ -167,7 +161,6 @@ pub fn local_string_addr_taken(f: fn(&String)) { // all-NOT: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie @@ -198,7 +191,6 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -235,7 +227,6 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -264,7 +255,6 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) { // all: __security_check_cookie // strong: __security_check_cookie - // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -304,7 +294,6 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -316,7 +305,6 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -328,7 +316,6 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { // all: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } @@ -360,7 +347,6 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // all-NOT: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie } diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs index dd2ecdd7ac290..e9d12753a6916 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs @@ -1,4 +1,4 @@ -//@ revisions: all strong basic none missing +//@ revisions: all strong none missing //@ assembly-output: emit-asm //@ ignore-apple slightly different policy on stack protection of arrays //@ ignore-msvc stack check code uses different function names @@ -6,7 +6,6 @@ //@ ignore-wasm32-bare //@ [all] compile-flags: -C stack-protector=all //@ [strong] compile-flags: -C stack-protector=strong -//@ [basic] compile-flags: -C stack-protector=basic //@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled @@ -24,7 +23,6 @@ pub fn emptyfn() { // all: __stack_chk_fail // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -42,7 +40,6 @@ pub fn array_char(f: fn(*const char)) { // all: __stack_chk_fail // strong: __stack_chk_fail - // basic: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -58,7 +55,6 @@ pub fn array_u8_1(f: fn(*const u8)) { // all: __stack_chk_fail // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -72,10 +68,10 @@ pub fn array_u8_small(f: fn(*const u8)) { f(&b as *const _); // Small arrays do not lead to stack protection by the 'basic' heuristic. + // (basic is not currently supported, leaving the test anyway). // all: __stack_chk_fail // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -88,10 +84,10 @@ pub fn array_u8_large(f: fn(*const u8)) { // Since `a` is a byte array with size greater than 8, the basic heuristic // will also protect this function. + // (basic is not currently supported, leaving the test anyway). // all: __stack_chk_fail // strong: __stack_chk_fail - // basic: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -107,10 +103,10 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { // Since `a` is a byte array in the LLVM output, the basic heuristic will // also protect this function. + // (basic is not currently supported, leaving the test anyway). // all: __stack_chk_fail // strong: __stack_chk_fail - // basic: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -137,7 +133,6 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // all: __stack_chk_fail // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -153,7 +148,6 @@ pub fn local_string_addr_taken(f: fn(&String)) { // all: __stack_chk_fail // strong: __stack_chk_fail - // basic: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -182,7 +176,6 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // all: __stack_chk_fail // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -219,7 +212,6 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) { // all: __stack_chk_fail // strong: __stack_chk_fail - // basic: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -248,7 +240,6 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) { // all: __stack_chk_fail // strong: __stack_chk_fail - // basic: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -288,7 +279,6 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { // all: __stack_chk_fail // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -300,7 +290,6 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { // all: __stack_chk_fail // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -312,7 +301,6 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { // all: __stack_chk_fail // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } @@ -339,7 +327,6 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // all: __stack_chk_fail // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail } diff --git a/tests/codegen-llvm/stack-protector.rs b/tests/codegen-llvm/stack-protector.rs index 686db3f1f4412..1477d2ed7b28a 100644 --- a/tests/codegen-llvm/stack-protector.rs +++ b/tests/codegen-llvm/stack-protector.rs @@ -4,8 +4,6 @@ //@ [all-z] compile-flags: -Z stack-protector=all //@ [strong] compile-flags: -C stack-protector=strong //@ [strong-z] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -C stack-protector=basic -//@ [basic-z] compile-flags: -Z stack-protector=basic //@ [strong-c-overrides-z] compile-flags: -C stack-protector=strong -Z stack-protector=all #![crate_type = "lib"] @@ -44,18 +42,6 @@ pub fn foo() { // strong-c-overrides-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // strong-c-overrides-z-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // basic: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - - // basic-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // basic-z-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // basic-z: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-z-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // basic-z-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} } diff --git a/tests/ui/stack-protector/no-stack-protector-basic.rs b/tests/ui/stack-protector/no-stack-protector-basic.rs new file mode 100644 index 0000000000000..80f0e9b5d8c38 --- /dev/null +++ b/tests/ui/stack-protector/no-stack-protector-basic.rs @@ -0,0 +1,9 @@ +//@ check-fail +//@ revisions: stable unstable +//@ [unstable] compile-flags: -Z stack-protector=basic +//@ [stable] compile-flags: -C stack-protector=basic + +pub fn main(){} + +//[unstable]~? ERROR incorrect value `basic` for unstable option `stack-protector` +//[stable]~? ERROR incorrect value `basic` for codegen option `stack-protector` diff --git a/tests/ui/stack-protector/no-stack-protector-basic.stable.stderr b/tests/ui/stack-protector/no-stack-protector-basic.stable.stderr new file mode 100644 index 0000000000000..7295a2e9bd45a --- /dev/null +++ b/tests/ui/stack-protector/no-stack-protector-basic.stable.stderr @@ -0,0 +1,2 @@ +error: incorrect value `basic` for codegen option `stack-protector` - one of (`none` (default), `basic`, `strong`, or `all`) was expected + diff --git a/tests/ui/stack-protector/no-stack-protector-basic.unstable.stderr b/tests/ui/stack-protector/no-stack-protector-basic.unstable.stderr new file mode 100644 index 0000000000000..ce88114f16b82 --- /dev/null +++ b/tests/ui/stack-protector/no-stack-protector-basic.unstable.stderr @@ -0,0 +1,2 @@ +error: incorrect value `basic` for unstable option `stack-protector` - one of (`none` (default), `basic`, `strong`, or `all`) was expected + From e11d6047e20f696d67b9e89cb7572db5b3b747aa Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 9 Sep 2025 13:39:48 +0000 Subject: [PATCH 3/6] change wording for stack-protector-strong --- compiler/rustc_codegen_llvm/src/lib.rs | 6 ++++-- src/doc/rustc/src/codegen-options/index.md | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 53a32c794c523..c327939974996 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -291,8 +291,10 @@ impl CodegenBackend for LlvmCodegenBackend { The exact rules are unstable and subject to change, but currently, it generates stack protectors for functions that, - *post-optimization*, contain either arrays (of any size - or type) or address-taken locals. + *post-optimization*, contain LLVM allocas (which + include all stack allocations - including fixed-size + allocations - that are used in a way that is not completely + determined by static control flow). none Do not generate stack canaries. diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 78ff3bd777c1e..3c734572df9d4 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -691,9 +691,11 @@ Supported values for this option are: The exact rules are unstable and subject to change, but currently, it generates stack protectors for functions that, - *post-optimization*, contain either arrays (of any size - or type) or address-taken locals. -- `all`: Generate stack canaries in all functions + *post-optimization*, contain LLVM allocas (which + include all stack allocations - including fixed-size + allocations - that are used in a way that is not completely + determined by static control flow). + - `all`: Generate stack canaries in all functions Stack protectors are not supported on many GPU targets, use of stack protectors on these targets is an error. From 8b418a52ba231475393f8b3ee12b08cdc8bf937a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 9 Sep 2025 16:31:34 +0000 Subject: [PATCH 4/6] similar security guarnatees rather than exactly --- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- src/doc/rustc/src/codegen-options/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index c327939974996..93b75dafe1a8d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -286,7 +286,7 @@ impl CodegenBackend for LlvmCodegenBackend { can prove these functions can't be the source of a stack buffer overflow (even in the presence of undefined behavior). - This provides the same security guarantees as Clang's + This provides similar security guarantees to Clang's `-fstack-protector=strong`. The exact rules are unstable and subject to change, but diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 3c734572df9d4..2d105d2670bcc 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -686,7 +686,7 @@ Supported values for this option are: can prove these functions can't be the source of a stack buffer overflow (even in the presence of undefined behavior). - This provides the same security guarantees as Clang's + This provides similar security guarantees to Clang's `-fstack-protector=strong`. The exact rules are unstable and subject to change, but From 077c76176ebd1c62f6aed1aab7a495cd2b63db49 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 10 Sep 2025 10:41:40 +0000 Subject: [PATCH 5/6] stack smash protection => stack smashing protection --- compiler/rustc_session/src/options.rs | 4 ++-- .../stack-protector-heuristics-effect-windows-32bit.rs | 4 ++-- .../stack-protector-heuristics-effect-windows-64bit.rs | 4 ++-- .../stack-protector/stack-protector-heuristics-effect.rs | 6 +++--- .../stack-protector/stack-protector-target-support.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 95444e101123a..9912c03290312 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2166,7 +2166,7 @@ options! { "how to handle split-debuginfo, a platform-specific option"), #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] stack_protector: Option = (None, parse_stack_protector, [TRACKED], - "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), + "control stack smashing protection strategy (`rustc --print stack-protector-strategies` for details)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option = (None, @@ -2642,7 +2642,7 @@ written to standard error output)"), "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] stack_protector: Option = (None, parse_stack_protector, [TRACKED], - "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), + "control stack smashing protection strategy (`rustc --print stack-protector-strategies` for details)"), staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], "allow staticlibs to have rust dylib dependencies"), staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED], diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 89be2bb5ebc2c..95661b6894131 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -114,7 +114,7 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // This function takes the address of a local variable taken. Although this // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: + // heuristic adds stack smashing protection. This is also the case in C++: // ``` // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk // #include @@ -182,7 +182,7 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // Even though the local variable conceptually has its address taken, as // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with + // is easily inlined. There is therefore no stack smashing protection even with // the `strong` heuristic. // all: __security_check_cookie diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs index bbd0a2918532d..525be324f509c 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs @@ -113,7 +113,7 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // This function takes the address of a local variable taken. Although this // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: + // heuristic adds stack smashing protection. This is also the case in C++: // ``` // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk // #include @@ -186,7 +186,7 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // Even though the local variable conceptually has its address taken, as // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with + // is easily inlined. There is therefore no stack smashing protection even with // the `strong` heuristic. // all: __security_check_cookie diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs index e9d12753a6916..40f4c58de43c9 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs @@ -9,7 +9,7 @@ //@ [none] compile-flags: -C stack-protector=none //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -// NOTE: the heuristics for stack smash protection inappropriately rely on types in LLVM IR, +// NOTE: the heuristics for stack smashing protection inappropriately rely on types in LLVM IR, // despite those types having no semantic meaning. This means that the `basic` and `strong` // settings do not behave in a coherent way. This is a known issue in LLVM. // See comments on https://github.com/rust-lang/rust/issues/114903. @@ -120,7 +120,7 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // This function takes the address of a local variable taken. Although this // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: + // heuristic adds stack smashing protection. This is also the case in C++: // ``` // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk // #include @@ -171,7 +171,7 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // Even though the local variable conceptually has its address taken, as // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with + // is easily inlined. There is therefore no stack smashing protection even with // the `strong` heuristic. // all: __stack_chk_fail diff --git a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs index 91753e7d4343c..34b3ee10902e1 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs @@ -1,4 +1,4 @@ -// Test that stack smash protection code is emitted for all tier1 and tier2 +// Test that stack smashing protection code is emitted for all tier1 and tier2 // targets, with the exception of nvptx64-nvidia-cuda // //@ add-core-stubs From 29eea0979e1fc9bd89b25f0f866b9c293b31183f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 13 Sep 2025 15:58:18 +0000 Subject: [PATCH 6/6] add comments for why we dont have basic/plain mode --- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- src/doc/rustc/src/codegen-options/index.md | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 93b75dafe1a8d..c66b77a506973 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -287,7 +287,7 @@ impl CodegenBackend for LlvmCodegenBackend { buffer overflow (even in the presence of undefined behavior). This provides similar security guarantees to Clang's - `-fstack-protector=strong`. + `-fstack-protector-strong`. The exact rules are unstable and subject to change, but currently, it generates stack protectors for functions that, diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 2d105d2670bcc..f98400e8e27d1 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -687,7 +687,7 @@ Supported values for this option are: buffer overflow (even in the presence of undefined behavior). This provides similar security guarantees to Clang's - `-fstack-protector=strong`. + `-fstack-protector-strong`. The exact rules are unstable and subject to change, but currently, it generates stack protectors for functions that, @@ -697,6 +697,15 @@ Supported values for this option are: determined by static control flow). - `all`: Generate stack canaries in all functions +rustc does not have a mode equivalent to Clang's (or GCC's) +plain `-fstack-protector` - `-fstack-protector` is an older heuristic +designed for C, that only protects functions that allocate a +`char buf[N];` buffer on the stack, making it prone to buffer overflows +from length miscalculations. This heuristic is poorly suited for Rust +code. Even in C codebases, `-fstack-protector-strong` is nowadays +preferred because plain `-fstack-protector` misses many stack +buffer overflows. + Stack protectors are not supported on many GPU targets, use of stack protectors on these targets is an error.