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/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
index 46ff661..0ac5bbb 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -479,6 +479,13 @@
   ///  other functions that handle specific kinds of statements.
   void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
   
+  /// VisitLVal - Similar to Visit, but the specified expression is assummed
+  ///  to be evaluated under the context where it evaluates to an LVal.  For
+  ///  example, if Ex is a DeclRefExpr, under Visit Ex would evaluate to the
+  ///  value bound to Ex in the symbolic state, while under VisitLVal it would
+  ///  evaluate to an LVal representing the location of the referred Decl.
+  void VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
+  
   /// VisitAsmStmt - Transfer function logic for inline asm.
   void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
   
@@ -494,14 +501,41 @@
   
   /// VisitBinaryOperator - Transfer function logic for binary operators.
   void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
-  
-  void VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
+
   
   /// VisitCall - Transfer function for function calls.
   void VisitCall(CallExpr* CE, NodeTy* Pred,
                  CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
                  NodeSet& Dst);
   
+  /// VisitCast - Transfer function logic for all casts (implicit and explicit).
+  void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);  
+  
+  /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
+  void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst); 
+  
+  /// VisitDeclStmt - Transfer function logic for DeclStmts.
+  void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); 
+  
+  void VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst,
+                  bool GetLVal = false);
+  
+  void VisitDeref(Expr* Ex, RVal V, ValueState* St, NodeTy* Pred, NodeSet& Dst,
+                  bool GetLVal);
+  
+  /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
+  void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
+  
+  /// VisitLogicalExpr - Transfer function logic for '&&', '||'
+  void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
+  
+  /// VisitMemberExpr - Transfer function for member expressions.
+  void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst, bool asLVal);
+  
+  void VisitMemberExprField(MemberExpr* M, Expr* Base, NodeTy* Pred,
+                            NodeSet& Dst, bool asLVal);
+    
+  
   /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
   void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
   
@@ -513,21 +547,6 @@
   void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred,
                                           NodeSet& Dst);
   
-  /// VisitCast - Transfer function logic for all casts (implicit and explicit).
-  void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);  
-  
-  /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
-  void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst); 
-  
-  /// VisitDeclStmt - Transfer function logic for DeclStmts.
-  void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); 
-  
-  /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
-  void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
-  
-  /// VisitLogicalExpr - Transfer function logic for '&&', '||'
-  void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
-  
   /// VisitReturnStmt - Transfer function logic for return statements.
   void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
   
@@ -541,8 +560,8 @@
   /// VisitUnaryOperator - Transfer function logic for unary operators.
   void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst);
   
-  void VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst,
-                  bool GetLVal = false);
+  
+  
   
   RVal EvalCast(RVal X, QualType CastT) {
     if (X.isUnknownOrUndef())
@@ -554,6 +573,8 @@
       return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
   }
   
+
+  
   RVal EvalMinus(UnaryOperator* U, RVal X) {
     return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
   }
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);
 }