<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Jul 22, 2015 at 1:34 PM, Vedant Kumar <span dir="ltr"><<a href="mailto:vsk@apple.com" target="_blank">vsk@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>Large CFGs cause clang::Sema::checkForFunctionCall() to stack overflow.<br></div></div></blockquote><div>Is the code that produces the large CFG available?  It may be useful to test that other users of the CFG can cope with processing the code. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>
<br>
I have a patch which breaks the recursion in checkForFunctionCall() by manually<br>
managing the call stack. This fixes the problem. The check-clang target reports<br>
no regressions.<br>
<br>
I don't have commit rights, so I'd appreciate someone taking a look at the<br>
patch and getting it into trunk :).<br>
<br>
thanks!<br>
vedant<br>
<br>
================================================================================<br>
<br>
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp<br>
index f2ff48a..dc6dda0 100644<br>
--- a/lib/Sema/AnalysisBasedWarnings.cpp<br>
+++ b/lib/Sema/AnalysisBasedWarnings.cpp<br>
@@ -52,6 +52,8 @@<br>
#include <deque><br>
#include <iterator><br>
#include <vector><br>
+#include <functional><br>
+#include <utility><br>
<br>
using namespace clang;<br>
<br>
@@ -175,59 +177,69 @@ static void checkForFunctionCall(Sema &S, const FunctionDecl *FD,<br>
                                 CFGBlock &Block, unsigned ExitID,<br>
                                 llvm::SmallVectorImpl<RecursiveState> &States,<br>
                                 RecursiveState State) {<br>
-  unsigned ID = Block.getBlockID();<br>
+  std::vector<std::pair<std::reference_wrapper<CFGBlock>, RecursiveState>><br>
+      Stack;<br>
+  Stack.emplace_back(std::make_pair(std::ref(Block), State));<br>
<br>
-  // A block's state can only move to a higher state.<br>
-  if (States[ID] >= State)<br>
-    return;<br>
+  while (!Stack.empty()) {<br>
+    CFGBlock &CurBlock = Stack.back().first.get();<br>
+    RecursiveState CurState = Stack.back().second;<br>
+    Stack.pop_back();<br>
<br>
-  States[ID] = State;<br>
+    unsigned ID = CurBlock.getBlockID();<br>
<br>
-  // Found a path to the exit node without a recursive call.<br>
-  if (ID == ExitID && State == FoundPathWithNoRecursiveCall)<br>
-    return;<br>
+    // A block's state can only move to a higher state.<br>
+    if (States[ID] >= CurState)<br>
+      continue;<br>
<br>
-  if (State == FoundPathWithNoRecursiveCall) {<br>
-    // If the current state is FoundPathWithNoRecursiveCall, the successors<br>
-    // will be either FoundPathWithNoRecursiveCall or FoundPath.  To determine<br>
-    // which, process all the Stmt's in this block to find any recursive calls.<br>
-    for (const auto &B : Block) {<br>
-      if (B.getKind() != CFGElement::Statement)<br>
-        continue;<br>
+    States[ID] = CurState;<br>
+<br>
+    // Found a path to the exit node without a recursive call.<br>
+    if (ID == ExitID && CurState == FoundPathWithNoRecursiveCall)<br>
+      continue;<br>
+<br>
+    if (CurState == FoundPathWithNoRecursiveCall) {<br>
+      // If the current state is FoundPathWithNoRecursiveCall, the successors<br>
+      // will be either FoundPathWithNoRecursiveCall or FoundPath.  To determine<br>
+      // which, process all the Stmt's in this block to find any recursive<br>
+      // calls.<br>
+      for (const auto &B : CurBlock) {<br>
+        if (B.getKind() != CFGElement::Statement)<br>
+          continue;<br>
<br>
-      const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());<br>
-      if (CE && CE->getCalleeDecl() &&<br>
-          CE->getCalleeDecl()->getCanonicalDecl() == FD) {<br>
-<br>
-        // Skip function calls which are qualified with a templated class.<br>
-        if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(<br>
-                CE->getCallee()->IgnoreParenImpCasts())) {<br>
-          if (NestedNameSpecifier *NNS = DRE->getQualifier()) {<br>
-            if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&<br>
-                isa<TemplateSpecializationType>(NNS->getAsType())) {<br>
-               continue;<br>
+        const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());<br>
+        if (CE && CE->getCalleeDecl() &&<br>
+            CE->getCalleeDecl()->getCanonicalDecl() == FD) {<br>
+<br>
+          // Skip function calls which are qualified with a templated class.<br>
+          if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(<br>
+                  CE->getCallee()->IgnoreParenImpCasts())) {<br>
+            if (NestedNameSpecifier *NNS = DRE->getQualifier()) {<br>
+              if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&<br>
+                  isa<TemplateSpecializationType>(NNS->getAsType())) {<br>
+                continue;<br>
+              }<br>
            }<br>
          }<br>
-        }<br>
<br>
-        if (const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE)) {<br>
-          if (isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||<br>
-              !MCE->getMethodDecl()->isVirtual()) {<br>
-            State = FoundPath;<br>
+          if (const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE)) {<br>
+            if (isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||<br>
+                !MCE->getMethodDecl()->isVirtual()) {<br>
+              CurState = FoundPath;<br>
+              break;<br>
+            }<br>
+          } else {<br>
+            CurState = FoundPath;<br>
            break;<br>
          }<br>
-        } else {<br>
-          State = FoundPath;<br>
-          break;<br>
        }<br>
      }<br>
    }<br>
-  }<br>
<br>
-  for (CFGBlock::succ_iterator I = Block.succ_begin(), E = Block.succ_end();<br>
-       I != E; ++I)<br>
-    if (*I)<br>
-      checkForFunctionCall(S, FD, **I, ExitID, States, State);<br>
+    for (auto I = CurBlock.succ_rbegin(), E = CurBlock.succ_rend(); I != E; ++I)<br>
+      if (*I)<br>
+        Stack.emplace_back(std::make_pair(std::ref(**I), CurState));<br>
+  }<br>
}<br>
<br>
static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,<br>
_______________________________________________<br>
</div></div>cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" target="_blank">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>