[clang] 5b1eed6 - [WinEH] Fix crash when aligning parameters larger than ABI (#180905)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 11 19:53:37 PDT 2026
Author: GkvJwa
Date: 2026-03-12T10:53:32+08:00
New Revision: 5b1eed6278de1fffa195978b017039add70a94e3
URL: https://github.com/llvm/llvm-project/commit/5b1eed6278de1fffa195978b017039add70a94e3
DIFF: https://github.com/llvm/llvm-project/commit/5b1eed6278de1fffa195978b017039add70a94e3.diff
LOG: [WinEH] Fix crash when aligning parameters larger than ABI (#180905)
Fix #180648 caused by an unhandled `Argument` for parameters exceeding
ABI size limits. This patch explicitly emits an `alloca` for the `Argument` in
the entry block to ensure correct address resolution.
Added:
clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
Modified:
clang/lib/CodeGen/CGException.cpp
Removed:
################################################################################
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..089d966c86969
--- /dev/null
+++ b/clang/test/CodeGen/windows-seh-arg-capture-crash.cpp
@@ -0,0 +1,56 @@
+// 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)
+
+// 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 {
+ 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)
+
+// 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