[cfe-commits] r85471 - in /cfe/trunk: include/clang/Analysis/PathSensitive/BugReporter.h include/clang/Analysis/PathSensitive/BugType.h include/clang/Analysis/PathSensitive/Checker.h include/clang/Analysis/PathSensitive/GRExprEngine.h include/clang/Analysis/PathSensitive/NullDerefChecker.h lib/Analysis/CheckNSError.cpp lib/Analysis/GRExprEngine.cpp lib/Analysis/GRExprEngineInternalChecks.cpp

Zhongxing Xu xuzhongxing at gmail.com
Wed Oct 28 19:09:31 PDT 2009


Author: zhongxingxu
Date: Wed Oct 28 21:09:30 2009
New Revision: 85471

URL: http://llvm.org/viewvc/llvm-project?rev=85471&view=rev
Log:
Move NullDeref and UndefDeref into their own checker. 
Add a CheckLocation() interface to Checker.
Now ImplicitNullDeref nodes are cached in NullDerefChecker.
More cleanups follow.

Added:
    cfe/trunk/include/clang/Analysis/PathSensitive/BugType.h
    cfe/trunk/include/clang/Analysis/PathSensitive/NullDerefChecker.h
Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
    cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/lib/Analysis/CheckNSError.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp
    cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h?rev=85471&r1=85470&r2=85471&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h Wed Oct 28 21:09:30 2009
@@ -19,6 +19,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Analysis/PathSensitive/GRState.h"
 #include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/BugType.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallString.h"
@@ -183,38 +184,6 @@
   const_iterator end() const { return const_iterator(Reports.end()); }
 };
 
-class BugType {
-private:
-  const std::string Name;
-  const std::string Category;
-  llvm::FoldingSet<BugReportEquivClass> EQClasses;
-  friend class BugReporter;
-  bool SuppressonSink;
-public:
-  BugType(const char *name, const char* cat)
-    : Name(name), Category(cat), SuppressonSink(false) {}
-  virtual ~BugType();
-
-  // FIXME: Should these be made strings as well?
-  const std::string& getName() const { return Name; }
-  const std::string& getCategory() const { return Category; }
-  
-  /// isSuppressOnSink - Returns true if bug reports associated with this bug
-  ///  type should be suppressed if the end node of the report is post-dominated
-  ///  by a sink node.
-  bool isSuppressOnSink() const { return SuppressonSink; }
-  void setSuppressOnSink(bool x) { SuppressonSink = x; }
-
-  virtual void FlushReports(BugReporter& BR);
-
-  typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
-  iterator begin() { return EQClasses.begin(); }
-  iterator end() { return EQClasses.end(); }
-
-  typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
-  const_iterator begin() const { return EQClasses.begin(); }
-  const_iterator end() const { return EQClasses.end(); }
-};
 
 //===----------------------------------------------------------------------===//
 // Specialized subclasses of BugReport.

