[cfe-commits] r46843 - in /cfe/trunk/Analysis: GRConstants.cpp RValues.cpp RValues.h ValueState.cpp ValueState.h

Ted Kremenek kremenek at apple.com
Wed Feb 6 21:48:01 PST 2008


Author: kremenek
Date: Wed Feb  6 23:48:01 2008
New Revision: 46843

URL: http://llvm.org/viewvc/llvm-project?rev=46843&view=rev
Log:
Added recording of "implicit" NULL dereferences of symbolic pointers.

Modified:
    cfe/trunk/Analysis/GRConstants.cpp
    cfe/trunk/Analysis/RValues.cpp
    cfe/trunk/Analysis/RValues.h
    cfe/trunk/Analysis/ValueState.cpp
    cfe/trunk/Analysis/ValueState.h

Modified: cfe/trunk/Analysis/GRConstants.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/GRConstants.cpp?rev=46843&r1=46842&r2=46843&view=diff

==============================================================================
--- cfe/trunk/Analysis/GRConstants.cpp (original)
+++ cfe/trunk/Analysis/GRConstants.cpp Wed Feb  6 23:48:01 2008
@@ -124,6 +124,12 @@
   typedef llvm::SmallPtrSet<NodeTy*,5> UninitBranchesTy;
   UninitBranchesTy UninitBranches;
   
+  /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
+  ///  taking a dereference on a symbolic pointer that may be NULL.
+  typedef llvm::SmallPtrSet<NodeTy*,5> ImplicitNullDerefTy;
+  ImplicitNullDerefTy ImplicitNullDeref;
+  
+  
   bool StateCleaned;
   
   ASTContext& getContext() const { return G.getContext(); }
@@ -162,6 +168,10 @@
   bool isUninitControlFlow(const NodeTy* N) const {
     return N->isSink() && UninitBranches.count(const_cast<NodeTy*>(N)) != 0;
   }
+  
+  bool isImplicitNullDeref(const NodeTy* N) const {
+    return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
+  }
 
   /// ProcessStmt - Called by GREngine. Used to generate new successor
   ///  nodes by processing the 'effects' of a block-level statement.
@@ -203,8 +213,10 @@
     return GetValue(St, const_cast<Stmt*>(S));
   }
   
-  inline RValue GetValue(const StateTy& St, const LValue& LV) {
-    return StateMgr.GetValue(St, LV);
+  inline RValue GetValue(const StateTy& St, const LValue& LV,
+                         QualType* T = NULL) {
+    
+    return StateMgr.GetValue(St, LV, T);
   }
   
   inline LValue GetLValue(const StateTy& St, Stmt* S) {
@@ -237,7 +249,7 @@
   StateTy AssumeSymInt(StateTy St, bool Assumption, const SymIntConstraint& C,
                        bool& isFeasible);
   
-  void Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St);
+  NodeTy* Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St);
   
   /// Nodify - This version of Nodify is used to batch process a set of states.
   ///  The states are not guaranteed to be unique.
@@ -557,13 +569,16 @@
   return M;
 }
 
-void GRConstants::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St) {
+GRConstants::NodeTy*
+GRConstants::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St) {
  
   // If the state hasn't changed, don't generate a new node.
   if (St == Pred->getState())
-    return;
+    return NULL;
   
-  Dst.Add(Builder->generateNode(S, St, Pred));
+  NodeTy* N = Builder->generateNode(S, St, Pred);
+  Dst.Add(N);
+  return N;
 }
 
 void GRConstants::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred,
@@ -756,7 +771,34 @@
         const RValue& V = GetValue(St, U->getSubExpr());
         const LValue& L1 = cast<LValue>(V);
         
-        Nodify(Dst, U, N1, SetValue(St, U, GetValue(St, L1)));
+        // 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.
+                
+        bool isFeasible;
+        
+        // "Assume" that the pointer is NULL.
+        StateTy StNull = Assume(St, L1, false, isFeasible);
+        
+        if (isFeasible) {
+          NodeTy* NullNode = Nodify(Dst, U, N1, StNull);
+          if (NullNode) {
+            NullNode->markAsSink();
+            ImplicitNullDeref.insert(NullNode);
+          }
+        }
+        
+        // "Assume" that the pointer is Not-NULL.
+        StateTy StNotNull = Assume(St, L1, true, isFeasible);
+
+        if (isFeasible) {
+          QualType T = U->getType();
+          Nodify(Dst, U, N1, SetValue(StNotNull, U,
+                                      GetValue(StNotNull, L1, &T)));
+        }
+        
         break;
       }
         
