r186411 - Fixes another hard to test problem with iterator invalidation.

Manuel Klimek klimek at google.com
Tue Jul 16 06:20:30 PDT 2013


Author: klimek
Date: Tue Jul 16 08:20:30 2013
New Revision: 186411

URL: http://llvm.org/viewvc/llvm-project?rev=186411&view=rev
Log:
Fixes another hard to test problem with iterator invalidation.

As every match call can recursively call back into the memoized match
via a nested traversal matcher (for example:
stmt(hasAncestor(stmt(hasDescendant(stmt(hasDescendant(stmt()))))))),
and every memoization step might clear the cache, we must not store
iterators into the result cache when calling match on a submatcher.

Modified:
    cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=186411&r1=186410&r2=186411&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Tue Jul 16 08:20:30 2013
@@ -373,27 +373,31 @@ public:
                                   const DynTypedMatcher &Matcher,
                                   BoundNodesTreeBuilder *Builder, int MaxDepth,
                                   TraversalKind Traversal, BindKind Bind) {
+    // For AST-nodes that don't have an identity, we can't memoize.
+    if (!Node.getMemoizationData())
+      return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
+                                Bind);
+
     MatchKey Key;
     Key.MatcherID = Matcher.getID();
     Key.Node = Node;
     // Note that we key on the bindings *before* the match.
     Key.BoundNodes = *Builder;
 
-    // For AST-nodes that don't have an identity, we can't memoize.
-    if (!Node.getMemoizationData())
-      return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
-                                Bind);
-
-    std::pair<MemoizationMap::iterator, bool> InsertResult =
-        ResultCache.insert(std::make_pair(Key, MemoizedMatchResult()));
-    if (InsertResult.second) {
-      InsertResult.first->second.Nodes = *Builder;
-      InsertResult.first->second.ResultOfMatch =
-          matchesRecursively(Node, Matcher, &InsertResult.first->second.Nodes,
-                             MaxDepth, Traversal, Bind);
+    MemoizationMap::iterator I = ResultCache.find(Key);
+    if (I != ResultCache.end()) {
+      *Builder = I->second.Nodes;
+      return I->second.ResultOfMatch;
     }
-    *Builder = InsertResult.first->second.Nodes;
-    return InsertResult.first->second.ResultOfMatch;
+
+    MemoizedMatchResult Result;
+    Result.ResultOfMatch = false;
+    Result.Nodes = *Builder;
+    Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
+                                              MaxDepth, Traversal, Bind);
+    ResultCache[Key] = Result;
+    *Builder = Result.Nodes;
+    return Result.ResultOfMatch;
   }
 
   // Matches children or descendants of 'Node' with 'BaseMatcher'.
@@ -502,57 +506,62 @@ private:
     Key.MatcherID = Matcher.getID();
     Key.Node = Node;
     Key.BoundNodes = *Builder;
-    std::pair<MemoizationMap::iterator, bool> InsertResult =
-        ResultCache.insert(std::make_pair(Key, MemoizedMatchResult()));
-    if (InsertResult.second) {
-      bool Matches = false;
-      if (Parents.size() == 1) {
-        // Only one parent - do recursive memoization.
-        const ast_type_traits::DynTypedNode Parent = Parents[0];
-        BoundNodesTreeBuilder Result(*Builder);
-        if (Matcher.matches(Parent, this, &Result)) {
-          InsertResult.first->second.Nodes = Result;
-          Matches = true;
-        } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
-          Matches = memoizedMatchesAncestorOfRecursively(Parent, Matcher,
-                                                         Builder, MatchMode);
-          // Once we get back from the recursive call, the result will be the
-          // same as the parent's result.
-          InsertResult.first->second.Nodes = *Builder;
+
+    // Note that we cannot use insert and reuse the iterator, as recursive
+    // calls to match might invalidate the result cache iterators.
+    MemoizationMap::iterator I = ResultCache.find(Key);
+    if (I != ResultCache.end()) {
+      *Builder = I->second.Nodes;
+      return I->second.ResultOfMatch;
+    }
+    MemoizedMatchResult Result;
+    Result.ResultOfMatch = false;
+    Result.Nodes = *Builder;
+    if (Parents.size() == 1) {
+      // Only one parent - do recursive memoization.
+      const ast_type_traits::DynTypedNode Parent = Parents[0];
+      if (Matcher.matches(Parent, this, &Result.Nodes)) {
+        Result.ResultOfMatch = true;
+      } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+        // Reset the results to not include the bound nodes from the failed
+        // match above.
+        Result.Nodes = *Builder;
+        Result.ResultOfMatch = memoizedMatchesAncestorOfRecursively(
+            Parent, Matcher, &Result.Nodes, MatchMode);
+        // Once we get back from the recursive call, the result will be the
+        // same as the parent's result.
+      }
+    } else {
+      // Multiple parents - BFS over the rest of the nodes.
+      llvm::DenseSet<const void *> Visited;
+      std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
+                                                      Parents.end());
+      while (!Queue.empty()) {
+        Result.Nodes = *Builder;
+        if (Matcher.matches(Queue.front(), this, &Result.Nodes)) {
+          Result.ResultOfMatch = true;
+          break;
         }
-      } else {
-        // Multiple parents - BFS over the rest of the nodes.
-        llvm::DenseSet<const void *> Visited;
-        std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
-                                                        Parents.end());
-        while (!Queue.empty()) {
-          BoundNodesTreeBuilder Result(*Builder);
-          if (Matcher.matches(Queue.front(), this, &Result)) {
-            InsertResult.first->second.Nodes = Result;
-            Matches = true;
-            break;
-          }
-          if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
-            ASTContext::ParentVector Ancestors =
-                ActiveASTContext->getParents(Queue.front());
-            for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
-                                                          E = Ancestors.end();
-                 I != E; ++I) {
-              // Make sure we do not visit the same node twice.
-              // Otherwise, we'll visit the common ancestors as often as there
-              // are splits on the way down.
-              if (Visited.insert(I->getMemoizationData()).second)
-                Queue.push_back(*I);
-            }
+        if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+          ASTContext::ParentVector Ancestors =
+              ActiveASTContext->getParents(Queue.front());
+          for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
+                                                        E = Ancestors.end();
+               I != E; ++I) {
+            // Make sure we do not visit the same node twice.
+            // Otherwise, we'll visit the common ancestors as often as there
+            // are splits on the way down.
+            if (Visited.insert(I->getMemoizationData()).second)
+              Queue.push_back(*I);
           }
-          Queue.pop_front();
         }
+        Queue.pop_front();
       }
-
-      InsertResult.first->second.ResultOfMatch = Matches;
     }
-    *Builder = InsertResult.first->second.Nodes;
-    return InsertResult.first->second.ResultOfMatch;
+    ResultCache[Key] = Result;
+
+    *Builder = Result.Nodes;
+    return Result.ResultOfMatch;
   }
 
   // Implements a BoundNodesTree::Visitor that calls a MatchCallback with





More information about the cfe-commits mailing list