Added: cfe/trunk/include/clang/Analysis/PathSensitive/BugType.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/BugType.h?rev=85471&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/BugType.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/BugType.h Wed Oct 28 21:09:30 2009
@@ -0,0 +1,73 @@
+#ifndef LLVM_CLANG_BUGTYPE
+#define LLVM_CLANG_BUGTYPE
+
+#include <llvm/ADT/FoldingSet.h>
+
+#include <string>
+
+namespace clang {
+
+class BugReportEquivClass;
+class BugReporter;
+class BuiltinBugReport;
+class BugReporterContext;
+class GRExprEngine;
+
+class BugType {
+private:
+  const std::string Name;
+  const std::string Category;
+  llvm::FoldingSet<BugReportEquivClass> EQClasses;
+  friend class BugReporter;
+  bool SuppressonSink;
+public:
+  BugType(const char *name, const char* cat)
+    : Name(name), Category(cat), SuppressonSink(false) {}
+  virtual ~BugType();
+
+  // FIXME: Should these be made strings as well?
+  const std::string& getName() const { return Name; }
+  const std::string& getCategory() const { return Category; }
+  
+  /// isSuppressOnSink - Returns true if bug reports associated with this bug
+  ///  type should be suppressed if the end node of the report is post-dominated
+  ///  by a sink node.
+  bool isSuppressOnSink() const { return SuppressonSink; }
+  void setSuppressOnSink(bool x) { SuppressonSink = x; }
+
+  virtual void FlushReports(BugReporter& BR);
+
+  typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
+  iterator begin() { return EQClasses.begin(); }
+  iterator end() { return EQClasses.end(); }
+
+  typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
+  const_iterator begin() const { return EQClasses.begin(); }
+  const_iterator end() const { return EQClasses.end(); }
+};
+
+class BuiltinBug : public BugType {
+  GRExprEngine &Eng;
+protected:
+  const std::string desc;
+public:
+  BuiltinBug(GRExprEngine *eng, const char* n, const char* d)
+    : BugType(n, "Logic errors"), Eng(*eng), desc(d) {}
+
+  BuiltinBug(GRExprEngine *eng, const char* n)
+    : BugType(n, "Logic errors"), Eng(*eng), desc(n) {}
+
+  const std::string &getDescription() const { return desc; }
+
+  virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {}
+
+  void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
+
+  virtual void registerInitialVisitors(BugReporterContext& BRC,
+                                       const ExplodedNode* N,
+                                       BuiltinBugReport *R) {}
+
+  template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E);
+};
+} // end clang namespace
+#endif

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h?rev=85471&r1=85470&r2=85471&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h Wed Oct 28 21:09:30 2009
@@ -104,16 +104,24 @@
                 GRStmtNodeBuilder &Builder,
                 GRExprEngine &Eng,
                 const Stmt *stmt,
-                ExplodedNode *Pred, bool isPrevisit) {
-    CheckerContext C(Dst, Builder, Eng, Pred, getTag(), isPrevisit);
+                ExplodedNode *Pred, void *tag, bool isPrevisit) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit);
     assert(isPrevisit && "Only previsit supported for now.");
     _PreVisit(C, stmt);
   }
 
+
+
 public:
   virtual ~Checker() {}
-  virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) = 0;
-  virtual const void *getTag() = 0;
+  virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) {}
+  
+  // This is a previsit which takes a node returns a node.
+  virtual ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred,
+                                      const GRState *state, SVal V,
+                                      GRExprEngine &Eng) {
+    return Pred;
+  }
 };
 
 } // end clang namespace

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=85471&r1=85470&r2=85471&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Wed Oct 28 21:09:30 2009
@@ -75,7 +75,8 @@
   Selector RaiseSel;
 
   llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
-  std::vector<Checker*> Checkers;
+
+  llvm::DenseMap<void *, Checker*> Checkers;
 
   /// BR - The BugReporter associated with this engine.  It is important that
   //   this object be placed at the very end of member variables so that its
@@ -126,18 +127,6 @@
   //  calling a function with the attribute "noreturn".
   ErrorNodes NoReturnCalls;
 
-  /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
-  ///  taking a dereference on a symbolic pointer that MAY be NULL.
-  ErrorNodes ImplicitNullDeref;
-
-  /// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
-  ///  taking a dereference on a symbolic pointer that MUST be NULL.
-  ErrorNodes ExplicitNullDeref;
-
-  /// UndefDeref - Nodes in the ExplodedGraph that result from
-  ///  taking a dereference on an undefined value.
-  ErrorNodes UndefDeref;
-
   /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
   ///  constructing a zero-sized VLA where the size may be zero.
   ErrorNodes ImplicitBadSizedVLA;
@@ -158,10 +147,6 @@
   ///  ObjC message expressions where the receiver is undefined (uninitialized).
   ErrorNodes UndefReceivers;
 
-  /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
-  ///   where a pass-by-value argument has an undefined value.
-  UndefArgsTy UndefArgs;
-
   /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from
   ///   message expressions where a pass-by-value argument has an undefined
   ///  value.