@@ -1208,6 +1250,11 @@
             << (void*) L.getStmt() << ' ';
         
         L.getStmt()->printPretty(Out);
+        
+        if (GraphPrintCheckerState->isImplicitNullDeref(N)) {
+          Out << "\\|Implicit-Null Dereference.\\l";
+        }
+        
         break;
       }
     

Modified: cfe/trunk/Analysis/RValues.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/RValues.cpp?rev=46843&r1=46842&r2=46843&view=diff

==============================================================================
--- cfe/trunk/Analysis/RValues.cpp (original)
+++ cfe/trunk/Analysis/RValues.cpp Wed Feb  6 23:48:01 2008
@@ -24,23 +24,35 @@
 //===----------------------------------------------------------------------===//
 
 SymbolID SymbolManager::getSymbol(ParmVarDecl* D) {
-  SymbolID& X = DataToSymbol[D];
+  SymbolID& X = DataToSymbol[getKey(D)];
   
   if (!X.isInitialized()) {
     X = SymbolToData.size();
-    SymbolToData.push_back(D);
+    SymbolToData.push_back(SymbolDataParmVar(D));
   }
   
   return X;
 }
 
+SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) {
+  SymbolID& X = DataToSymbol[getKey(sym)];
+  
+  if (!X.isInitialized()) {
+    X = SymbolToData.size();
+    SymbolToData.push_back(SymbolDataContentsOf(sym));
+  }
+  
+  return X;  
+}
+
 QualType SymbolData::getType() const {
   switch (getKind()) {
     default:
       assert (false && "getType() not implemented for this symbol.");
     
     case ParmKind:
-      return static_cast<ParmVarDecl*>(getPtr())->getType();
+      return cast<SymbolDataParmVar>(this)->getDecl()->getType();
+
   }
 }
 
@@ -554,7 +566,7 @@
   }
 }
 
-#if 0
+
 void LValue::print(std::ostream& Out) const {
   switch (getSubKind()) {        
     case lval::ConcreteIntKind:
@@ -576,4 +588,4 @@
       break;
   }
 }
-#endif
+

Modified: cfe/trunk/Analysis/RValues.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/RValues.h?rev=46843&r1=46842&r2=46843&view=diff

==============================================================================
--- cfe/trunk/Analysis/RValues.h (original)
+++ cfe/trunk/Analysis/RValues.h Wed Feb  6 23:48:01 2008
@@ -61,21 +61,70 @@
   }
 };
   
+  // SymbolData: Used to record meta data about symbols.
+  
 class SymbolData {
+public:
+  enum Kind { UninitKind, ParmKind, ContentsOfKind };
+
+private:
   uintptr_t Data;
+  Kind K;
+  
+protected:
+  SymbolData(uintptr_t D, Kind k) : Data(D), K(k) {}
+  SymbolData(void* D, Kind k) : Data(reinterpret_cast<uintptr_t>(D)), K(k) {}
+  
+  void* getPtr() const { 
+    assert (K != UninitKind);
+    return reinterpret_cast<void*>(Data);
+  }
+  
+  uintptr_t getInt() const {
+    assert (K != UninitKind);
+    return Data;
+  }
+  
 public:
-  enum Kind { ParmKind = 0x0, Mask = 0x3 };
+  SymbolData() : Data(0), K(UninitKind) {}
   
-  SymbolData(ParmVarDecl* D)
-  : Data(reinterpret_cast<uintptr_t>(D) | ParmKind) {}
+  Kind  getKind() const { return K; }  
+
+  inline bool operator==(const SymbolData& R) const { 
+    return K == R.K && Data == R.Data;
+  }
   
-  inline Kind getKind() const { return (Kind) (Data & Mask); }
-  inline void* getPtr() const { return reinterpret_cast<void*>(Data & ~Mask); }  
-  inline bool operator==(const SymbolData& R) const { return Data == R.Data; }
+  QualType getType() const;
   
-  QualType getType() const;  
+  // Implement isa<T> support.
+  static inline bool classof(const SymbolData*) { return true; }
 };
+
+class SymbolDataParmVar : public SymbolData {
+public:
+  SymbolDataParmVar(ParmVarDecl* VD) : SymbolData(VD, ParmKind) {}
+  
+  ParmVarDecl* getDecl() const { return (ParmVarDecl*) getPtr(); }
+  
+  // Implement isa<T> support.
+  static inline bool classof(const SymbolData* D) {
+    return D->getKind() == ParmKind;
+  }
+};
+  
+class SymbolDataContentsOf : public SymbolData {
+public:
+  SymbolDataContentsOf(SymbolID ID) : SymbolData(ID, ContentsOfKind) {}
+  
+  SymbolID getSymbol() const { return (SymbolID) getInt(); }
   
+  // Implement isa<T> support.
+  static inline bool classof(const SymbolData* D) {
+    return D->getKind() == ContentsOfKind;
+  }  
+};
+    
+    // Constraints on symbols.  Usually wrapped by RValues.
 
 class SymIntConstraint : public llvm::FoldingSetNode {
   SymbolID Symbol;
@@ -112,13 +161,22 @@
   typedef llvm::DenseMap<void*,SymbolID> MapTy;
   MapTy DataToSymbol;
   
+  void* getKey(void* P) const {
+    return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(P) | 0x1);
+  }
+  
+  void* getKey(SymbolID sym) const {
+    return reinterpret_cast<void*>((uintptr_t) (sym << 1));
+  }
+  
 public:
   SymbolManager();
   ~SymbolManager();
   
   SymbolID getSymbol(ParmVarDecl* D);
+  SymbolID getContentsOfSymbol(SymbolID sym);
   
-  inline SymbolData getSymbolData(SymbolID ID) const {
+  inline const SymbolData& getSymbolData(SymbolID ID) const {
     assert (ID < SymbolToData.size());
     return SymbolToData[ID];
   }
@@ -176,30 +234,6 @@
 } // end clang namespace
 
 //==------------------------------------------------------------------------==//
-// Casting machinery to get cast<> and dyn_cast<> working with SymbolData.
-//==------------------------------------------------------------------------==//
-
-namespace llvm {
-  
-  template<> inline bool
-  isa<clang::ParmVarDecl,clang::SymbolData>(const clang::SymbolData& V) {
-    return V.getKind() == clang::SymbolData::ParmKind;
-  }
-  
-  template<> struct cast_retty_impl<clang::ParmVarDecl,clang::SymbolData> {
-    typedef const clang::ParmVarDecl* ret_type;
-  };
-  
-  template<> struct simplify_type<clang::SymbolData> {
-    typedef void* SimpleType;
-    static inline SimpleType getSimplifiedValue(const clang::SymbolData &V) {
-      return V.getPtr();
-    }
-  };
-  
-} // end llvm namespace
-
-//==------------------------------------------------------------------------==//
 //  Base RValue types.
 //==------------------------------------------------------------------------==// 
 
@@ -323,7 +357,7 @@
   NonLValue NE(ValueManager& ValMgr, const LValue& RHS) const;
   
 public:
-//  void print(std::ostream& Out) const;
+  void print(std::ostream& Out) const;
 
   RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
                             const LValue& RHS) const;

Modified: cfe/trunk/Analysis/ValueState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/ValueState.cpp?rev=46843&r1=46842&r2=46843&view=diff

==============================================================================
--- cfe/trunk/Analysis/ValueState.cpp (original)
+++ cfe/trunk/Analysis/ValueState.cpp Wed Feb  6 23:48:01 2008
@@ -33,7 +33,8 @@
 
 
 
-RValue ValueStateManager::GetValue(const StateTy& St, const LValue& LV) {
+RValue ValueStateManager::GetValue(const StateTy& St, const LValue& LV,
+                                   QualType* T) {
   if (isa<InvalidValue>(LV))
     return InvalidValue();
   
@@ -44,6 +45,19 @@
       
       return T ? T->getValue().second : InvalidValue();
     }
+     
+      // FIXME: We should bind how far a "ContentsOf" will go...
+      
+    case lval::SymbolValKind: {
+      const lval::SymbolVal& SV = cast<lval::SymbolVal>(LV);
+      assert (T);
+      
+      if (T->getTypePtr()->isPointerType())
+        return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
+      else
+        return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
+    }
+      
     default:
       assert (false && "Invalid LValue.");
       break;

Modified: cfe/trunk/Analysis/ValueState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/ValueState.h?rev=46843&r1=46842&r2=46843&view=diff

==============================================================================
--- cfe/trunk/Analysis/ValueState.h (original)
+++ cfe/trunk/Analysis/ValueState.h Wed Feb  6 23:48:01 2008
@@ -264,7 +264,7 @@
   StateTy SetValue(StateTy St, const LValue& LV, const RValue& V);
 
   RValue GetValue(const StateTy& St, Stmt* S, bool* hasVal = NULL);
-  RValue GetValue(const StateTy& St, const LValue& LV);
+  RValue GetValue(const StateTy& St, const LValue& LV, QualType* T = NULL);
     
   LValue GetLValue(const StateTy& St, Stmt* S);
 





More information about the cfe-commits mailing list