]> granicus.if.org Git - clang/commitdiff
Fix CFGBuilder to not blow out the stack when processing deeply nested CaseStmts...
authorTed Kremenek <kremenek@apple.com>
Wed, 4 Aug 2010 23:54:30 +0000 (23:54 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 4 Aug 2010 23:54:30 +0000 (23:54 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110286 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFG.cpp

index 821a578dbcfc0dabf317d09a6bbf0191c1c12dfb..f8f26f61075c7d19d83dd2d5d42bacd3b993eae5 100644 (file)
@@ -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) {