[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