diff options
author | Ten Tzen <tentzen@microsoft.com> | 2020-07-12 01:37:56 -0700 |
---|---|---|
committer | Ten Tzen <tentzen@microsoft.com> | 2020-07-12 01:37:56 -0700 |
commit | 66f1dcd872dba189ee054fb016f4bff535fb5afc (patch) | |
tree | fbdef482c2cbd8f08808296ae1a5db16d9f224ec /clang/lib/CodeGen/CGException.cpp | |
parent | 6634aef71f3b5e9820d2955bd6b39d2744de06eb (diff) | |
download | llvm-66f1dcd872dba189ee054fb016f4bff535fb5afc.zip llvm-66f1dcd872dba189ee054fb016f4bff535fb5afc.tar.gz llvm-66f1dcd872dba189ee054fb016f4bff535fb5afc.tar.bz2 |
[Windows SEH] Fix the frame-ptr of a nested-filter within a _finally
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 code below:
%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
Differential Revision: https://reviews.llvm.org/D77982
Diffstat (limited to 'clang/lib/CodeGen/CGException.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGException.cpp | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 2494f38..bdf7025 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -1815,6 +1815,48 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, llvm::Constant *ParentI8Fn = llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP}); + + // if the parent is a _finally, the passed-in ParentFP is the FP + // of parent _finally, not Establisher's FP (FP of outermost function). + // Establkisher FP is 2nd paramenter passed into parent _finally. + // Fortunately, it's always saved in parent's frame. The following + // code retrieves it, and escapes it so that spill instruction won't be + // optimized away. + if (ParentCGF.ParentCGF != nullptr) { + // Locate and escape Parent's frame_pointer.addr alloca + // Depending on target, should be 1st/2nd one in LocalDeclMap. + // Let's just scan for ImplicitParamDecl with VoidPtrTy. + llvm::AllocaInst *FramePtrAddrAlloca = nullptr; + for (auto &I : ParentCGF.LocalDeclMap) { + const VarDecl *D = cast<VarDecl>(I.first); + if (isa<ImplicitParamDecl>(D) && + D->getType() == getContext().VoidPtrTy) { + assert(D->getName().startswith("frame_pointer")); + FramePtrAddrAlloca = cast<llvm::AllocaInst>(I.second.getPointer()); + 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(bitcast(@"?fin$0@0@main@@"),..) + // %1 = call i8* @llvm.localrecover(bitcast(@"?fin$0@0@main@@"),..) + // %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. @@ -2013,6 +2055,7 @@ void CodeGenFunction::pushSEHCleanup(CleanupKind Kind, 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 = |