Added support for detected bad dereferences involving MemberExprs, e.g. x->f where "x" is NULL.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50071 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 8c771bf..86d2cc9 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -285,6 +285,11 @@
       break;
     }
       
+    case Stmt::MemberExprClass: {
+      VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst, false);
+      break;
+    }
+      
     case Stmt::ObjCMessageExprClass: {
       VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
       break;
@@ -709,6 +714,36 @@
   MakeNode(Dst, D, Pred, SetBlkExprRVal(St, D, Y));
 }
 
+/// VisitMemberExpr - Transfer function for member expressions.
+void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred,
+                                   NodeSet& Dst, bool asLVal) {
+  
+  Expr* Base = M->getBase()->IgnoreParens();
+
+  NodeSet Tmp;
+  VisitLVal(Base, Pred, Tmp);
+  
+  if (Base->getType()->isPointerType()) {
+    NodeSet Tmp2;
+    
+    for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+      ValueState* St = GetState(*I);      
+      VisitDeref(Base, GetRVal(St, Base), St, *I, Tmp2, true);
+    }
+    
+    for (NodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I)
+      VisitMemberExprField(M, Base, *I, Dst, asLVal);
+  }
+  else
+    for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
+      VisitMemberExprField(M, Base, *I, Dst, asLVal);
+}
+
+void GRExprEngine::VisitMemberExprField(MemberExpr* M, Expr* Base, NodeTy* Pred,
+                                        NodeSet& Dst, bool asLVal) {
+  Dst.Add(Pred);  
+}
+
 void GRExprEngine::EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred,
                              ValueState* St, RVal TargetLV, RVal Val) {
   
@@ -1149,9 +1184,9 @@
 
 void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred,
                               NodeSet& Dst, bool GetLVal) {
-
+  
   Expr* Ex = U->getSubExpr()->IgnoreParens();
-    
+  
   NodeSet DstTmp;
   
   if (isa<DeclRefExpr>(Ex))
@@ -1160,82 +1195,80 @@
     Visit(Ex, Pred, DstTmp);
   
   for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) {
-
-    NodeTy* N = *I;
-    ValueState* St = GetState(N);
-    
-    // FIXME: Bifurcate when dereferencing a symbolic with no constraints?
-    
+    ValueState* St = GetState(Pred);
     RVal V = GetRVal(St, Ex);
-    
-    // Check for dereferences of undefined values.
-    
-    if (V.isUndef()) {
-      
-      NodeTy* Succ = Builder->generateNode(U, St, N);
-      
-      if (Succ) {
-        Succ->markAsSink();
-        UndefDeref.insert(Succ);
-      }
-      
-      continue;
+    VisitDeref(U, V, St, Pred, Dst, GetLVal);
+  }
+}
+
+void GRExprEngine::VisitDeref(Expr* Ex, RVal V, ValueState* St, NodeTy* Pred,
+                              NodeSet& Dst, bool GetLVal) {
+  
+  // Check for dereferences of undefined values.
+  
+  if (V.isUndef()) {
+    if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred)) {
+      Succ->markAsSink();
+      UndefDeref.insert(Succ);
     }
     
-    // Check for dereferences of unknown values.  Treat as No-Ops.
+    return;
+  }
+  
+  // Check for dereferences of unknown values.  Treat as No-Ops.
+  
+  if (V.isUnknown()) {
+    Dst.Add(Pred);
+    return;
+  }
+  
+  // After a dereference, one of two possible situations arise:
+  //  (1) A crash, because the pointer was NULL.
+  //  (2) The pointer is not NULL, and the dereference works.
+  // 
+  // We add these assumptions.
+  
+  LVal LV = cast<LVal>(V);    
+  bool isFeasibleNotNull;
+  
+  // "Assume" that the pointer is Not-NULL.
+  
+  ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
+  
+  if (isFeasibleNotNull) {
     
-    if (V.isUnknown()) {
-      Dst.Add(N);
-      continue;
+    if (GetLVal)
+      MakeNode(Dst, Ex, Pred, SetRVal(StNotNull, Ex, LV));
+    else {
+      
+      // FIXME: Currently symbolic analysis "generates" new symbols
+      //  for the contents of values.  We need a better approach.
+      
+      MakeNode(Dst, Ex, Pred,
+               SetRVal(StNotNull, Ex, GetRVal(StNotNull, LV, Ex->getType())));
     }
+  }
+  
+  bool isFeasibleNull;
+  
+  // Now "assume" that the pointer is NULL.
+  
+  ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
+  
+  if (isFeasibleNull) {
     
-    // After a dereference, one of two possible situations arise:
-    //  (1) A crash, because the pointer was NULL.
-    //  (2) The pointer is not NULL, and the dereference works.
-    // 
-    // We add these assumptions.
+    // We don't use "MakeNode" here because the node will be a sink
+    // and we have no intention of processing it later.
     
-    LVal LV = cast<LVal>(V);    
-    bool isFeasibleNotNull;
+    NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred);
     
-    // "Assume" that the pointer is Not-NULL.
-    
-    ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
-    
-    if (isFeasibleNotNull) {
-
-      if (GetLVal) MakeNode(Dst, U, N, SetRVal(StNotNull, U, LV));
-      else {
-        
-        // FIXME: Currently symbolic analysis "generates" new symbols
-        //  for the contents of values.  We need a better approach.
+    if (NullNode) {
       
-        MakeNode(Dst, U, N, SetRVal(StNotNull, U,
-                                  GetRVal(StNotNull, LV, U->getType())));
-      }
+      NullNode->markAsSink();
+      
+      if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
+      else ExplicitNullDeref.insert(NullNode);
     }
-    
-    bool isFeasibleNull;
-    
-    // Now "assume" that the pointer is NULL.
-    
-    ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
-    
-    if (isFeasibleNull) {
-      
-      // We don't use "MakeNode" here because the node will be a sink
-      // and we have no intention of processing it later.
-
-      NodeTy* NullNode = Builder->generateNode(U, StNull, N);
-      
-      if (NullNode) {
-
-        NullNode->markAsSink();
-        
-        if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
-        else ExplicitNullDeref.insert(NullNode);
-      }
-    }    
   }
 }
 
@@ -1387,23 +1420,36 @@
 
 void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
 
+  Ex = Ex->IgnoreParens();
+
   if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) {
     Dst.Add(Pred);
     return;
   }
   
-  Ex = Ex->IgnoreParens();
-  
-  if (isa<DeclRefExpr>(Ex)) {
-    Dst.Add(Pred);
-    return;
-  }
-  
-  if (UnaryOperator* U = dyn_cast<UnaryOperator>(Ex))
-    if (U->getOpcode() == UnaryOperator::Deref) {
-      VisitDeref(U, Pred, Dst, true);
+  switch (Ex->getStmtClass()) {
+    default:
+      break;
+      
+    case Stmt::DeclRefExprClass:
+      Dst.Add(Pred);
       return;
+      
+    case Stmt::UnaryOperatorClass: {
+      UnaryOperator* U = cast<UnaryOperator>(Ex);
+      
+      if (U->getOpcode() == UnaryOperator::Deref) {
+        VisitDeref(U, Pred, Dst, true);
+        return;
+      }
+      
+      break;
     }
+      
+    case Stmt::MemberExprClass:
+      VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
+      return;
+  }
   
   Visit(Ex, Pred, Dst);
 }