diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-08-04 23:54:30 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-08-04 23:54:30 +0000 |
commit | 0fc67e2d619088945ac71e9d2590d5158650885d (patch) | |
tree | 7119798657f438552d55ba79a61502467ca55686 /lib/Analysis/CFG.cpp | |
parent | 65005536dee9216b14e2361153a14ddd8a7cd50a (diff) |
Fix CFGBuilder to not blow out the stack when processing deeply nested CaseStmts. Fixes <rdar://problem/8268753>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110286 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFG.cpp')
-rw-r--r-- | lib/Analysis/CFG.cpp | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 821a578dbc..f8f26f6107 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1617,9 +1617,30 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { // CaseStmts are essentially labels, so they are the first statement in a // block. + CFGBlock *TopBlock = 0, *LastBlock = 0; + + if (Stmt *Sub = CS->getSubStmt()) { + // For deeply nested chains of CaseStmts, instead of doing a recursion + // (which can blow out the stack), manually unroll and create blocks + // along the way. + while (isa<CaseStmt>(Sub)) { + CFGBlock *CurrentBlock = createBlock(false); + CurrentBlock->setLabel(CS); + + if (TopBlock) + AddSuccessor(LastBlock, CurrentBlock); + else + TopBlock = CurrentBlock; + + AddSuccessor(SwitchTerminatedBlock, CurrentBlock); + LastBlock = CurrentBlock; - if (CS->getSubStmt()) - addStmt(CS->getSubStmt()); + CS = cast<CaseStmt>(Sub); + Sub = CS->getSubStmt(); + } + + addStmt(Sub); + } CFGBlock* CaseBlock = Block; if (!CaseBlock) @@ -1640,10 +1661,16 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { // We set Block to NULL to allow lazy creation of a new block (if necessary) Block = NULL; - // This block is now the implicit successor of other blocks. - Succ = CaseBlock; + if (TopBlock) { + AddSuccessor(LastBlock, CaseBlock); + Succ = TopBlock; + } + else { + // This block is now the implicit successor of other blocks. + Succ = CaseBlock; + } - return CaseBlock; + return Succ; } CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { |