[llvm] [CodeGen] Generalize trap emission after SP check fail (PR #109744)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 24 20:03:51 PDT 2024


https://github.com/duk-37 updated https://github.com/llvm/llvm-project/pull/109744

>From 8f5a1e7336bd793307267cb5b882555f8ae067b8 Mon Sep 17 00:00:00 2001
From: duk <37 at cmail.nu>
Date: Tue, 24 Sep 2024 21:22:46 -0400
Subject: [PATCH] [CodeGen] Generalize trap instruction emission after SP check
 fail

Generalize some target-specific code that emits traps after stack protector failure in SelectionDAG/GlobalIsel and add some tests.
---
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  | 15 +++----
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 13 ++----
 ...slator-stack-protector-trap-unreachable.ll | 28 ++++++++++++
 .../stack-protector-trap-unreachable.ll       | 36 ++++++++++++++++
 .../X86/stack-protector-trap-unreachable.ll   | 43 +++++++++++++++++++
 llvm/test/CodeGen/X86/unreachable-trap.ll     | 10 ++++-
 6 files changed, 125 insertions(+), 20 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll
 create mode 100644 llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll
 create mode 100644 llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll

diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 8e860a1f740295..8486d9a1477eb6 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3807,16 +3807,11 @@ bool IRTranslator::emitSPDescriptorFailure(StackProtectorDescriptor &SPD,
     return false;
   }
 
-  // On PS4/PS5, the "return address" must still be within the calling
-  // function, even if it's at the very end, so emit an explicit TRAP here.
-  // WebAssembly needs an unreachable instruction after a non-returning call,
-  // because the function return type can be different from __stack_chk_fail's
-  // return type (void).
-  const TargetMachine &TM = MF->getTarget();
-  if (TM.getTargetTriple().isPS() || TM.getTargetTriple().isWasm()) {
-    LLVM_DEBUG(dbgs() << "Unhandled trap emission for stack protector fail\n");
-    return false;
-  }
+  // Emit a trap instruction if we are required to do so.
+  const TargetOptions &TargetOpts = TLI->getTargetMachine().Options;
+  if (TargetOpts.TrapUnreachable && !TargetOpts.NoTrapAfterNoreturn)
+    CurBuilder->buildInstr(TargetOpcode::G_TRAP);
+
   return true;
 }
 
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 25213f587116d5..5004756c0ab9c1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3183,15 +3183,10 @@ SelectionDAGBuilder::visitSPDescriptorFailure(StackProtectorDescriptor &SPD) {
   SDValue Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL,
                                   MVT::isVoid, {}, CallOptions, getCurSDLoc())
                       .second;
-  // On PS4/PS5, the "return address" must still be within the calling
-  // function, even if it's at the very end, so emit an explicit TRAP here.
-  // Passing 'true' for doesNotReturn above won't generate the trap for us.
-  if (TM.getTargetTriple().isPS())
-    Chain = DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, Chain);
-  // WebAssembly needs an unreachable instruction after a non-returning call,
-  // because the function return type can be different from __stack_chk_fail's
-  // return type (void).
-  if (TM.getTargetTriple().isWasm())
+
+  // Emit a trap instruction if we are required to do so.
+  const TargetOptions &TargetOpts = DAG.getTarget().Options;
+  if (TargetOpts.TrapUnreachable && !TargetOpts.NoTrapAfterNoreturn)
     Chain = DAG.getNode(ISD::TRAP, getCurSDLoc(), MVT::Other, Chain);
 
   DAG.setRoot(Chain);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll
