-
Notifications
You must be signed in to change notification settings - Fork 15.6k
Allow the no_stack_protector attribute on local variables #173311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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.
|
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: None (cooperp) ChangesThis 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. This is paired with an LLVM change which has already landed, which uses the new metadata to opt specific alloca instructions out of requiring a stack protector. Full diff: https://github.com/llvm/llvm-project/pull/173311.diff 5 Files Affected:
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index f85d2da21eab9..10cb3c64f54d2 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
|
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) ClangClang.CodeGen/stack-protector-vars.cIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
🪟 Windows x64 Test Results
Failed Tests(click on a test name to see its output) ClangClang.CodeGen/stack-protector-vars.cIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
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.
This is paired with an LLVM change which has already landed, which uses the new metadata to opt specific alloca instructions out of requiring a stack protector.