@@ -195,6 +180,8 @@
 
   BugReporter& getBugReporter() { return BR; }
 
+  GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
+
   /// setTransferFunctions
   void setTransferFunctions(GRTransferFuncs* tf);
 
@@ -217,8 +204,14 @@
 
   void RegisterInternalChecks();
 
+  template <typename CHECKER>
   void registerCheck(Checker *check) {
-    Checkers.push_back(check);
+    Checkers[CHECKER::getTag()] = check;
+  }
+
+  template <typename CHECKER>
+  CHECKER *getChecker() {
+     return static_cast<CHECKER*>(Checkers[CHECKER::getTag()]);
   }
 
   bool isRetStackAddr(const ExplodedNode* N) const {
@@ -234,15 +227,15 @@
   }
 
   bool isImplicitNullDeref(const ExplodedNode* N) const {
-    return N->isSink() && ImplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0;
+    return false;
   }
 
   bool isExplicitNullDeref(const ExplodedNode* N) const {
-    return N->isSink() && ExplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0;
+    return false;
   }
 
   bool isUndefDeref(const ExplodedNode* N) const {
-    return N->isSink() && UndefDeref.count(const_cast<ExplodedNode*>(N)) != 0;
+    return false;
   }
 
   bool isNoReturnCall(const ExplodedNode* N) const {
@@ -254,13 +247,11 @@
   }
 
   bool isBadCall(const ExplodedNode* N) const {
-    return N->isSink() && BadCalls.count(const_cast<ExplodedNode*>(N)) != 0;
+    return false;
   }
 
   bool isUndefArg(const ExplodedNode* N) const {
-    return N->isSink() &&
-      (UndefArgs.find(const_cast<ExplodedNode*>(N)) != UndefArgs.end() ||
-       MsgExprUndefArgs.find(const_cast<ExplodedNode*>(N)) != MsgExprUndefArgs.end());
+    return false;
   }
 
   bool isUndefReceiver(const ExplodedNode* N) const {
@@ -279,17 +270,6 @@
   undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
   undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
 
-  typedef ErrorNodes::iterator null_deref_iterator;
-  null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
-  null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
-
-  null_deref_iterator implicit_null_derefs_begin() {
-    return ImplicitNullDeref.begin();
-  }
-  null_deref_iterator implicit_null_derefs_end() {
-    return ImplicitNullDeref.end();
-  }
-
   typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator;
 
   nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() {
@@ -312,10 +292,6 @@
     return NilReceiverLargerThanVoidPtrRetExplicit.end();
   }
 
-  typedef ErrorNodes::iterator undef_deref_iterator;
-  undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
-  undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
-
   typedef ErrorNodes::iterator undef_result_iterator;
   undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
   undef_result_iterator undef_results_end() { return UndefResults.end(); }
@@ -325,9 +301,6 @@
   bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
 
   typedef UndefArgsTy::iterator undef_arg_iterator;
-  undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
-  undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
-
   undef_arg_iterator msg_expr_undef_arg_begin() {
     return MsgExprUndefArgs.begin();
   }
@@ -427,7 +400,11 @@
 protected:
   /// CheckerVisit - Dispatcher for performing checker-specific logic
   ///  at specific statements.
-  void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit);
+  void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
+                    bool isPrevisit);
+
+  ExplodedNode *CheckerVisitLocation(Stmt *S, ExplodedNode *Pred, 
+                                     const GRState *state, SVal V);
 
   /// Visit - Transfer function logic for all statements.  Dispatches to
   ///  other functions that handle specific kinds of statements.

