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 | 60fa657aa2460c114ec4e9fb35e02f5b3798d87e (patch) | |
tree | e6d75e461efddd535c1b8ad7cc812cf7b05e8956 /clang/lib/Analysis/CFG.cpp | |
parent | c8bd9c277bf9946870b69333edd21a25aa482048 (diff) | |
download | bcm5719-llvm-60fa657aa2460c114ec4e9fb35e02f5b3798d87e.tar.gz bcm5719-llvm-60fa657aa2460c114ec4e9fb35e02f5b3798d87e.zip |
Fix CFGBuilder to not blow out the stack when processing deeply nested CaseStmts. Fixes <rdar://problem/8268753>.
llvm-svn: 110286
Diffstat (limited to 'clang/lib/Analysis/CFG.cpp')
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 821a578dbcf..f8f26f61075 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/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) { |