new file mode 100644
index 00000000000000..23cd168fd48e3e
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-trap-unreachable.ll
@@ -0,0 +1,28 @@
+; NOTE: Do not autogenerate, we'd lose the .Lfunc_end0 -NEXT checks otherwise.
+;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
+
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs \
+; RUN:     -trap-unreachable=false -o - %s | FileCheck -check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck -check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck -check-prefix=TRAP_UNREACHABLE %s
+
+define void @test() nounwind ssp {
+; NO_TRAP_UNREACHABLE-LABEL: test:
+; NO_TRAP_UNREACHABLE:         bl __stack_chk_fail
+; NO_TRAP_UNREACHABLE-NOT:     brk #0x1
+; NO_TRAP_UNREACHABLE-NEXT:  .Lfunc_end0
+;
+; TRAP_UNREACHABLE-LABEL: test:
+; TRAP_UNREACHABLE:         bl __stack_chk_fail
+; TRAP_UNREACHABLE-NEXT:    brk #0x1
+; TRAP_UNREACHABLE-NEXT:  .Lfunc_end0
+
+entry:
+  %buf = alloca [8 x i8]
+  %2 = call i32(ptr) @callee(ptr %buf) nounwind
+  ret void
+}
+
+declare i32 @callee(ptr) nounwind
diff --git a/llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll b/llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll
new file mode 100644
index 00000000000000..0aeb962f7c3e13
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/stack-protector-trap-unreachable.ll
@@ -0,0 +1,36 @@
+; NOTE: Do not autogenerate, we'd lose the .Lfunc_end0 -NEXT checks otherwise.
+;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
+
+; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+;; Make sure FastISel doesn't break anything.
+; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs \
+; RUN:     -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=aarch64 -fast-isel -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+define void @test() nounwind ssp {
+; NO_TRAP_UNREACHABLE-LABEL: test:
+; NO_TRAP_UNREACHABLE:         bl __stack_chk_fail
+; NO_TRAP_UNREACHABLE-NOT:     brk #0x1
+; NO_TRAP_UNREACHABLE-NEXT:  .Lfunc_end0
+;
+; TRAP_UNREACHABLE-LABEL: test:
+; TRAP_UNREACHABLE:         bl __stack_chk_fail
+; TRAP_UNREACHABLE-NEXT:    brk #0x1
+; TRAP_UNREACHABLE-NEXT:  .Lfunc_end0
+
+entry:
+  %buf = alloca [8 x i8]
+  %2 = call i32(ptr) @callee(ptr %buf) nounwind
+  ret void
+}
+
+declare i32 @callee(ptr) nounwind
diff --git a/llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll b/llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll
new file mode 100644
index 00000000000000..f24e9b1cc3740a
--- /dev/null
+++ b/llvm/test/CodeGen/X86/stack-protector-trap-unreachable.ll
@@ -0,0 +1,43 @@
+; NOTE: Do not autogenerate, we'd lose the .Lfunc_end0 -NEXT checks otherwise.
+;; Make sure we emit trap instructions after stack protector checks iff NoTrapAfterNoReturn is false.
+
+; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -enable-selectiondag-sp=false -mtriple=x86_64 -fast-isel=false -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+;; Make sure FastISel doesn't break anything.
+; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable=false -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn -o - %s | FileCheck --check-prefix=NO_TRAP_UNREACHABLE %s
+; RUN: llc -mtriple=x86_64 -fast-isel -global-isel=false -verify-machineinstrs \
+; RUN:     -trap-unreachable -no-trap-after-noreturn=false -o - %s | FileCheck --check-prefix=TRAP_UNREACHABLE %s
+
+define void @test() nounwind ssp {
+; NO_TRAP_UNREACHABLE-LABEL: test:
+; NO_TRAP_UNREACHABLE:         callq __stack_chk_fail
+; NO_TRAP_UNREACHABLE-NOT:     ud2
+; NO_TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+
+; TRAP_UNREACHABLE-LABEL: test:
+; TRAP_UNREACHABLE:         callq __stack_chk_fail
+; TRAP_UNREACHABLE-NEXT:    ud2
+; TRAP_UNREACHABLE-NEXT: .Lfunc_end0
+
+entry:
+  %buf = alloca [8 x i8]
+  %2 = call i32(ptr) @callee(ptr %buf) nounwind
+  ret void
+}
+
+declare i32 @callee(ptr) nounwind
diff --git a/llvm/test/CodeGen/X86/unreachable-trap.ll b/llvm/test/CodeGen/X86/unreachable-trap.ll
index d2704bf7b46205..486ee0f7a0e246 100644
--- a/llvm/test/CodeGen/X86/unreachable-trap.ll
+++ b/llvm/test/CodeGen/X86/unreachable-trap.ll
@@ -1,7 +1,15 @@
 ; RUN: llc -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK
 ; RUN: llc -o - %s -mtriple=x86_64-windows-msvc | FileCheck %s --check-prefixes=CHECK
-; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
 ; RUN: llc -o - %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefixes=CHECK,NO_TRAP_AFTER_NORETURN
+
+; On PS4/PS5, always emit trap instructions regardless of of trap-unreachable or no-trap-after-noreturn.
+; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-scei-ps4 -trap-unreachable -no-trap-after-noreturn=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+; RUN: llc -o - %s -mtriple=x86_64-sie-ps5 -trap-unreachable -no-trap-after-noreturn=false | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
+
 ; RUN: llc --trap-unreachable -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
 ; RUN: llc --trap-unreachable -global-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN
 ; RUN: llc --trap-unreachable -fast-isel -o - %s -mtriple=x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,TRAP_AFTER_NORETURN



More information about the llvm-commits mailing list