[llvm] Skip stack protectors on alloca's which have new metadata to opt out (PR #170229)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 19 09:30:19 PST 2025


https://github.com/cooperp updated https://github.com/llvm/llvm-project/pull/170229

>From 8d4f042b861a944eddc754b8ceca5183e86e8efd Mon Sep 17 00:00:00 2001
From: Peter Cooper <peter_cooper at apple.com>
Date: Sat, 8 Nov 2025 18:32:38 -0800
Subject: [PATCH] Use the stack_protector metadata to skip alloca's which don't
 need protection.

This is the LLVM piece of this work.  The clang work permitted the no_stack_protector
attribute on local variables. That generated new metadata which is used here to
skip any alloca's which would otherwise require a stack protector.
---
 llvm/docs/LangRef.rst                         | 17 ++++++
 llvm/lib/CodeGen/StackProtector.cpp           |  5 ++
 .../AArch64/stack-protector-metadata.ll       | 55 +++++++++++++++++++
 3 files changed, 77 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/stack-protector-metadata.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 02865f8a29c67..932db29169b0b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8670,6 +8670,23 @@ denoting if the type contains a pointer.
 
   !0 = !{!"<type-name>", i1 <contains-pointer>}
 
+'``stack-protector``' Metadata
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``stack-protector`` metadata may be attached to alloca instructions.  An
+alloca instruction with this metadata and value `i32 0` will be skipped when
+deciding whether a given function requires a stack protector.  The function
+may still use a stack protector, if other criteria determine it needs one.
+
+The metadata contains an integer, where a 0 value opts the given alloca out
+of requiring a stack protector.
+
+.. code-block:: none
+
+   %a = alloca [1000 x i8], align 1, !stack-protector !0
+
+  !0 = !{i32 0}
+
 Module Flags Metadata
 =====================
 
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index 5fd5d6cce23df..9ddd61b0f20ef 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -431,6 +431,11 @@ bool SSPLayoutAnalysis::requiresStackProtector(Function *F,
   for (const BasicBlock &BB : *F) {
     for (const Instruction &I : BB) {
       if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
+        if (const MDNode *MD = AI->getMetadata("stack-protector")) {
+          const auto *CI = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0));
+          if (CI->isZero())
+            continue;
+        }
         if (AI->isArrayAllocation()) {
           auto RemarkBuilder = [&]() {
             return OptimizationRemark(DEBUG_TYPE, "StackProtectorAllocaOrArray",
diff --git a/llvm/test/CodeGen/AArch64/stack-protector-metadata.ll b/llvm/test/CodeGen/AArch64/stack-protector-metadata.ll
new file mode 100644
index 0000000000000..95473be6d7999
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/stack-protector-metadata.ll
@@ -0,0 +1,55 @@
+; RUN: llc -mtriple=aarch64-apple-darwin < %s -o - | FileCheck %s
+
+ at .str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; CHECK-LABEL: test1:
+; CHECK-NOT: ___stack_chk_guard
+
+; Function Attrs: noinline nounwind optnone
+define void @test1(ptr noundef %msg) #0 {
+entry:
+  %msg.addr = alloca ptr, align 8
+  %a = alloca [1000 x i8], align 1, !stack-protector !2
+  store ptr %msg, ptr %msg.addr, align 8
+  %arraydecay = getelementptr inbounds [1000 x i8], ptr %a, i64 0, i64 0
+  %0 = load ptr, ptr %msg.addr, align 8
+  %call = call ptr @strcpy(ptr noundef %arraydecay, ptr noundef %0) #3
+  %arraydecay1 = getelementptr inbounds [1000 x i8], ptr %a, i64 0, i64 0
+  %call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %arraydecay1)
+  ret void
+}
+
+
+; CHECK-LABEL: test2:
+; CHECK: ___stack_chk_guard
+
+; Function Attrs: noinline nounwind optnone
+define void @test2(ptr noundef %msg) #0 {
+entry:
+  %msg.addr = alloca ptr, align 8
+  %b = alloca [1000 x i8], align 1
+  store ptr %msg, ptr %msg.addr, align 8
+  %arraydecay = getelementptr inbounds [1000 x i8], ptr %b, i64 0, i64 0
+  %0 = load ptr, ptr %msg.addr, align 8
+  %call = call ptr @strcpy(ptr noundef %arraydecay, ptr noundef %0) #3
+  %arraydecay1 = getelementptr inbounds [1000 x i8], ptr %b, i64 0, i64 0
+  %call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %arraydecay1)
+  ret void
+}
+
+; Function Attrs: nounwind
+declare ptr @strcpy(ptr noundef, ptr noundef) #1
+
+declare i32 @printf(ptr noundef, ...) #2
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" ssp }
+attributes #1 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #3 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 22.0.0"}
+!2 = !{i32 0}



More information about the llvm-commits mailing list