tentzen created this revision.
tentzen added reviewers: rnk, eli.friedman, JosephTremoulet, asmith.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
This change fixed a SEH bug (exposed by test58 & test61 in MSVC test xcpt4u.c);
when an Except-filter is located inside a finally, the frame-pointer generated
today via intrinsic @llvm.eh.recoverfp is the frame-pointer of the immediate
parent _finally, not the frame-ptr of outermost host function.
The fix is to retrieve the Establisher's frame-pointer that was previously
saved in parent's frame.
The prolog of a filter inside a _finally should be like:
%0 = call i8* @llvm.eh.recoverfp(i8* bitcast (@"?fin$0@0@main@@"), i8*
%frame_pointer)
%1 = call i8* @llvm.localrecover(i8* bitcast (@"?fin$0@0@main@@"), i8* %0,
i32 0)
%2 = bitcast i8* %1 to i8**
%3 = load i8*, i8** %2, align 8
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D77982
Files:
clang/lib/CodeGen/CGException.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/test/CodeGen/windows-seh-filter-inFinally.c
Index: clang/test/CodeGen/windows-seh-filter-inFinally.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-filter-inFinally.c
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-windows -fms-extensions -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: %[[dst:[0-9-]+]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (i8, i8*)* @"?fin$0@0@main@@" to i8*), i8* %frame_pointer)
+// CHECK-NEXT: %[[dst1:[0-9-]+]] = call i8* @llvm.localrecover(i8* bitcast (void (i8, i8*)* @"?fin$0@0@main@@" to i8*), i8* %[[dst]], i32 0)
+// CHECK-NEXT: %[[dst2:[0-9-]+]] = bitcast i8* %[[dst1]] to i8**
+// CHECK-NEXT: = load i8*, i8** %[[dst2]], align 8
+
+int
+main(int argc, char *argv[])
+{
+ int Counter = 0;
+ //
+ // Try/except within the finally clause of a try/finally.
+ //
+ __try {
+ Counter -= 1;
+ }
+ __finally {
+ __try {
+ Counter += 2;
+ // RtlRaiseStatus(STATUS_INTEGER_OVERFLOW);
+ } __except(Counter) {
+ __try {
+ Counter += 3;
+ }
+ __finally {
+ if (abnormal_termination() == 1) {
+ Counter += 5;
+ }
+ }
+ }
+ }
+ // expect Counter == 9
+ return 1;
+}
+
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -367,6 +367,9 @@
CodeGenModule &CGM; // Per-module state.
const TargetInfo &Target;
+ // For outliner helper only
+ CodeGenFunction *ParentCGF = nullptr;
+
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
LoopInfoStack LoopStack;
CGBuilderTy Builder;
Index: clang/lib/CodeGen/CGException.cpp
===================================================================
--- clang/lib/CodeGen/CGException.cpp
+++ clang/lib/CodeGen/CGException.cpp
@@ -1794,6 +1794,40 @@
llvm::Constant *ParentI8Fn =
llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP});
+
+ // if the parent is a _finally, need to retrive Establisher's FP,
+ // 2nd paramenter, saved & named frame_pointer in parent's frame
+ if (ParentCGF.ParentCGF != NULL) {
+ // Locate and escape Parent's frame_pointer.addr alloca
+ llvm::AllocaInst *FramePtrAddrAlloca = nullptr;
+ for (llvm::Instruction &I : ParentCGF.CurFn->getEntryBlock()) {
+ llvm::AllocaInst *II = dyn_cast<llvm::AllocaInst>(&I);
+ if (II && II->getName().startswith("frame_pointer")) {
+ FramePtrAddrAlloca = II;
+ break;
+ }
+ }
+ assert(FramePtrAddrAlloca);
+ auto InsertPair = ParentCGF.EscapedLocals.insert(
+ std::make_pair(FramePtrAddrAlloca, ParentCGF.EscapedLocals.size()));
+ int FrameEscapeIdx = InsertPair.first->second;
+
+ // an example of a filter's prolog::
+ // %0 = call i8 * @llvm.eh.recoverfp(i8 * bitcast(@"?fin$0@0@main@@"), i8 * %frame_pointer)
+ // %1 = call i8 * @llvm.localrecover(i8 * bitcast(@"?fin$0@0@main@@"), i8 * %0, i32 0)
+ // %2 = bitcast i8 * %1 to i8 **
+ // %3 = load i8*, i8 * *%2, align 8
+ // ==> %3 is the frame-pointer of outermost host function
+ llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
+ &CGM.getModule(), llvm::Intrinsic::localrecover);
+ llvm::Constant *ParentI8Fn =
+ llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
+ ParentFP = Builder.CreateCall(
+ FrameRecoverFn, {ParentI8Fn, ParentFP,
+ llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});
+ ParentFP = Builder.CreateBitCast(ParentFP, CGM.VoidPtrPtrTy);
+ ParentFP = Builder.CreateLoad(Address(ParentFP, getPointerAlign()));
+ }
}
// Create llvm.localrecover calls for all captures.
@@ -1992,6 +2026,7 @@
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
+ HelperCGF.ParentCGF = this;
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
// Outline the finally block.
llvm::Function *FinallyFunc =
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits