]> granicus.if.org Git - clang/commitdiff
[analyzer] Remove constraints on dead symbols as part of removeDeadBindings.
authorJordan Rose <jordan_rose@apple.com>
Sat, 8 Sep 2012 01:24:53 +0000 (01:24 +0000)
committerJordan Rose <jordan_rose@apple.com>
Sat, 8 Sep 2012 01:24:53 +0000 (01:24 +0000)
Previously, we'd just keep constraints around forever, which means we'd
never be able to merge paths that differed only in constraints on dead
symbols.

Because we now allow constraints on symbolic expressions, not just single
symbols, this requires changing SymExpr::symbol_iterator to include
intermediate symbol nodes in its traversal, not just the SymbolData leaf
nodes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163444 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/ProgramState.cpp
lib/StaticAnalyzer/Core/SymbolManager.cpp
test/Analysis/traversal-path-unification.c [new file with mode: 0644]

index ed8e1dc9ec1f40ca964c1b2ff86527586fdc5b9d..3c7e28e94619678b5d970b3328448fc14dd53fcf 100644 (file)
@@ -106,8 +106,9 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
                                                    SymReaper);
   NewState.setStore(newStore);
   SymReaper.setReapedStore(newStore);
-  
-  return getPersistentState(NewState);
+
+  ProgramStateRef Result = getPersistentState(NewState);
+  return ConstraintMgr->removeDeadBindings(Result, SymReaper);
 }
 
 ProgramStateRef ProgramStateManager::MarshalState(ProgramStateRef state,
@@ -697,7 +698,9 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
   bool Tainted = false;
   for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
        SI != SE; ++SI) {
-    assert(isa<SymbolData>(*SI));
+    if (!isa<SymbolData>(*SI))
+      continue;
+    
     const TaintTagType *Tag = get<TaintMap>(*SI);
     Tainted = (Tag && *Tag == Kind);
 
index c21df4c31811bab1215cb93b8c9b9abb0a5446a9..16fc5408f53a8c7a7e44f1f2a09975cc9852f3fe 100644 (file)
@@ -117,21 +117,17 @@ bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
 
 SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
   itr.push_back(SE);
-  while (!isa<SymbolData>(itr.back())) expand();
 }
 
 SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
   assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
-  assert(isa<SymbolData>(itr.back()));
-  itr.pop_back();
-  if (!itr.empty())
-    while (!isa<SymbolData>(itr.back())) expand();
+  expand();
   return *this;
 }
 
 SymbolRef SymExpr::symbol_iterator::operator*() {
   assert(!itr.empty() && "attempting to dereference an 'end' iterator");
-  return cast<SymbolData>(itr.back());
+  return itr.back();
 }
 
 void SymExpr::symbol_iterator::expand() {
diff --git a/test/Analysis/traversal-path-unification.c b/test/Analysis/traversal-path-unification.c
new file mode 100644 (file)
index 0000000..0a45f48
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
+
+int a();
+int b();
+int c();
+
+void testRemoveDeadBindings() {
+  int i = a();
+  if (i)
+    a();
+  else
+    b();
+
+  // At this point the symbol bound to 'i' is dead.
+  // The effects of a() and b() are identical (they both invalidate globals).
+  // We should unify the two paths here and only get one end-of-path node.
+  c();
+}
+
+// CHECK: --END PATH--
+// CHECK-NOT: --END PATH--
\ No newline at end of file