Added: cfe/trunk/include/clang/Analysis/PathSensitive/NullDerefChecker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/NullDerefChecker.h?rev=85471&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/NullDerefChecker.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/NullDerefChecker.h Wed Oct 28 21:09:30 2009
@@ -0,0 +1,51 @@
+//== NullDerefChecker - Null dereference checker ----------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_NULLDEREFCHECKER
+#define LLVM_CLANG_NULLDEREFCHECKER
+
+#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Analysis/PathSensitive/BugType.h"
+
+namespace clang {
+
+class ExplodedNode;
+
+class NullDeref : public BuiltinBug {
+public:
+  NullDeref() 
+    : BuiltinBug(0, "Null dereference", "Dereference of null pointer") {}
+
+  void registerInitialVisitors(BugReporterContext& BRC,
+                               const ExplodedNode* N,
+                               BuiltinBugReport *R);
+};
+
+class NullDerefChecker : public Checker {
+  NullDeref *BT;
+  llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
+
+public:
+
+  NullDerefChecker() : BT(0) {}
+  ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred,
+                              const GRState *state, SVal V,GRExprEngine &Eng);
+
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+
+  typedef llvm::SmallVectorImpl<ExplodedNode*>::iterator iterator;
+  iterator implicit_nodes_begin() { return ImplicitNullDerefNodes.begin(); }
+  iterator implicit_nodes_end() { return ImplicitNullDerefNodes.end(); }
+};
+
+} // end clang namespace
+#endif

Modified: cfe/trunk/lib/Analysis/CheckNSError.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CheckNSError.cpp?rev=85471&r1=85470&r2=85471&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CheckNSError.cpp (original)
+++ cfe/trunk/lib/Analysis/CheckNSError.cpp Wed Oct 28 21:09:30 2009
@@ -18,6 +18,7 @@
 #include "clang/Analysis/LocalCheckers.h"
 #include "clang/Analysis/PathSensitive/BugReporter.h"
 #include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/NullDerefChecker.h"
 #include "BasicObjCFoundationChecks.h"
 #include "llvm/Support/Compiler.h"
 #include "clang/AST/DeclObjC.h"
@@ -208,8 +209,9 @@
     return;
 
   // Iterate over the implicit-null dereferences.
-  for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(),
-       E=Eng.implicit_null_derefs_end(); I!=E; ++I) {
+  NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>();
+  for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(),
+         E = Checker->implicit_nodes_end(); I != E; ++I) {
 
     const GRState *state = (*I)->getState();
     const SVal* X = state->get<GRState::NullDerefTag>();

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=85471&r1=85470&r2=85471&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Wed Oct 28 21:09:30 2009
@@ -118,17 +118,20 @@
   ExplodedNodeSet Tmp;
   ExplodedNodeSet *PrevSet = &Src;
 
-  for (std::vector<Checker*>::iterator I = Checkers.begin(), E = Checkers.end();
-       I != E; ++I) {
+  for (llvm::DenseMap<void*, Checker*>::iterator I = Checkers.begin(), 
+         E = Checkers.end(); I != E; ++I) {
+
+    llvm::DenseMap<void*, Checker*>::iterator X = I;
 
-    ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+    ExplodedNodeSet *CurrSet = (++X == E) ? &Dst
                                           : (PrevSet == &Tmp) ? &Src : &Tmp;
     CurrSet->clear();
-    Checker *checker = *I;
+    void *tag = I->first;
+    Checker *checker = I->second;
 
     for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
          NI != NE; ++NI)
-      checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, isPrevisit);
+      checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
 
     // Update which NodeSet is the current one.
     PrevSet = CurrSet;
@@ -138,6 +141,21 @@
   // automatically.
 }
 
+ExplodedNode *GRExprEngine::CheckerVisitLocation(Stmt *S, ExplodedNode *Pred, 
+                                                const GRState *state, SVal V) {
+  if (Checkers.empty())
+    return Pred;
+
+  for (llvm::DenseMap<void*, Checker*>::iterator I = Checkers.begin(), 
+         E = Checkers.end(); I != E; ++I) {
+    Pred = I->second->CheckLocation(S, Pred, state, V, *this);
+    if (!Pred)
+      break;
+  }
+
+  return Pred;
+}
+
 //===----------------------------------------------------------------------===//
 // Engine construction and deletion.
 //===----------------------------------------------------------------------===//
