Fix:

<rdar://problem/6914474> checker doesn't realize that variable might
have been assigned if a pointer to that variable was passed to another
function via a structure

The problem here was the RegionStoreManager::InvalidateRegion didn't
invalidate the bindings of invalidated regions.  This required a
rewrite of this method using a worklist.

As part of this fix, changed ValueManager::getConjuredSymbolVal() to
require a 'void*' SymbolTag argument.  This tag is used to
differentiate two different symbols created at the same location.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82920 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 75907da..6b7799c 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -436,69 +436,98 @@
   DVM = DVMFactory.Remove(DVM, R);
 }
 
-
 const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
                                                     const MemRegion *R,
-                                                    const Expr *E,
+                                                    const Expr *Ex,
                                                     unsigned Count) {
   ASTContext& Ctx = StateMgr.getContext();
 
   // Strip away casts.
   R = R->getBaseRegion();
 
-  // Remove the bindings to subregions.
-  {
-    // Get the mapping of regions -> subregions.
-    llvm::OwningPtr<RegionStoreSubRegionMap>
-      SubRegions(getRegionStoreSubRegionMap(state));
+  // Get the mapping of regions -> subregions.
+  llvm::OwningPtr<RegionStoreSubRegionMap>
+    SubRegions(getRegionStoreSubRegionMap(state));
+  
+  RegionBindings B = GetRegionBindings(state->getStore());
+  RegionDefaultBindings DVM = state->get<RegionDefaultValue>();
+  RegionDefaultBindings::Factory &DVMFactory =
+    state->get_context<RegionDefaultValue>();
+  
+  llvm::DenseMap<const MemRegion *, unsigned> Visited;
+  llvm::SmallVector<const MemRegion *, 10> WorkList;
+  WorkList.push_back(R);
+  
+  while (!WorkList.empty()) {
+    R = WorkList.back();
+    WorkList.pop_back();
+    
+    // Have we visited this region before?
+    unsigned &visited = Visited[R];
+    if (visited)
+      continue;
+    visited = 1;
 
-    RegionBindings B = GetRegionBindings(state->getStore());
-    RegionDefaultBindings DVM = state->get<RegionDefaultValue>();
-    RegionDefaultBindings::Factory &DVMFactory =
-      state->get_context<RegionDefaultValue>();
+    // Add subregions to work list.
+    RegionStoreSubRegionMap::iterator I, E;
+    for (llvm::tie(I, E) = SubRegions->begin_end(R); I!=E; ++I)
+      WorkList.push_back(*I);
+    
+    // Handle region.
+    if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
+        isa<ObjCObjectRegion>(R)) {
+        // Invalidate the region by setting its default value to
+        // conjured symbol. The type of the symbol is irrelavant.
+      DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+                                                           Count);      
+      DVM = DVMFactory.Add(DVM, R, V);
+      continue;
+    }
 
-    RemoveSubRegionBindings(B, DVM, DVMFactory, R, *SubRegions.get());
-    state = state->makeWithStore(B.getRoot())->set<RegionDefaultValue>(DVM);
+    if (!R->isBoundable())
+      continue;
+  
+    const TypedRegion *TR = cast<TypedRegion>(R);
+    QualType T = TR->getValueType(Ctx);
+  
+    if (const RecordType *RT = T->getAsStructureType()) {
+        // FIXME: handle structs with default region value.
+      const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
+    
+        // No record definition.  There is nothing we can do.
+      if (!RD)
+        continue;
+    
+        // Invalidate the region by setting its default value to
+        // conjured symbol. The type of the symbol is irrelavant.
+      DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+                                                           Count);
+      DVM = DVMFactory.Add(DVM, R, V);
+      continue;
+    }
+  
+    if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
+      // Set the default value of the array to conjured symbol.
+      DefinedOrUnknownSVal V =
+        ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
+      DVM = DVMFactory.Add(DVM, R, V);
+      continue;
+    }
+    
+    // Get the old binding.  Is it a region?  If so, add it to the worklist.
+    if (const SVal *OldV = B.lookup(R)) {
+      if (const MemRegion *RV = OldV->getAsRegion())
+        WorkList.push_back(RV);
+    }
+    
+    // Invalidate the binding.
+    DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
+    assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
+    B = RBFactory.Add(B, R, V);
   }
 
-  if (!R->isBoundable())
-    return state;
-
-  if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
-      isa<ObjCObjectRegion>(R)) {
-    // Invalidate the region by setting its default value to
-    // conjured symbol. The type of the symbol is irrelavant.
-    SVal V = ValMgr.getConjuredSymbolVal(E, Ctx.IntTy, Count);
-    return setDefaultValue(state, R, V);
-  }
-
-  const TypedRegion *TR = cast<TypedRegion>(R);
-  QualType T = TR->getValueType(Ctx);
-
-  if (const RecordType *RT = T->getAsStructureType()) {
-    // FIXME: handle structs with default region value.
-    const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
-
-    // No record definition.  There is nothing we can do.
-    if (!RD)
-      return state;
-
-    // Invalidate the region by setting its default value to
-    // conjured symbol. The type of the symbol is irrelavant.
-    SVal V = ValMgr.getConjuredSymbolVal(E, Ctx.IntTy, Count);
-    return setDefaultValue(state, R, V);
-  }
-
-  if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
-    // Set the default value of the array to conjured symbol.
-    SVal V = ValMgr.getConjuredSymbolVal(E, AT->getElementType(),
-                                         Count);
-    return setDefaultValue(state, TR, V);
-  }
-
-  SVal V = ValMgr.getConjuredSymbolVal(E, T, Count);
-  assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
-  return Bind(state, ValMgr.makeLoc(TR), V);
+  // Create a new state with the updated bindings.
+  return state->makeWithStore(B.getRoot())->set<RegionDefaultValue>(DVM);
 }
 
 //===----------------------------------------------------------------------===//