[clang] [WinEH] Fix crash when aligning parameters larger than ABI (PR #180905)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 11 09:00:54 PDT 2026


https://github.com/GkvJwa updated https://github.com/llvm/llvm-project/pull/180905

>From 9881686aeba91a427b1baa2084db3076ac3b16ed Mon Sep 17 00:00:00 2001
From: GkvJwa <gkvjwa at gmail.com>
Date: Wed, 11 Mar 2026 13:26:48 +0800
Subject: [PATCH 1/2] [WinEH] Fix crash when aligning parameters larger than
 ABI

---
 clang/lib/CodeGen/CGException.cpp             | 34 ++++++++++++----
 .../CodeGen/windows-seh-arg-capture-crash.cpp | 40 +++++++++++++++++++
 2 files changed, 67 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/CodeGen/windows-seh-arg-capture-crash.cpp

diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 98bc6ea34b0bc..1437bc2d32159 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -1834,10 +1834,27 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
 Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
                                                    Address ParentVar,
                                                    llvm::Value *ParentFP) {
-  llvm::CallInst *RecoverCall = nullptr;
+  llvm::Value *RecoverCall = nullptr;
   CGBuilderTy Builder(CGM, AllocaInsertPt);
-  if (auto *ParentAlloca =
-          dyn_cast_or_null<llvm::AllocaInst>(ParentVar.getBasePointer())) {
+  // We are currently handling the following case:
+  // ParentAlloca: An alloca for a local variable/direct argument
+  // ParentArg: An argument pointer, pointing to an argument passed indirectly
+  // Other case: A call to localrecover, if this is a nested __try.
+  auto *ParentAlloca =
+      dyn_cast_or_null<llvm::AllocaInst>(ParentVar.getBasePointer());
+  auto *ParentArg =
+      dyn_cast_or_null<llvm::Argument>(ParentVar.getBasePointer());
+  if (!ParentAlloca) {
+    if (ParentArg) {
+      llvm::BasicBlock &EntryBB = ParentCGF.CurFn->getEntryBlock();
+      llvm::IRBuilder<> ParentEntryBuilder(&EntryBB, EntryBB.begin());
+      ParentAlloca = ParentEntryBuilder.CreateAlloca(
+          ParentArg->getType(), nullptr, ParentArg->getName() + ".spill");
+      ParentEntryBuilder.CreateStore(ParentArg, ParentAlloca);
+    }
+  }
+
+  if (ParentAlloca) {
     // Mark the variable escaped if nobody else referenced it and compute the
     // localescape index.
     auto InsertPair = ParentCGF.EscapedLocals.insert(
@@ -1849,7 +1866,9 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
     RecoverCall = Builder.CreateCall(
         FrameRecoverFn, {ParentCGF.CurFn, ParentFP,
                          llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});
-
+    if (ParentArg)
+      RecoverCall = Builder.CreateLoad(
+          Address(RecoverCall, ParentArg->getType(), getPointerAlign()));
   } else {
     // If the parent didn't have an alloca, we're doing some nested outlining.
     // Just clone the existing localrecover call, but tweak the FP argument to
@@ -1858,9 +1877,10 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
         ParentVar.emitRawPointer(*this)->stripPointerCasts());
     assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover &&
            "expected alloca or localrecover in parent LocalDeclMap");
-    RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
-    RecoverCall->setArgOperand(1, ParentFP);
-    RecoverCall->insertBefore(AllocaInsertPt->getIterator());
+    RecoverCall = ParentRecover->clone();
+    cast<llvm::CallInst>(RecoverCall)->setArgOperand(1, ParentFP);
+    cast<llvm::CallInst>(RecoverCall)
+        ->insertBefore(AllocaInsertPt->getIterator());
   }
 
   // Bitcast the variable, rename it, and insert it in the local decl map.
diff --git a/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp b/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
new file mode 100644
index 0000000000000..2e7490c2db0c9
--- /dev/null
+++ b/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions -fexceptions -emit-llvm -o - %s | FileCheck %s
+
+class span_a {
+ public:
+  char data_;
+  int size_;
+};
+
+long g(span_a input);
+
+void f(span_a input) {
+  __try {
+  } __except (g(input)) {
+  }
+}
+
+// CHECK-LABEL: define dso_local void @"?f@@YAXVspan_a@@@Z"(i64 %input.coerce)
+// CHECK: entry:
+// CHECK:   call void (...) @llvm.localescape(ptr %input)
+
+typedef __SIZE_TYPE__ size_t;
+
+class span_b {
+ public:
+  char data_;
+  size_t size_;
+};
+
+long g(span_b input);
+
+void f(span_b input) {
+  __try {
+  } __except (g(input)) {
+  }
+}
+
+// CHECK-LABEL: define dso_local void @"?f@@YAXVspan_b@@@Z"(ptr noundef dead_on_return %input)
+// CHECK: entry:
+// CHECK:   %input.spill = alloca ptr, align 8
+// CHECK:   call void (...) @llvm.localescape(ptr %input.spill)

>From d770a3b8717e0730576b687c4bb3d6a8bc9b6da4 Mon Sep 17 00:00:00 2001
From: GkvJwa <gkvjwa at gmail.com>
Date: Thu, 12 Mar 2026 00:00:30 +0800
Subject: [PATCH 2/2] Add localrecover and load

---
 .../CodeGen/windows-seh-arg-capture-crash.cpp    | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp b/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
index 2e7490c2db0c9..089d966c86969 100644
--- a/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
+++ b/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
@@ -18,6 +18,14 @@ void f(span_a input) {
 // CHECK: entry:
 // CHECK:   call void (...) @llvm.localescape(ptr %input)
 
+// CHECK-LABEL: define internal noundef i32 @"?filt$0 at 0@f@@"(ptr noundef %exception_pointers
+// CHECK: entry:
+// CHECK:   %frame_pointer.addr = alloca ptr, align 8
+// CHECK:   %exception_pointers.addr = alloca ptr, align 8
+// CHECK:   %0 = call ptr @llvm.eh.recoverfp(ptr @"?f@@YAXVspan_a@@@Z", ptr %frame_pointer)
+// CHECK:   %input = call ptr @llvm.localrecover(ptr @"?f@@YAXVspan_a@@@Z", ptr %0, i32 0)
+
+
 typedef __SIZE_TYPE__ size_t;
 
 class span_b {
@@ -38,3 +46,11 @@ void f(span_b input) {
 // CHECK: entry:
 // CHECK:   %input.spill = alloca ptr, align 8
 // CHECK:   call void (...) @llvm.localescape(ptr %input.spill)
+
+// CHECK-LABEL: define internal noundef i32 @"?filt$0 at 0@f@@.1"(ptr noundef %exception_pointers
+// CHECK: entry:
+// CHECK:   %frame_pointer.addr = alloca ptr, align 8
+// CHECK:   %exception_pointers.addr = alloca ptr, align 8
+// CHECK:   %0 = call ptr @llvm.eh.recoverfp(ptr @"?f@@YAXVspan_b@@@Z", ptr %frame_pointer)
+// CHECK:   %1 = call ptr @llvm.localrecover(ptr @"?f@@YAXVspan_b@@@Z", ptr %0, i32 0)
+// CHECK:   %input = load ptr, ptr %1, align 8



More information about the cfe-commits mailing list