@@ -166,9 +184,9 @@
 GRExprEngine::~GRExprEngine() {
   BR.FlushReports();
   delete [] NSExceptionInstanceRaiseSelectors;
-  for (std::vector<Checker*>::iterator I=Checkers.begin(), E=Checkers.end();
-       I!=E; ++I)
-    delete *I;
+  for (llvm::DenseMap<void*, Checker*>::iterator I=Checkers.begin(), 
+         E=Checkers.end(); I!=E; ++I)
+    delete I->second;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1188,58 +1206,11 @@
   SaveAndRestore<const void*> OldTag(Builder->Tag);
   Builder->Tag = tag;
 
-  // Check for loads/stores from/to undefined values.
-  if (location.isUndef()) {
-    ExplodedNode* N =
-      Builder->generateNode(Ex, state, Pred,
-                            ProgramPoint::PostUndefLocationCheckFailedKind);
-
-    if (N) {
-      N->markAsSink();
-      UndefDeref.insert(N);
-    }
-
-    return 0;
-  }
-
-  // Check for loads/stores from/to unknown locations.  Treat as No-Ops.
   if (location.isUnknown())
     return Pred;
 
-  // During a load, one of two possible situations arise:
-  //  (1) A crash, because the location (pointer) was NULL.
-  //  (2) The location (pointer) is not NULL, and the dereference works.
-  //
-  // We add these assumptions.
-
-  Loc LV = cast<Loc>(location);
-
-  // "Assume" that the pointer is not NULL.
-  const GRState *StNotNull = state->Assume(LV, true);
-
-  // "Assume" that the pointer is NULL.
-  const GRState *StNull = state->Assume(LV, false);
-
-  if (StNull) {
-    // Use the Generic Data Map to mark in the state what lval was null.
-    const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV);
-    StNull = StNull->set<GRState::NullDerefTag>(PersistentLV);
+  return CheckerVisitLocation(Ex, Pred, state, location);
 
-    // We don't use "MakeNode" here because the node will be a sink
-    // and we have no intention of processing it later.
-    ExplodedNode* NullNode =
-      Builder->generateNode(Ex, StNull, Pred,
-                            ProgramPoint::PostNullCheckFailedKind);
-
-    if (NullNode) {
-      NullNode->markAsSink();
-      if (StNotNull) ImplicitNullDeref.insert(NullNode);
-      else ExplicitNullDeref.insert(NullNode);
-    }
-  }
-
-  if (!StNotNull)
-    return NULL;
 
   // FIXME: Temporarily disable out-of-bounds checking until we make
   // the logic reflect recent changes to CastRegion and friends.
@@ -1282,10 +1253,6 @@
     }
   }
 #endif
-
-  // Generate a new node indicating the checks succeed.
-  return Builder->generateNode(Ex, StNotNull, Pred,
-                               ProgramPoint::PostLocationChecksSucceedKind);
 }
 
 //===----------------------------------------------------------------------===//
@@ -2895,7 +2862,8 @@
 template<>
 struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
   public DefaultDOTGraphTraits {
-
+  // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not
+  // work.
   static std::string getNodeAttributes(const ExplodedNode* N, void*) {
 
     if (GraphPrintCheckerState->isImplicitNullDeref(N) ||

Modified: cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp?rev=85471&r1=85470&r2=85471&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp Wed Oct 28 21:09:30 2009
@@ -15,6 +15,7 @@
 #include "clang/Analysis/PathSensitive/BugReporter.h"
 #include "clang/Analysis/PathSensitive/GRExprEngine.h"
 #include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/NullDerefChecker.h"
 #include "clang/Analysis/PathDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/Support/Compiler.h"
@@ -40,10 +41,8 @@
 //===----------------------------------------------------------------------===//
 // Bug Descriptions.
 //===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport {
+namespace clang {
+class BuiltinBugReport : public RangedBugReport {
 public:
   BuiltinBugReport(BugType& bt, const char* desc,
                    ExplodedNode *n)
@@ -57,58 +56,22 @@
                                const ExplodedNode* N);
 };
 
-class VISIBILITY_HIDDEN BuiltinBug : public BugType {
-  GRExprEngine &Eng;
-protected:
-  const std::string desc;
-public:
-  BuiltinBug(GRExprEngine *eng, const char* n, const char* d)
-    : BugType(n, "Logic errors"), Eng(*eng), desc(d) {}
-
-  BuiltinBug(GRExprEngine *eng, const char* n)
-    : BugType(n, "Logic errors"), Eng(*eng), desc(n) {}
-
-  const std::string &getDescription() const { return desc; }
-
-  virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {}
-
-  void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
-
-  virtual void registerInitialVisitors(BugReporterContext& BRC,
-                                       const ExplodedNode* N,
-                                       BuiltinBugReport *R) {}
-
-  template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E);
-};
-
+void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
+                                               const ExplodedNode* N) {
+  static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
+}
 
 template <typename ITER>
 void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
   for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(),
                                                          GetNode(I)));
 }
-
-void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
-                                               const ExplodedNode* N) {
-  static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
+void NullDeref::registerInitialVisitors(BugReporterContext& BRC,
+                                        const ExplodedNode* N,
+                                        BuiltinBugReport *R) {
+  registerTrackNullOrUndefValue(BRC, bugreporter::GetDerefExpr(N), N);
 }
 
-class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
-public:
-  NullDeref(GRExprEngine* eng)
-    : BuiltinBug(eng,"Null dereference", "Dereference of null pointer") {}
-
-  void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
-    Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
-  }
-
-  void registerInitialVisitors(BugReporterContext& BRC,
-                               const ExplodedNode* N,
-                               BuiltinBugReport *R) {
-    registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
-  }
-};
-
 class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
 public:
   NilReceiverStructRet(GRExprEngine* eng) :
@@ -175,14 +138,12 @@
   }
 };
 
+
+
 class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug {
 public:
-  UndefinedDeref(GRExprEngine* eng)
-    : BuiltinBug(eng,"Dereference of undefined pointer value") {}
-
-  void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
-    Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end());
-  }
+  UndefinedDeref() 
+    : BuiltinBug(0, "Dereference of undefined pointer value") {}
 
   void registerInitialVisitors(BugReporterContext& BRC,
                                const ExplodedNode* N,
@@ -595,7 +556,7 @@
   CheckAttrNonNull() : BT(0) {}
   ~CheckAttrNonNull() {}
 
-  const void *getTag() {
+  static void *getTag() {
     static int x = 0;
     return &x;
   }
@@ -676,10 +637,9 @@
       C.addTransition(C.GenerateNode(CE, state));
   }
 };
-} // end anonymous namespace
 
 // Undefined arguments checking.
