From: Nico Weber Date: Thu, 26 Feb 2015 22:34:33 +0000 (+0000) Subject: Don't crash on leaving nested __finally blocks through an EH edge. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c8347e9163ca02e9a02a58c9360fbcf20df1048d;p=clang Don't crash on leaving nested __finally blocks through an EH edge. The __finally emission block tries to be clever by removing unused continuation edges if there's an unconditional jump out of the __finally block. With exception edges, the EH continuation edge isn't always unused though and we'd crash in a few places. Just don't be clever. That makes the IR for __finally blocks a bit longer in some cases (hence small and behavior-preserving changes to existing tests), but it makes no difference in general and it fixes the last crash from PR22553. http://reviews.llvm.org/D7918 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@230697 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index f1ffa589f6..4e9eb326c1 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -1684,8 +1684,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { const char *RethrowName = Personality.CatchallRethrowFn; if (RethrowName != nullptr && !isCleanup) { EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName), - getExceptionFromSlot()) - ->setDoesNotReturn(); + getExceptionFromSlot())->setDoesNotReturn(); Builder.CreateUnreachable(); Builder.restoreIP(SavedIP); return EHResumeBlock; @@ -1943,23 +1942,17 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) { Builder.SetInsertPoint(FI.FinallyBB); EmitStmt(Finally->getBlock()); - // If the finally block doesn't fall through, we don't need these blocks. - if (!HaveInsertPoint()) { - FI.ContBB->eraseFromParent(); - if (FI.ResumeBB) - FI.ResumeBB->eraseFromParent(); - return; - } - - if (FI.ResumeBB) { - llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(), - "abnormal.termination"); - IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0)); - Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB); - } else { - // There was nothing exceptional in the try body, so we only have normal - // control flow. - Builder.CreateBr(FI.ContBB); + if (HaveInsertPoint()) { + if (FI.ResumeBB) { + llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(), + "abnormal.termination"); + IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0)); + Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB); + } else { + // There was nothing exceptional in the try body, so we only have normal + // control flow. + Builder.CreateBr(FI.ContBB); + } } Builder.restoreIP(SavedIP); diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c index 64b3ffdf18..1bb60d820a 100644 --- a/test/CodeGen/exceptions-seh-finally.c +++ b/test/CodeGen/exceptions-seh-finally.c @@ -193,12 +193,99 @@ int nested___finally___finally() { // CHECK-NEXT: br label %[[finally:[^ ]*]] // // CHECK: [[finally]] -// CHECK-NEXT: store i32 1, i32* % -// CHECK-NEXT: store i8 0, i8* % +// CHECK-NEXT: store i32 1, i32* % +// CHECK-NEXT: store i32 1, i32* % +// CHECK-NEXT: br label %[[cleanup:[^ ]*]] +// +// The finally's unreachable continuation block: +// CHECK: store i32 0, i32* % +// CHECK-NEXT: br label %[[cleanup]] +// +// CHECK: [[cleanup]] +// CHECK-NEXT: store i8 0, i8* % // CHECK-NEXT: br label %[[outerfinally:[^ ]*]] // // CHECK: [[outerfinally]] // CHECK-NEXT: br label %[[finallycont:[^ ]*]] // // CHECK: [[finallycont]] -// CHECK-NEXT: ret i32 1 +// CHECK-NEXT: %[[dest:[^ ]*]] = load i32* % +// CHECK-NEXT: switch i32 %[[dest]] +// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]] +// +// CHECK: [[cleanupcont]] +// CHECK-NEXT: store i32 0, i32* % +// CHECK-NEXT: br label %[[return:[^ ]*]] +// +// CHECK: [[return]] +// CHECK-NEXT: %[[reg:[^ ]*]] = load i32* % +// CHECK-NEXT: ret i32 %[[reg]] + +int nested___finally___finally_with_eh_edge() { + __try { + __try { + might_crash(); + } __finally { + return 899; + } + } __finally { + // Intentionally no return here. + } + return 912; +} +// CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge +// CHECK: invoke void @might_crash() #3 +// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// +// CHECK: [[invokecont]] +// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]] +// CHECK-NEXT: br label %[[finally:[^ ]*]] + +// CHECK: [[finally]] +// CHECK-NEXT: store i32 899, i32* % +// CHECK-NEXT: store i32 1, i32* % +// CHECK-NEXT: br label %[[cleanup:[^ ]*]] +// +// The inner finally's unreachable continuation block: +// CHECK: store i32 0, i32* % +// CHECK-NEXT: br label %[[cleanup]] +// +// CHECK: [[cleanup]] +// CHECK-NEXT: store i8 0, i8* % +// CHECK-NEXT: br label %[[outerfinally:[^ ]*]] +// +// CHECK: [[outerfinally]] +// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8* %[[abnormal]] +// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0 +// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]] +// +// CHECK: [[finallycont]] +// CHECK-NEXT: %[[dest:[^ ]*]] = load i32* % +// CHECK-NEXT: switch i32 %[[dest]] +// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]] +// +// CHECK: [[cleanupcont]] +// CHECK-NEXT: store i32 912, i32* % +// CHECK-NEXT: br label %[[return:[^ ]*]] +// +// +// CHECK: [[lpad]] +// CHECK-NEXT: landingpad +// CHECK-NEXT: cleanup +// CHECK: store i8 1, i8* %[[abnormal]] +// CHECK: br label %[[finally]] +// +// The inner finally's unreachable resume block: +// CHECK: store i8 1, i8* %[[abnormal]] +// CHECK-NEXT: br label %[[outerfinally]] +// +// CHECK: [[finallyresume]] +// CHECK-NEXT: br label %[[ehresume:[^ ]*]] +// +// CHECK: [[return]] +// CHECK-NEXT: %[[reg:[^ ]*]] = load i32* % +// CHECK-NEXT: ret i32 %[[reg]] +// +// The ehresume block, not reachable either. +// CHECK: [[ehresume]] +// CHECK: resume diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c index c590bd8703..7901c8c2fb 100644 --- a/test/CodeGen/exceptions-seh-leave.c +++ b/test/CodeGen/exceptions-seh-leave.c @@ -162,6 +162,13 @@ int nested___except___finally() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 +// Unused __finally continuation block +// CHECK: store i32 51, i32* % +// CHECK-NEXT: br label %[[tryleave]] + +// CHECK: [[tryleave]] +// CHECK-NEXT: br label %[[trycont:[^ ]*]] + // CHECK: [[g1_lpad]] // CHECK: store i8 1, i8* % // CHECK-NEXT: br label %[[finally]] @@ -171,14 +178,11 @@ int nested___except___finally() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: br label %[[trycont:[^ ]*]] +// CHECK-NEXT: br label %[[trycont]] // CHECK: [[trycont]] // CHECK-NEXT: ret i32 1 -// CHECK: [[tryleave]] -// CHECK-NEXT: br label %[[trycont]] - int nested___except___except() { int myres = 0; __try {