Skip to content

StackProtector: Use RuntimeLibcalls to query libcall names #147913

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

Open
wants to merge 1 commit into
base: users/arsenm/runtime-libcalls/add-openbsd-stack-protector-tests
Choose a base branch
from

Conversation

arsenm
Copy link
Contributor

@arsenm arsenm commented Jul 10, 2025

The compiler should not introduce calls to arbitrary strings
that aren't defined in RuntimeLibcalls. Previously OpenBSD was
disabling the default __stack_chk_fail, but there was no record
of the alternative __stack_smash_handler function it emits instead.

This also avoids a random triple check in the pass.

The compiler should not introduce calls to arbitrary strings
that aren't defined in RuntimeLibcalls. Previously OpenBSD was
disabling the default __stack_chk_fail, but there was no record
of the alternative __stack_smash_handler function it emits instead.

This also avoids a random triple check in the pass.
Copy link
Contributor Author

arsenm commented Jul 10, 2025

@llvmbot
Copy link
Member

llvmbot commented Jul 10, 2025

@llvm/pr-subscribers-backend-nvptx
@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-backend-loongarch

@llvm/pr-subscribers-backend-powerpc

Author: Matt Arsenault (arsenm)

Changes

The compiler should not introduce calls to arbitrary strings
that aren't defined in RuntimeLibcalls. Previously OpenBSD was
disabling the default __stack_chk_fail, but there was no record
of the alternative __stack_smash_handler function it emits instead.

This also avoids a random triple check in the pass.


Full diff: https://github.com/llvm/llvm-project/pull/147913.diff

