summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/CFG.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-08-04 23:54:30 +0000
committerTed Kremenek <kremenek@apple.com>2010-08-04 23:54:30 +0000
commit60fa657aa2460c114ec4e9fb35e02f5b3798d87e (patch)
treee6d75e461efddd535c1b8ad7cc812cf7b05e8956 /clang/lib/Analysis/CFG.cpp
parentc8bd9c277bf9946870b69333edd21a25aa482048 (diff)
downloadbcm5719-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.cpp37
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) {
OpenPOWER on IntegriCloud