-namespace {
+
 class VISIBILITY_HIDDEN CheckUndefinedArg
   : public CheckerVisitor<CheckUndefinedArg> {
 
@@ -689,7 +649,7 @@
   CheckUndefinedArg() : BT(0) {}
   ~CheckUndefinedArg() {}
 
-  const void *getTag() {
+  static void *getTag() {
     static int x = 0;
     return &x;
   }
@@ -721,7 +681,7 @@
   CheckBadCall() : BT(0) {}
   ~CheckBadCall() {}
 
-  const void *getTag() {
+  static void *getTag() {
     static int x = 0;
     return &x;
   }
@@ -748,7 +708,7 @@
   CheckDivZero() : BT(0) {}
   ~CheckDivZero() {}
 
-  const void *getTag() {
+  static void *getTag() {
     static int x;
     return &x;
   }
@@ -797,7 +757,85 @@
   if (stateNotZero != C.getState())
     C.addTransition(C.GenerateNode(B, stateNotZero));
 }
+
+class VISIBILITY_HIDDEN CheckUndefDeref : public Checker {
+  UndefinedDeref *BT;
+public:
+  CheckUndefDeref() : BT(0) {}
+
+  ExplodedNode *CheckSVal(const Stmt *S, ExplodedNode *Pred,
+                          const GRState *state, SVal V, GRExprEngine &Eng);
+
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+};
+
+ExplodedNode *CheckUndefDeref::CheckSVal(const Stmt *S, ExplodedNode *Pred,
+                                         const GRState *state, SVal V,
+                                         GRExprEngine &Eng) {
+  GRStmtNodeBuilder &Builder = Eng.getBuilder();
+  BugReporter &BR = Eng.getBugReporter();
+
+  if (V.isUndef()) {
+    ExplodedNode *N = Builder.generateNode(S, state, Pred, 
+                               ProgramPoint::PostUndefLocationCheckFailedKind);
+    if (N) {
+      if (!BT)
+        BT = new UndefinedDeref();
+
+      N->markAsSink();
+      BR.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
+    }
+    return 0;
+  }
+
+  return Pred;
+}
+
+ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred,
+                                        const GRState *state, SVal V,
+                                        GRExprEngine &Eng) {
+  Loc *LV = dyn_cast<Loc>(&V);
+
+  // If the value is not a location, don't touch the node.
+  if (!LV)
+    return Pred;
+
+  const GRState *NotNullState = state->Assume(*LV, true);
+  const GRState *NullState = state->Assume(*LV, false);
+
+  GRStmtNodeBuilder &Builder = Eng.getBuilder();
+  BugReporter &BR = Eng.getBugReporter();
+
+  // The explicit NULL case.
+  if (NullState) {
+    // Use the GDM to mark in the state what lval was null.
+    const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV);
+    NullState = NullState->set<GRState::NullDerefTag>(PersistentLV);
+
+    ExplodedNode *N = Builder.generateNode(S, NullState, Pred,
+                                         ProgramPoint::PostNullCheckFailedKind);
+    if (N) {
+      N->markAsSink();
+      
+      if (!NotNullState) { // Explicit null case.
+        if (!BT)
+          BT = new NullDeref();
+        BR.EmitReport(new BuiltinBugReport(*BT,BT->getDescription().c_str(),N));
+        return 0;
+      } else // Implicit null case.
+        ImplicitNullDerefNodes.push_back(N);
+    }
+  }
+
+  if (!NotNullState)
+    return 0;
+  return Builder.generateNode(S, NotNullState, Pred, 
+                              ProgramPoint::PostLocationChecksSucceedKind);
 }
+} // end clang namespace
 //===----------------------------------------------------------------------===//
 // Check registration.
 //===----------------------------------------------------------------------===//
@@ -808,8 +846,6 @@
   // create BugReports on-the-fly but instead wait until GRExprEngine finishes
   // analyzing a function.  Generation of BugReport objects is done via a call
   // to 'FlushReports' from BugReporter.
-  BR.Register(new NullDeref(this));
-  BR.Register(new UndefinedDeref(this));
   BR.Register(new UndefBranch(this));
   BR.Register(new UndefResult(this));
   BR.Register(new RetStack(this));
@@ -826,8 +862,10 @@
   // their associated BugType will get registered with the BugReporter
   // automatically.  Note that the check itself is owned by the GRExprEngine
   // object.
-  registerCheck(new CheckAttrNonNull());
-  registerCheck(new CheckUndefinedArg());
-  registerCheck(new CheckBadCall());
-  registerCheck(new CheckDivZero());
+  registerCheck<CheckAttrNonNull>(new CheckAttrNonNull());
+  registerCheck<CheckUndefinedArg>(new CheckUndefinedArg());
+  registerCheck<CheckBadCall>(new CheckBadCall());
+  registerCheck<CheckDivZero>(new CheckDivZero());
+  registerCheck<CheckUndefDeref>(new CheckUndefDeref());
+  registerCheck<NullDerefChecker>(new NullDerefChecker());
 }





More information about the cfe-commits mailing list