4 Files Affected:

  • (modified) llvm/include/llvm/IR/RuntimeLibcalls.td (+4)
  • (modified) llvm/lib/CodeGen/StackProtector.cpp (+18-10)
  • (modified) llvm/lib/IR/RuntimeLibcalls.cpp (+1)
  • (added) llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll (+10)
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index a954dde9fb223..f7598979ca4c5 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -334,6 +334,7 @@ defset list<RuntimeLibcall> LibCalls__OutOfLineAtomic = {
 
 // Stack Protector Fail
 def STACKPROTECTOR_CHECK_FAIL : RuntimeLibcall;
+def STACK_SMASH_HANDLER : RuntimeLibcall;
 
 // Deoptimization
 def DEOPTIMIZE : RuntimeLibcall;
@@ -918,6 +919,9 @@ def bzero : RuntimeLibcallImpl<BZERO>;
 def __bzero : RuntimeLibcallImpl<BZERO>;
 def _Unwind_SjLj_Resume : RuntimeLibcallImpl<UNWIND_RESUME>;
 
+// Used on OpenBSD
+def __stack_smash_handler : RuntimeLibcallImpl<STACK_SMASH_HANDLER>;
+
 //===----------------------------------------------------------------------===//
 // F128 libm Runtime Libcalls
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index 5f866eea7d4e7..3ec70083b7043 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -76,7 +76,7 @@ static bool InsertStackProtectors(const TargetMachine *TM, Function *F,
 
 /// CreateFailBB - Create a basic block to jump to when the stack protector
 /// check fails.
-static BasicBlock *CreateFailBB(Function *F, const Triple &Trip);
+static BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI);
 
 bool SSPLayoutInfo::shouldEmitSDCheck(const BasicBlock &BB) const {
   return HasPrologue && !HasIRCheck && isa<ReturnInst>(BB.getTerminator());
@@ -673,7 +673,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
       // merge pass will merge together all of the various BB into one including
       // fail BB generated by the stack protector pseudo instruction.
       if (!FailBB)
-        FailBB = CreateFailBB(F, TM->getTargetTriple());
+        FailBB = CreateFailBB(F, *TLI);
 
       IRBuilder<> B(CheckLoc);
       Value *Guard = getStackGuard(TLI, M, B);
@@ -706,7 +706,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
   return HasPrologue;
 }
 
-BasicBlock *CreateFailBB(Function *F, const Triple &Trip) {
+BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
   auto *M = F->getParent();
   LLVMContext &Context = F->getContext();
   BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
@@ -716,17 +716,25 @@ BasicBlock *CreateFailBB(Function *F, const Triple &Trip) {
         DILocation::get(Context, 0, 0, F->getSubprogram()));
   FunctionCallee StackChkFail;
   SmallVector<Value *, 1> Args;
-  if (Trip.isOSOpenBSD()) {
-    StackChkFail = M->getOrInsertFunction("__stack_smash_handler",
-                                          Type::getVoidTy(Context),
+
+  if (const char *ChkFailName =
+          TLI.getLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
+    StackChkFail =
+        M->getOrInsertFunction(ChkFailName, Type::getVoidTy(Context));
+  } else if (const char *SSHName =
+                 TLI.getLibcallName(RTLIB::STACK_SMASH_HANDLER)) {
+    StackChkFail = M->getOrInsertFunction(SSHName, Type::getVoidTy(Context),
                                           PointerType::getUnqual(Context));
     Args.push_back(B.CreateGlobalString(F->getName(), "SSH"));
   } else {
-    StackChkFail =
-        M->getOrInsertFunction("__stack_chk_fail", Type::getVoidTy(Context));
+    Context.emitError("no libcall available for stack protector");
   }
-  cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);
-  B.CreateCall(StackChkFail, Args);
+
+  if (StackChkFail) {
+    cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);
+    B.CreateCall(StackChkFail, Args);
+  }
+
   B.CreateUnreachable();
   return FailBB;
 }
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index fdc183a6b09ce..f9bd9b6029234 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -272,6 +272,7 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
 
   if (TT.isOSOpenBSD()) {
     setLibcallImpl(RTLIB::STACKPROTECTOR_CHECK_FAIL, RTLIB::Unsupported);
+    setLibcallImpl(RTLIB::STACK_SMASH_HANDLER, RTLIB::__stack_smash_handler);
   }
 
   if (TT.isOSWindows() && !TT.isOSCygMing()) {
diff --git a/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
new file mode 100644
index 0000000000000..f877d95dd3769
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
@@ -0,0 +1,10 @@
+; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes=stack-protector %s 2>&1 | FileCheck %s
+
+; CHECK: error: no libcall available for stack protector
+define void @func() sspreq nounwind {
+  %alloca = alloca i32, align 4
+  call void @capture(ptr %alloca)
+  ret void
+}
+
+declare void @capture(ptr)

@llvmbot
Copy link
Member

llvmbot commented Jul 10, 2025

@llvm/pr-subscribers-backend-arm

Author: Matt Arsenault (arsenm)

Changes

The compiler should not introduce calls to arbitrary strings
that aren't defined in RuntimeLibcalls. Previously OpenBSD was
disabling the default __stack_chk_fail, but there was no record
of the alternative __stack_smash_handler function it emits instead.

This also avoids a random triple check in the pass.


Full diff: https://github.com/llvm/llvm-project/pull/147913.diff

4 Files Affected:

  • (modified) llvm/include/llvm/IR/RuntimeLibcalls.td (+4)
  • (modified) llvm/lib/CodeGen/StackProtector.cpp (+18-10)
  • (modified) llvm/lib/IR/RuntimeLibcalls.cpp (+1)
  • (added) llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll (+10)
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index a954dde9fb223..f7598979ca4c5 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -334,6 +334,7 @@ defset list<RuntimeLibcall> LibCalls__OutOfLineAtomic = {
 
 // Stack Protector Fail
 def STACKPROTECTOR_CHECK_FAIL : RuntimeLibcall;
+def STACK_SMASH_HANDLER : RuntimeLibcall;
 
 // Deoptimization
 def DEOPTIMIZE : RuntimeLibcall;
@@ -918,6 +919,9 @@ def bzero : RuntimeLibcallImpl<BZERO>;
 def __bzero : RuntimeLibcallImpl<BZERO>;
 def _Unwind_SjLj_Resume : RuntimeLibcallImpl<UNWIND_RESUME>;
 
+// Used on OpenBSD
+def __stack_smash_handler : RuntimeLibcallImpl<STACK_SMASH_HANDLER>;
+
 //===----------------------------------------------------------------------===//
 // F128 libm Runtime Libcalls
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index 5f866eea7d4e7..3ec70083b7043 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -76,7 +76,7 @@ static bool InsertStackProtectors(const TargetMachine *TM, Function *F,
 
 /// CreateFailBB - Create a basic block to jump to when the stack protector
 /// check fails.
-static BasicBlock *CreateFailBB(Function *F, const Triple &Trip);
+static BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI);
 
 bool SSPLayoutInfo::shouldEmitSDCheck(const BasicBlock &BB) const {
   return HasPrologue && !HasIRCheck && isa<ReturnInst>(BB.getTerminator());
@@ -673,7 +673,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
       // merge pass will merge together all of the various BB into one including
       // fail BB generated by the stack protector pseudo instruction.
       if (!FailBB)
-        FailBB = CreateFailBB(F, TM->getTargetTriple());
+        FailBB = CreateFailBB(F, *TLI);
 
       IRBuilder<> B(CheckLoc);
       Value *Guard = getStackGuard(TLI, M, B);
@@ -706,7 +706,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
   return HasPrologue;
 }
 
-BasicBlock *CreateFailBB(Function *F, const Triple &Trip) {
+BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
   auto *M = F->getParent();
   LLVMContext &Context = F->getContext();
   BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
@@ -716,17 +716,25 @@ BasicBlock *CreateFailBB(Function *F, const Triple &Trip) {
         DILocation::get(Context, 0, 0, F->getSubprogram()));
   FunctionCallee StackChkFail;
   SmallVector<Value *, 1> Args;
-  if (Trip.isOSOpenBSD()) {
-    StackChkFail = M->getOrInsertFunction("__stack_smash_handler",
-                                          Type::getVoidTy(Context),
+
+  if (const char *ChkFailName =
+          TLI.getLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
+    StackChkFail =
+        M->getOrInsertFunction(ChkFailName, Type::getVoidTy(Context));
+  } else if (const char *SSHName =
+                 TLI.getLibcallName(RTLIB::STACK_SMASH_HANDLER)) {
+    StackChkFail = M->getOrInsertFunction(SSHName, Type::getVoidTy(Context),
                                           PointerType::getUnqual(Context));
     Args.push_back(B.CreateGlobalString(F->getName(), "SSH"));
   } else {
-    StackChkFail =
-        M->getOrInsertFunction("__stack_chk_fail", Type::getVoidTy(Context));
+    Context.emitError("no libcall available for stack protector");
   }
-  cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);
-  B.CreateCall(StackChkFail, Args);
+
+  if (StackChkFail) {
+    cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);
+    B.CreateCall(StackChkFail, Args);
+  }
+
   B.CreateUnreachable();
   return FailBB;
 }
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index fdc183a6b09ce..f9bd9b6029234 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -272,6 +272,7 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
 
   if (TT.isOSOpenBSD()) {
     setLibcallImpl(RTLIB::STACKPROTECTOR_CHECK_FAIL, RTLIB::Unsupported);
+    setLibcallImpl(RTLIB::STACK_SMASH_HANDLER, RTLIB::__stack_smash_handler);
   }
 
   if (TT.isOSWindows() && !TT.isOSCygMing()) {
diff --git a/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
new file mode 100644
index 0000000000000..f877d95dd3769
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
@@ -0,0 +1,10 @@
+; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes=stack-protector %s 2>&1 | FileCheck %s
+
+; CHECK: error: no libcall available for stack protector
+define void @func() sspreq nounwind {
+  %alloca = alloca i32, align 4
+  call void @capture(ptr %alloca)
+  ret void
+}
+
+declare void @capture(ptr)

@llvmbot
Copy link
Member

llvmbot commented Jul 10, 2025

@llvm/pr-subscribers-backend-x86

Author: Matt Arsenault (arsenm)

Changes

The compiler should not introduce calls to arbitrary strings
that aren't defined in RuntimeLibcalls. Previously OpenBSD was
disabling the default __stack_chk_fail, but there was no record
of the alternative __stack_smash_handler function it emits instead.

This also avoids a random triple check in the pass.


Full diff: https://github.com/llvm/llvm-project/pull/147913.diff

4 Files Affected:

  • (modified) llvm/include/llvm/IR/RuntimeLibcalls.td (+4)
  • (modified) llvm/lib/CodeGen/StackProtector.cpp (+18-10)
  • (modified) llvm/lib/IR/RuntimeLibcalls.cpp (+1)
  • (added) llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll (+10)
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index a954dde9fb223..f7598979ca4c5 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -334,6 +334,7 @@ defset list<RuntimeLibcall> LibCalls__OutOfLineAtomic = {
 
 // Stack Protector Fail
 def STACKPROTECTOR_CHECK_FAIL : RuntimeLibcall;
+def STACK_SMASH_HANDLER : RuntimeLibcall;
 
 // Deoptimization
 def DEOPTIMIZE : RuntimeLibcall;
@@ -918,6 +919,9 @@ def bzero : RuntimeLibcallImpl<BZERO>;
 def __bzero : RuntimeLibcallImpl<BZERO>;
 def _Unwind_SjLj_Resume : RuntimeLibcallImpl<UNWIND_RESUME>;
 
+// Used on OpenBSD
+def __stack_smash_handler : RuntimeLibcallImpl<STACK_SMASH_HANDLER>;
+
 //===----------------------------------------------------------------------===//
 // F128 libm Runtime Libcalls
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index 5f866eea7d4e7..3ec70083b7043 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -76,7 +76,7 @@ static bool InsertStackProtectors(const TargetMachine *TM, Function *F,
 
 /// CreateFailBB - Create a basic block to jump to when the stack protector
 /// check fails.
-static BasicBlock *CreateFailBB(Function *F, const Triple &Trip);
+static BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI);
 
 bool SSPLayoutInfo::shouldEmitSDCheck(const BasicBlock &BB) const {
   return HasPrologue && !HasIRCheck && isa<ReturnInst>(BB.getTerminator());
@@ -673,7 +673,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
       // merge pass will merge together all of the various BB into one including
       // fail BB generated by the stack protector pseudo instruction.
       if (!FailBB)
-        FailBB = CreateFailBB(F, TM->getTargetTriple());
+        FailBB = CreateFailBB(F, *TLI);
 
       IRBuilder<> B(CheckLoc);
       Value *Guard = getStackGuard(TLI, M, B);
@@ -706,7 +706,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
   return HasPrologue;
 }
 
-BasicBlock *CreateFailBB(Function *F, const Triple &Trip) {
+BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
   auto *M = F->getParent();
   LLVMContext &Context = F->getContext();
   BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
@@ -716,17 +716,25 @@ BasicBlock *CreateFailBB(Function *F, const Triple &Trip) {
         DILocation::get(Context, 0, 0, F->getSubprogram()));
   FunctionCallee StackChkFail;
   SmallVector<Value *, 1> Args;
-  if (Trip.isOSOpenBSD()) {
-    StackChkFail = M->getOrInsertFunction("__stack_smash_handler",
-                                          Type::getVoidTy(Context),
+
+  if (const char *ChkFailName =
+          TLI.getLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
+    StackChkFail =
+        M->getOrInsertFunction(ChkFailName, Type::getVoidTy(Context));
+  } else if (const char *SSHName =
+                 TLI.getLibcallName(RTLIB::STACK_SMASH_HANDLER)) {
+    StackChkFail = M->getOrInsertFunction(SSHName, Type::getVoidTy(Context),
                                           PointerType::getUnqual(Context));
     Args.push_back(B.CreateGlobalString(F->getName(), "SSH"));
   } else {
-    StackChkFail =
-        M->getOrInsertFunction("__stack_chk_fail", Type::getVoidTy(Context));
+    Context.emitError("no libcall available for stack protector");
   }
-  cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);
-  B.CreateCall(StackChkFail, Args);
+
+  if (StackChkFail) {
+    cast<Function>(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);
+    B.CreateCall(StackChkFail, Args);
+  }
+
   B.CreateUnreachable();
   return FailBB;
 }
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index fdc183a6b09ce..f9bd9b6029234 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -272,6 +272,7 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
 
   if (TT.isOSOpenBSD()) {
     setLibcallImpl(RTLIB::STACKPROTECTOR_CHECK_FAIL, RTLIB::Unsupported);
+    setLibcallImpl(RTLIB::STACK_SMASH_HANDLER, RTLIB::__stack_smash_handler);
   }
 
   if (TT.isOSWindows() && !TT.isOSCygMing()) {
diff --git a/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
new file mode 100644
index 0000000000000..f877d95dd3769
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
@@ -0,0 +1,10 @@
+; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes=stack-protector %s 2>&1 | FileCheck %s
+
+; CHECK: error: no libcall available for stack protector
+define void @func() sspreq nounwind {
+  %alloca = alloca i32, align 4
+  call void @capture(ptr %alloca)
+  ret void
+}
+
+declare void @capture(ptr)

@arsenm arsenm marked this pull request as ready for review July 10, 2025 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants