diff options
| author | Nico Weber <nicolasweber@gmx.de> | 2015-02-26 22:34:33 +0000 |
|---|---|---|
| committer | Nico Weber <nicolasweber@gmx.de> | 2015-02-26 22:34:33 +0000 |
| commit | ff62a6a0b79da24fe6336fe1dfbe1bc11d0a563a (patch) | |
| tree | 89207f1f0497d60acc34f2ad6825ec63583d6c54 | |
| parent | 653773d0048de921fbd5cf6a4aa2767a7cd9158a (diff) | |
| download | bcm5719-llvm-ff62a6a0b79da24fe6336fe1dfbe1bc11d0a563a.tar.gz bcm5719-llvm-ff62a6a0b79da24fe6336fe1dfbe1bc11d0a563a.zip | |
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
llvm-svn: 230697
| -rw-r--r-- | clang/lib/CodeGen/CGException.cpp | 31 | ||||
| -rw-r--r-- | clang/test/CodeGen/exceptions-seh-finally.c | 93 | ||||
| -rw-r--r-- | clang/test/CodeGen/exceptions-seh-leave.c | 12 |
3 files changed, 110 insertions, 26 deletions
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index f1ffa589f6e..4e9eb326c10 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/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/clang/test/CodeGen/exceptions-seh-finally.c b/clang/test/CodeGen/exceptions-seh-finally.c index 64b3ffdf187..1bb60d820a9 100644 --- a/clang/test/CodeGen/exceptions-seh-finally.c +++ b/clang/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/clang/test/CodeGen/exceptions-seh-leave.c b/clang/test/CodeGen/exceptions-seh-leave.c index c590bd87033..7901c8c2fbd 100644 --- a/clang/test/CodeGen/exceptions-seh-leave.c +++ b/clang/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 { |

