From fe2f7f367a09cc5b0330b87c0f0b0078a0700a8f Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Mon, 29 Feb 2016 22:56:36 +0000 Subject: [PATCH] [Verifier] Handle more funclet edge cases This change makes the verifier a little more paranoid. It was possible to trick the verifier into crashing or infinite looping. llvm-svn: 262268 --- llvm/lib/IR/Verifier.cpp | 15 +++++++----- llvm/test/Verifier/invalid-eh.ll | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index f02879e..8367a27 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3119,8 +3119,6 @@ void Verifier::visitLandingPadInst(LandingPadInst &LPI) { } void Verifier::visitCatchPadInst(CatchPadInst &CPI) { - visitEHPadPredecessors(CPI); - BasicBlock *BB = CPI.getParent(); Function *F = BB->getParent(); @@ -3136,6 +3134,7 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) { Assert(BB->getFirstNonPHI() == &CPI, "CatchPadInst not the first non-PHI instruction in the block.", &CPI); + visitEHPadPredecessors(CPI); visitFuncletPadInst(CPI); } @@ -3148,8 +3147,6 @@ void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) { } void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) { - visitEHPadPredecessors(CPI); - BasicBlock *BB = CPI.getParent(); Function *F = BB->getParent(); @@ -3166,6 +3163,7 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) { Assert(isa(ParentPad) || isa(ParentPad), "CleanupPadInst has an invalid parent.", &CPI); + visitEHPadPredecessors(CPI); visitFuncletPadInst(CPI); } @@ -3173,8 +3171,12 @@ void Verifier::visitFuncletPadInst(FuncletPadInst &FPI) { User *FirstUser = nullptr; Value *FirstUnwindPad = nullptr; SmallVector Worklist({&FPI}); + std::set Seen; + while (!Worklist.empty()) { FuncletPadInst *CurrentPad = Worklist.pop_back_val(); + Assert(Seen.insert(CurrentPad).second, + "FuncletPadInst must not be nested within itself", CurrentPad); Value *UnresolvedAncestorPad = nullptr; for (User *U : CurrentPad->users()) { BasicBlock *UnwindDest; @@ -3210,6 +3212,8 @@ void Verifier::visitFuncletPadInst(FuncletPadInst &FPI) { bool ExitsFPI; if (UnwindDest) { UnwindPad = UnwindDest->getFirstNonPHI(); + if (!cast(UnwindPad)->isEHPad()) + continue; Value *UnwindParent = getParentPad(UnwindPad); // Ignore unwind edges that don't exit CurrentPad. if (UnwindParent == CurrentPad) @@ -3323,8 +3327,6 @@ void Verifier::visitFuncletPadInst(FuncletPadInst &FPI) { } void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) { - visitEHPadPredecessors(CatchSwitch); - BasicBlock *BB = CatchSwitch.getParent(); Function *F = BB->getParent(); @@ -3362,6 +3364,7 @@ void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) { "CatchSwitchInst handlers must be catchpads", &CatchSwitch, Handler); } + visitEHPadPredecessors(CatchSwitch); visitTerminatorInst(CatchSwitch); } diff --git a/llvm/test/Verifier/invalid-eh.ll b/llvm/test/Verifier/invalid-eh.ll index 0f27198..f94e3a6 100644 --- a/llvm/test/Verifier/invalid-eh.ll +++ b/llvm/test/Verifier/invalid-eh.ll @@ -19,6 +19,9 @@ ; RUN: sed -e s/.T19:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK19 %s ; RUN: sed -e s/.T20:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK20 %s ; RUN: sed -e s/.T21:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK21 %s +; RUN: sed -e s/.T22:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK22 %s +; RUN: sed -e s/.T23:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK23 %s +; RUN: sed -e s/.T24:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK24 %s declare void @g() @@ -370,3 +373,50 @@ declare void @g() ;T21: %cp2 = catchpad within %cs [i32 2] ;T21: unreachable ;T21: } + +;T22: define void @f() personality void ()* @g { +;T22: invoke void @g() +;T22: to label %merge unwind label %cleanup +;T22: +;T22: cleanup: +;T22: %outer = cleanuppad within none [] +;T22: invoke void @g() [ "funclet"(token %outer) ] +;T22: to label %merge unwind label %merge +;T22: ; CHECK22: The unwind destination does not have an exception handling instruction! +;T22: ; CHECK22: invoke void @g() [ "funclet"(token %outer) ] +;T22: ; CHECK22: to label %merge unwind label %merge +;T22: +;T22: merge: +;T22: unreachable +;T22: } + +;T23: define void @f() personality void ()* @g { +;T23: invoke void @g() +;T23: to label %exit unwind label %pad +;T23: +;T23: pad: +;T23: %outer = catchpad within %outer [] +;T23: ; CHECK23: CatchPadInst needs to be directly nested in a CatchSwitchInst. +;T23: ; CHECK23: %outer = catchpad within %outer [] +;T23: unreachable +;T23: +;T23: exit: +;T23: unreachable +;T23: } + +;T24: define void @f() personality void ()* @g { +;T24: invoke void @g() +;T24: to label %exit unwind label %pad +;T24: ; CHECK24: A single unwind edge may only enter one EH pad +;T24: ; CHECK24: invoke void @g() +;T24: ; CHECK24: to label %exit unwind label %pad +;T24: +;T24: pad: +;T24: %outer = cleanuppad within %outer [] +;T24: ; CHECK24: FuncletPadInst must not be nested within itself +;T24: ; CHECK24: %outer = cleanuppad within %outer [] +;T24: unreachable +;T24: +;T24: exit: +;T24: unreachable +;T24: } -- 2.7.4