https://github.com/cooperp updated https://github.com/llvm/llvm-project/pull/173311
>From 1d8b79c0eb131ec470827b51e8f03e47cac53014 Mon Sep 17 00:00:00 2001 From: Peter Cooper <[email protected]> Date: Sat, 8 Nov 2025 10:14:14 -0800 Subject: [PATCH 1/3] Allow the no_stack_protector attribute on local variables. This attribute is currently only permitted on functions, but sometimes it can be useful to opt out a specific local variable. That way the function can still get a stack protector if other locals require it, but locals which are opted out won't have the overhead of a stack protector if not needed. --- clang/include/clang/Basic/Attr.td | 2 +- clang/lib/CodeGen/CGDecl.cpp | 8 ++++++ clang/test/CodeGen/stack-protector-vars.c | 25 +++++++++++++++++++ ...a-attribute-supported-attributes-list.test | 2 +- clang/test/Sema/no_stack_protector.c | 7 +++++- 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/stack-protector-vars.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b017906a8d690..2a31626ca2471 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2726,7 +2726,7 @@ def : MutualExclusions<[AlwaysInline, NotTailCalled]>; def NoStackProtector : InheritableAttr { let Spellings = [Clang<"no_stack_protector">, CXX11<"gnu", "no_stack_protector">, C23<"gnu", "no_stack_protector">, Declspec<"safebuffers">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, LocalVar]>; let Documentation = [NoStackProtectorDocs]; let SimpleHandler = 1; } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 8b1cd83af2396..ae8ca92d8860f 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1604,6 +1604,14 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { allocaAlignment, D.getName(), /*ArraySize=*/nullptr, &AllocaAddr); + if (D.hasAttr<NoStackProtectorAttr>()) { + if (auto *AI = dyn_cast<llvm::AllocaInst>(address.getBasePointer())) { + llvm::LLVMContext &Ctx = Builder.getContext(); + auto *Operand = llvm::ConstantAsMetadata::get(Builder.getInt32(0)); + AI->setMetadata("stack-protector", llvm::MDNode::get(Ctx, {Operand})); + } + } + // Don't emit lifetime markers for MSVC catch parameters. The lifetime of // the catch parameter starts in the catchpad instruction, and we can't // insert code in those basic blocks. diff --git a/clang/test/CodeGen/stack-protector-vars.c b/clang/test/CodeGen/stack-protector-vars.c new file mode 100644 index 0000000000000..218cdc33b3010 --- /dev/null +++ b/clang/test/CodeGen/stack-protector-vars.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +typedef __SIZE_TYPE__ size_t; + +int printf(const char * _Format, ...); +char *strcpy(char *s1, const char *s2); + +// CHECK: define {{.*}}void @test1 +// CHECK: %a = alloca [1000 x i8], align 1, !stack-protector ![[A:.*]] +void test1(const char *msg) { + __attribute__((no_stack_protector)) + char a[1000]; + strcpy(a, msg); + printf("%s\n", a); +} + +// CHECK: define {{.*}}void @test2 +// CHECK-NOT: %b = alloca [1000 x i8], align 1, !stack-protector +void test2(const char *msg) { + char b[1000]; + strcpy(b, msg); + printf("%s\n", b); +} + +// CHECK: ![[A]] = !{i32 0} \ No newline at end of file diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 3114d2fc9e693..6420a298f4dc9 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -138,7 +138,7 @@ // CHECK-NEXT: NoSanitizeThread (SubjectMatchRule_function) // CHECK-NEXT: NoSpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: NoSplitStack (SubjectMatchRule_function) -// CHECK-NEXT: NoStackProtector (SubjectMatchRule_function) +// CHECK-NEXT: NoStackProtector (SubjectMatchRule_function, SubjectMatchRule_variable_is_local) // CHECK-NEXT: NoThreadSafetyAnalysis (SubjectMatchRule_function) // CHECK-NEXT: NoThrow (SubjectMatchRule_hasType_functionType) // CHECK-NEXT: NoUwtable (SubjectMatchRule_hasType_functionType) diff --git a/clang/test/Sema/no_stack_protector.c b/clang/test/Sema/no_stack_protector.c index 1ecd46bc624ce..fab3df667883a 100644 --- a/clang/test/Sema/no_stack_protector.c +++ b/clang/test/Sema/no_stack_protector.c @@ -4,5 +4,10 @@ [[clang::no_stack_protector]] void test2(void) {} void __attribute__((no_stack_protector)) foo(void) {} -int __attribute__((no_stack_protector)) var; // expected-warning {{'no_stack_protector' attribute only applies to functions}} +int __attribute__((no_stack_protector)) var; // expected-warning {{'no_stack_protector' attribute only applies to functions and local variables}} void __attribute__((no_stack_protector(2))) bar(void) {} // expected-error {{'no_stack_protector' attribute takes no arguments}} + +void func() +{ + int __attribute__((no_stack_protector)) localvar; +} \ No newline at end of file >From 69c6d23ecac2e95933d7b03234151c1d3001cb1e Mon Sep 17 00:00:00 2001 From: Peter Cooper <[email protected]> Date: Tue, 6 Jan 2026 21:15:58 -0800 Subject: [PATCH 2/3] newlines --- clang/test/CodeGen/stack-protector-vars.c | 2 +- clang/test/Sema/no_stack_protector.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CodeGen/stack-protector-vars.c b/clang/test/CodeGen/stack-protector-vars.c index 218cdc33b3010..03ffb32f807d2 100644 --- a/clang/test/CodeGen/stack-protector-vars.c +++ b/clang/test/CodeGen/stack-protector-vars.c @@ -22,4 +22,4 @@ void test2(const char *msg) { printf("%s\n", b); } -// CHECK: ![[A]] = !{i32 0} \ No newline at end of file +// CHECK: ![[A]] = !{i32 0} diff --git a/clang/test/Sema/no_stack_protector.c b/clang/test/Sema/no_stack_protector.c index fab3df667883a..d6b0c4d8bc208 100644 --- a/clang/test/Sema/no_stack_protector.c +++ b/clang/test/Sema/no_stack_protector.c @@ -10,4 +10,4 @@ void __attribute__((no_stack_protector(2))) bar(void) {} // expected-error {{'n void func() { int __attribute__((no_stack_protector)) localvar; -} \ No newline at end of file +} >From 4ec8dfdc4ef035f121d088484c6f7d241e810994 Mon Sep 17 00:00:00 2001 From: Peter Cooper <[email protected]> Date: Tue, 6 Jan 2026 21:32:49 -0800 Subject: [PATCH 3/3] Add new StackProtectorIgnore and StackProtectorIgnoreDocs --- clang/include/clang/Basic/Attr.td | 9 ++++++++- clang/include/clang/Basic/AttrDocs.td | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 2a31626ca2471..525a883f5987c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2726,11 +2726,18 @@ def : MutualExclusions<[AlwaysInline, NotTailCalled]>; def NoStackProtector : InheritableAttr { let Spellings = [Clang<"no_stack_protector">, CXX11<"gnu", "no_stack_protector">, C23<"gnu", "no_stack_protector">, Declspec<"safebuffers">]; - let Subjects = SubjectList<[Function, LocalVar]>; + let Subjects = SubjectList<[Function]>; let Documentation = [NoStackProtectorDocs]; let SimpleHandler = 1; } +def StackProtectorIgnore : InheritableAttr { + let Spellings = [Clang<"stack_protector_ignore">]; + let Subjects = SubjectList<[LocalVar]>; + let Documentation = [StackProtectorIgnoreDocs]; + let SimpleHandler = 1; +} + def StrictGuardStackCheck : InheritableAttr { let Spellings = [Declspec<"strict_gs_check">]; let Subjects = SubjectList<[Function]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 812b48058d189..79b872c6bbe78 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5736,6 +5736,17 @@ option. }]; } +def StackProtectorIgnoreDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``stack_protector_ignore`` attribute skips analysis of the given local +variable when determining if a function should use a stack protector. + +If ``-fstack-protector-all`` is specified then the given function will still +use a stack protector, even if some/all variables have this attribute. + }]; +} + def StrictGuardStackCheckDocs : Documentation { let Category = DocCatFunction; let Content = [{ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
