[cfe-commits] r126350 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/CheckerManager.h include/clang/StaticAnalyzer/Core/CheckerV2.h lib/StaticAnalyzer/Checkers/CStringChecker.cpp lib/StaticAnalyzer/Checkers/ExprEngine.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp

Argyrios Kyrtzidis akyrtzi at gmail.com
Wed Feb 23 17:05:30 PST 2011


Author: akirtzidis
Date: Wed Feb 23 19:05:30 2011
New Revision: 126350

URL: http://llvm.org/viewvc/llvm-project?rev=126350&view=rev
Log:
[analyzer] Migrate CStringChecker to CheckerV2.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=126350&r1=126349&r2=126350&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Wed Feb 23 19:05:30 2011
@@ -37,6 +37,8 @@
   class ExplodedGraph;
   class GRState;
   class EndOfFunctionNodeBuilder;
+  class MemRegion;
+  class SymbolReaper;
 
 class GraphExpander {
 public:
@@ -190,6 +192,24 @@
   /// \brief Run checkers for end of path.
   void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng);
 
+  /// \brief Run checkers for live symbols.
+  void runCheckersForLiveSymbols(const GRState *state,
+                                 SymbolReaper &SymReaper);
+
+  /// \brief Run checkers for dead symbols.
+  void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
+                                 const ExplodedNodeSet &Src,
+                                 SymbolReaper &SymReaper, const Stmt *S,
+                                 ExprEngine &Eng);
+
+  /// \brief True if at least one checker wants to check region changes.
+  bool wantsRegionChangeUpdate(const GRState *state);
+
+  /// \brief Run checkers for region changes.
+  const GRState *runCheckersForRegionChanges(const GRState *state,
+                                             const MemRegion * const *Begin,
+                                             const MemRegion * const *End);
+
   /// \brief Run checkers for evaluating a call.
   void runCheckersForEvalCall(ExplodedNodeSet &Dst,
                               const ExplodedNodeSet &Src,
@@ -226,6 +246,8 @@
   typedef CheckerFn<ExplodedGraph &, BugReporter &, ExprEngine &>
       CheckEndAnalysisFunc;
   typedef CheckerFn<EndOfFunctionNodeBuilder &, ExprEngine &> CheckEndPathFunc;
+  typedef CheckerFn<SymbolReaper &, CheckerContext &> CheckDeadSymbolsFunc;
+  typedef CheckerFn<const GRState *, SymbolReaper &> CheckLiveSymbolsFunc;
 
   typedef bool (*HandlesStmtFunc)(const Stmt *D);
   void _registerForPreStmt(CheckStmtFunc checkfn,
@@ -242,6 +264,40 @@
 
   void _registerForEndPath(CheckEndPathFunc checkfn);
 
+  void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn);
+
+  void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn);
+
+  class CheckRegionChangesFunc {
+    typedef const GRState * (*Func)(void *, const GRState *,
+                                    const MemRegion * const *,
+                                    const MemRegion * const *);
+    Func Fn;
+  public:
+    void *Checker;
+    CheckRegionChangesFunc(void *checker, Func fn) : Fn(fn), Checker(checker) {}
+    const GRState *operator()(const GRState *state,
+                              const MemRegion * const *begin,
+                              const MemRegion * const *end) {
+      return Fn(Checker, state, begin, end);
+    }
+  };
+
+  class WantsRegionChangeUpdateFunc {
+    typedef bool (*Func)(void *, const GRState *);
+    Func Fn;
+  public:
+    void *Checker;
+    WantsRegionChangeUpdateFunc(void *checker, Func fn)
+      : Fn(fn), Checker(checker) { }
+    bool operator()(const GRState *state) {
+      return Fn(Checker, state);
+    } 
+  };
+
+  void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
+                                 WantsRegionChangeUpdateFunc wantUpdateFn);
+
   class EvalCallFunc {
     typedef bool (*Func)(void *, const CallExpr *, CheckerContext &);
     Func Fn;
@@ -325,6 +381,16 @@
 
   std::vector<CheckEndPathFunc> EndPathCheckers;
 
+  std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers;
+
+  std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers;
+
+  struct RegionChangesCheckerInfo {
+    CheckRegionChangesFunc CheckFn;
+    WantsRegionChangeUpdateFunc WantUpdateFn;
+  };
+  std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
+
   std::vector<EvalCallFunc> EvalCallCheckers;
 };
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h?rev=126350&r1=126349&r2=126350&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h Wed Feb 23 19:05:30 2011
@@ -175,6 +175,59 @@
   }
 };
 
+class LiveSymbols {
+  template <typename CHECKER>
+  static void _checkLiveSymbols(void *checker, const GRState *state,
+                                SymbolReaper &SR) {
+    ((const CHECKER *)checker)->checkLiveSymbols(state, SR);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForLiveSymbols(
+     CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>));
+  }
+};
+
+class DeadSymbols {
+  template <typename CHECKER>
+  static void _checkDeadSymbols(void *checker,
+                                SymbolReaper &SR, CheckerContext &C) {
+    ((const CHECKER *)checker)->checkDeadSymbols(SR, C);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForDeadSymbols(
+     CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>));
+  }
+};
+
+class RegionChanges {
+  template <typename CHECKER>
+  static const GRState *_checkRegionChanges(void *checker, const GRState *state,
+                                            const MemRegion * const *Begin,
+                                            const MemRegion * const *End) {
+    return ((const CHECKER *)checker)->checkRegionChanges(state, Begin, End);
+  }
+  template <typename CHECKER>
+  static bool _wantsRegionChangeUpdate(void *checker, const GRState *state) {
+    return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForRegionChanges(
+          CheckerManager::CheckRegionChangesFunc(checker,
+                                                 _checkRegionChanges<CHECKER>),
+          CheckerManager::WantsRegionChangeUpdateFunc(checker,
+                                            _wantsRegionChangeUpdate<CHECKER>));
+  }
+};
+
 } // end check namespace
 
 namespace eval {

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=126350&r1=126349&r2=126350&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Wed Feb 23 19:05:30 2011
@@ -13,9 +13,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
 #include "llvm/ADT/StringSwitch.h"
 
@@ -23,80 +24,86 @@
 using namespace ento;
 
 namespace {
-class CStringChecker : public CheckerVisitor<CStringChecker> {
-  BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString;
+class CStringChecker : public CheckerV2< eval::Call,
+                                         check::PreStmt<DeclStmt>,
+                                         check::LiveSymbols,
+                                         check::DeadSymbols,
+                                         check::RegionChanges
+                                         > {
+  mutable llvm::OwningPtr<BugType> BT_Null, BT_Bounds, BT_BoundsWrite,
+                                   BT_Overlap, BT_NotCString;
 public:
-  CStringChecker()
-  : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0)
-  {}
   static void *getTag() { static int tag; return &tag; }
 
-  bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
-  void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
-  void MarkLiveSymbols(const GRState *state, SymbolReaper &SR);
-  void evalDeadSymbols(CheckerContext &C, SymbolReaper &SR);
-  bool wantsRegionChangeUpdate(const GRState *state);
-
-  const GRState *EvalRegionChanges(const GRState *state,
-                                   const MemRegion * const *Begin,
-                                   const MemRegion * const *End,
-                                   bool*);
-
-  typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *);
-
-  void evalMemcpy(CheckerContext &C, const CallExpr *CE);
-  void evalMemmove(CheckerContext &C, const CallExpr *CE);
-  void evalBcopy(CheckerContext &C, const CallExpr *CE);
+  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+  void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
+  void checkLiveSymbols(const GRState *state, SymbolReaper &SR) const;
+  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+  bool wantsRegionChangeUpdate(const GRState *state) const;
+
+  const GRState *checkRegionChanges(const GRState *state,
+                                    const MemRegion * const *Begin,
+                                    const MemRegion * const *End) const;
+
+  typedef void (CStringChecker::*FnCheck)(CheckerContext &,
+                                          const CallExpr *) const;
+
+  void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
+  void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
+  void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
   void evalCopyCommon(CheckerContext &C, const GRState *state,
                       const Expr *Size, const Expr *Source, const Expr *Dest,
-                      bool Restricted = false);
+                      bool Restricted = false) const;
 
-  void evalMemcmp(CheckerContext &C, const CallExpr *CE);
+  void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
 
-  void evalstrLength(CheckerContext &C, const CallExpr *CE);
-  void evalstrnLength(CheckerContext &C, const CallExpr *CE);
+  void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
+  void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
   void evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, 
-                           bool IsStrnlen = false);
+                           bool IsStrnlen = false) const;
 
-  void evalStrcpy(CheckerContext &C, const CallExpr *CE);
-  void evalStrncpy(CheckerContext &C, const CallExpr *CE);
-  void evalStpcpy(CheckerContext &C, const CallExpr *CE);
+  void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
+  void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
+  void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
   void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd,
-                        bool isStrncpy);
+                        bool isStrncpy) const;
 
   // Utility methods
   std::pair<const GRState*, const GRState*>
-  assumeZero(CheckerContext &C, const GRState *state, SVal V, QualType Ty);
+  static assumeZero(CheckerContext &C,
+                    const GRState *state, SVal V, QualType Ty);
 
-  const GRState *setCStringLength(const GRState *state, const MemRegion *MR,
-                                  SVal strLength);
-  SVal getCStringLengthForRegion(CheckerContext &C, const GRState *&state,
-                                 const Expr *Ex, const MemRegion *MR);
+  static const GRState *setCStringLength(const GRState *state,
+                                         const MemRegion *MR, SVal strLength);
+  static SVal getCStringLengthForRegion(CheckerContext &C,
+                                        const GRState *&state,
+                                        const Expr *Ex, const MemRegion *MR);
   SVal getCStringLength(CheckerContext &C, const GRState *&state,
-                        const Expr *Ex, SVal Buf);
+                        const Expr *Ex, SVal Buf) const;
 
-  const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state,
-                                  const Expr *Ex, SVal V);
+  static const GRState *InvalidateBuffer(CheckerContext &C,
+                                         const GRState *state,
+                                         const Expr *Ex, SVal V);
 
-  bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
-                       const MemRegion *MR);
+  static bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+                              const MemRegion *MR);
 
   // Re-usable checks
   const GRState *checkNonNull(CheckerContext &C, const GRState *state,
-                               const Expr *S, SVal l);
+                               const Expr *S, SVal l) const;
   const GRState *CheckLocation(CheckerContext &C, const GRState *state,
                                const Expr *S, SVal l,
-                               bool IsDestination = false);
+                               bool IsDestination = false) const;
   const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
                                    const Expr *Size,
                                    const Expr *FirstBuf,
                                    const Expr *SecondBuf = NULL,
-                                   bool FirstIsDestination = false);
+                                   bool FirstIsDestination = false) const;
   const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
                               const Expr *Size, const Expr *First,
-                              const Expr *Second);
+                              const Expr *Second) const;
   void emitOverlapBug(CheckerContext &C, const GRState *state,
-                      const Stmt *First, const Stmt *Second);
+                      const Stmt *First, const Stmt *Second) const;
 };
 
 class CStringLength {
@@ -115,14 +122,6 @@
 }
 }
 
-static void RegisterCStringChecker(ExprEngine &Eng) {
-  Eng.registerCheck(new CStringChecker());
-}
-
-void ento::registerCStringChecker(CheckerManager &mgr) {
-  mgr.addCheckerRegisterFunction(RegisterCStringChecker);
-}
-
 //===----------------------------------------------------------------------===//
 // Individual checks and utility methods.
 //===----------------------------------------------------------------------===//
@@ -141,7 +140,7 @@
 
 const GRState *CStringChecker::checkNonNull(CheckerContext &C,
                                             const GRState *state,
-                                            const Expr *S, SVal l) {
+                                            const Expr *S, SVal l) const {
   // If a previous check has failed, propagate the failure.
   if (!state)
     return NULL;
@@ -155,11 +154,11 @@
       return NULL;
 
     if (!BT_Null)
-      BT_Null = new BuiltinBug("API",
-        "Null pointer argument in call to byte string function");
+      BT_Null.reset(new BuiltinBug("API",
+        "Null pointer argument in call to byte string function"));
 
     // Generate a report for this bug.
-    BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null);
+    BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get());
     EnhancedBugReport *report = new EnhancedBugReport(*BT,
                                                       BT->getDescription(), N);
 
@@ -178,7 +177,7 @@
 const GRState *CStringChecker::CheckLocation(CheckerContext &C,
                                              const GRState *state,
                                              const Expr *S, SVal l,
-                                             bool IsDestination) {
+                                             bool IsDestination) const {
   // If a previous check has failed, propagate the failure.
   if (!state)
     return NULL;
@@ -214,16 +213,16 @@
     BuiltinBug *BT;
     if (IsDestination) {
       if (!BT_BoundsWrite) {
-        BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
-          "Byte string function overflows destination buffer");
+        BT_BoundsWrite.reset(new BuiltinBug("Out-of-bound array access",
+          "Byte string function overflows destination buffer"));
       }
-      BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
+      BT = static_cast<BuiltinBug*>(BT_BoundsWrite.get());
     } else {
       if (!BT_Bounds) {
-        BT_Bounds = new BuiltinBug("Out-of-bound array access",
-          "Byte string function accesses out-of-bound array element");
+        BT_Bounds.reset(new BuiltinBug("Out-of-bound array access",
+          "Byte string function accesses out-of-bound array element"));
       }
-      BT = static_cast<BuiltinBug*>(BT_Bounds);
+      BT = static_cast<BuiltinBug*>(BT_Bounds.get());
     }
 
     // FIXME: It would be nice to eventually make this diagnostic more clear,
@@ -248,7 +247,7 @@
                                                  const Expr *Size,
                                                  const Expr *FirstBuf,
                                                  const Expr *SecondBuf,
-                                                 bool FirstIsDestination) {
+                                                bool FirstIsDestination) const {
   // If a previous check has failed, propagate the failure.
   if (!state)
     return NULL;
@@ -311,7 +310,7 @@
                                             const GRState *state,
                                             const Expr *Size,
                                             const Expr *First,
-                                            const Expr *Second) {
+                                            const Expr *Second) const {
   // Do a simple check for overlap: if the two arguments are from the same
   // buffer, see if the end of the first is greater than the start of the second
   // or vice versa.
@@ -418,13 +417,13 @@
 }
 
 void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
-                                    const Stmt *First, const Stmt *Second) {
+                                  const Stmt *First, const Stmt *Second) const {
   ExplodedNode *N = C.generateSink(state);
   if (!N)
     return;
 
   if (!BT_Overlap)
-    BT_Overlap = new BugType("Unix API", "Improper arguments");
+    BT_Overlap.reset(new BugType("Unix API", "Improper arguments"));
 
   // Generate a report for this bug.
   RangedBugReport *report = 
@@ -485,13 +484,14 @@
   unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
   SValBuilder &svalBuilder = C.getSValBuilder();
   QualType sizeTy = svalBuilder.getContext().getSizeType();
-  SVal strLength = svalBuilder.getMetadataSymbolVal(getTag(), MR, Ex, sizeTy, Count);
+  SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
+                                                    MR, Ex, sizeTy, Count);
   state = state->set<CStringLength>(MR, strLength);
   return strLength;
 }
 
 SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
-                                      const Expr *Ex, SVal Buf) {
+                                      const Expr *Ex, SVal Buf) const {
   const MemRegion *MR = Buf.getAsRegion();
   if (!MR) {
     // If we can't get a region, see if it's something we /know/ isn't a
@@ -500,8 +500,8 @@
     if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
       if (ExplodedNode *N = C.generateNode(state)) {
         if (!BT_NotCString)
-          BT_NotCString = new BuiltinBug("API",
-            "Argument is not a null-terminated string.");
+          BT_NotCString.reset(new BuiltinBug("API",
+            "Argument is not a null-terminated string."));
 
         llvm::SmallString<120> buf;
         llvm::raw_svector_ostream os(buf);
@@ -556,8 +556,8 @@
     // The caller should always be prepared to handle this case.
     if (ExplodedNode *N = C.generateNode(state)) {
       if (!BT_NotCString)
-        BT_NotCString = new BuiltinBug("API",
-          "Argument is not a null-terminated string.");
+        BT_NotCString.reset(new BuiltinBug("API",
+          "Argument is not a null-terminated string."));
 
       llvm::SmallString<120> buf;
       llvm::raw_svector_ostream os(buf);
@@ -657,7 +657,7 @@
 
 void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
                                     const Expr *Size, const Expr *Dest,
-                                    const Expr *Source, bool Restricted) {
+                                    const Expr *Source, bool Restricted) const {
   // See if the size argument is zero.
   SVal sizeVal = state->getSVal(Size);
   QualType sizeTy = Size->getType();
@@ -690,7 +690,7 @@
 }
 
 
-void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
   // void *memcpy(void *restrict dst, const void *restrict src, size_t n);
   // The return value is the address of the destination buffer.
   const Expr *Dest = CE->getArg(0);
@@ -699,7 +699,7 @@
   evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
 }
 
-void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
   // void *memmove(void *dst, const void *src, size_t n);
   // The return value is the address of the destination buffer.
   const Expr *Dest = CE->getArg(0);
@@ -708,12 +708,12 @@
   evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
 }
 
-void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
   // void bcopy(const void *src, void *dst, size_t n);
   evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
 }
 
-void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
   // int memcmp(const void *s1, const void *s2, size_t n);
   const Expr *Left = CE->getArg(0);
   const Expr *Right = CE->getArg(1);
@@ -779,18 +779,20 @@
   }
 }
 
-void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalstrLength(CheckerContext &C,
+                                   const CallExpr *CE) const {
   // size_t strlen(const char *s);
   evalstrLengthCommon(C, CE, /* IsStrnlen = */ false);
 }
 
-void CStringChecker::evalstrnLength(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalstrnLength(CheckerContext &C,
+                                    const CallExpr *CE) const {
   // size_t strnlen(const char *s, size_t maxlen);
   evalstrLengthCommon(C, CE, /* IsStrnlen = */ true);
 }
 
 void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
-                                         bool IsStrnlen) {
+                                         bool IsStrnlen) const {
   const GRState *state = C.getState();
   const Expr *Arg = CE->getArg(0);
   SVal ArgVal = state->getSVal(Arg);
@@ -845,23 +847,23 @@
   }
 }
 
-void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
   // char *strcpy(char *restrict dst, const char *restrict src);
   evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false);
 }
 
-void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
   // char *strcpy(char *restrict dst, const char *restrict src);
   evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true);
 }
 
-void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
   // char *stpcpy(char *restrict dst, const char *restrict src);
   evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false);
 }
 
 void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
-                                      bool returnEnd, bool isStrncpy) {
+                                      bool returnEnd, bool isStrncpy) const {
   const GRState *state = C.getState();
 
   // Check that the destination is non-null
@@ -960,7 +962,7 @@
 // The driver method, and other Checker callbacks.
 //===----------------------------------------------------------------------===//
 
-bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
   // Get the callee.  All the functions we care about are C functions
   // with simple identifiers.
   const GRState *state = C.getState();
@@ -999,7 +1001,7 @@
   return true;
 }
 
-void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
   // Record string length for char a[] = "abc";
   const GRState *state = C.getState();
 
@@ -1035,15 +1037,15 @@
   C.addTransition(state);
 }
 
-bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) {
+bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
   CStringLength::EntryMap Entries = state->get<CStringLength>();
   return !Entries.isEmpty();
 }
 
-const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
-                                                 const MemRegion * const *Begin,
-                                                 const MemRegion * const *End,
-                                                 bool *) {
+const GRState *
+CStringChecker::checkRegionChanges(const GRState *state,
+                                   const MemRegion * const *Begin,
+                                   const MemRegion * const *End) const {
   CStringLength::EntryMap Entries = state->get<CStringLength>();
   if (Entries.isEmpty())
     return state;
@@ -1090,7 +1092,8 @@
   return state->set<CStringLength>(Entries);
 }
 
-void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
+void CStringChecker::checkLiveSymbols(const GRState *state,
+                                      SymbolReaper &SR) const {
   // Mark all symbols in our string length map as valid.
   CStringLength::EntryMap Entries = state->get<CStringLength>();
 
@@ -1102,7 +1105,8 @@
   }
 }
 
-void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
+void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
+                                      CheckerContext &C) const {
   if (!SR.hasDeadSymbols())
     return;
 
@@ -1124,3 +1128,7 @@
   state = state->set<CStringLength>(Entries);
   C.generateNode(state);
 }
+
+void ento::registerCStringChecker(CheckerManager &mgr) {
+  mgr.registerChecker<CStringChecker>();
+}

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=126350&r1=126349&r2=126350&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Wed Feb 23 19:05:30 2011
@@ -515,7 +515,7 @@
       return true;
   }
 
-  return false;
+  return getCheckerManager().wantsRegionChangeUpdate(state);
 }
 
 const GRState *
@@ -543,9 +543,9 @@
     CO = CO_Ref;
   }
 
-  // If there are no checkers, just return the state as is.
+  // If there are no checkers, just delegate to the checker manager.
   if (CO->empty())
-    return state;
+    return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
 
   for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
     // If any checker declares the state infeasible (or if it starts that way),
@@ -568,7 +568,7 @@
   if (NewCO.get())
     CO_Ref = NewCO.take();
 
-  return state;
+  return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
 }
 
 void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
@@ -624,6 +624,8 @@
       checker->MarkLiveSymbols(St, SymReaper);
     }
 
+    getCheckerManager().runCheckersForLiveSymbols(St, SymReaper);
+
     const StackFrameContext *SFC = LC->getCurrentStackFrame();
     CleanedState = StateMgr.removeDeadBindings(St, SFC, SymReaper);
   } else {
@@ -647,8 +649,9 @@
     getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
                             CleanedState, SymReaper);
 
+    ExplodedNodeSet checkersV1Tmp;
     if (Checkers.empty())
-      Tmp.insert(Tmp2);
+      checkersV1Tmp.insert(Tmp2);
     else {
       ExplodedNodeSet Tmp3;
       ExplodedNodeSet *SrcSet = &Tmp2;
@@ -656,7 +659,7 @@
            I != E; ++I) {
         ExplodedNodeSet *DstSet = 0;
         if (I+1 == E)
-          DstSet = &Tmp;
+          DstSet = &checkersV1Tmp;
         else {
           DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
           DstSet->clear();
@@ -672,6 +675,9 @@
       }
     }
 
+    getCheckerManager().runCheckersForDeadSymbols(Tmp, checkersV1Tmp,
+                                                 SymReaper, currentStmt, *this);
+
     if (!Builder->BuildSinks && !Builder->hasGeneratedNode)
       Tmp.Add(EntryNode);
   }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=126350&r1=126349&r2=126350&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Wed Feb 23 19:05:30 2011
@@ -227,6 +227,71 @@
   }
 }
 
+/// \brief Run checkers for live symbols.
+void CheckerManager::runCheckersForLiveSymbols(const GRState *state,
+                                               SymbolReaper &SymReaper) {
+  for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
+    LiveSymbolsCheckers[i](state, SymReaper);
+}
+
+namespace {
+  struct CheckDeadSymbolsContext {
+    typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy;
+    const CheckersTy &Checkers;
+    SymbolReaper &SR;
+    const Stmt *S;
+    ExprEngine &Eng;
+
+    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+    CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
+                            const Stmt *s, ExprEngine &eng)
+      : Checkers(checkers), SR(sr), S(s), Eng(eng) { }
+
+    void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
+                    ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+                       ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
+      checkFn(SR, C);
+    }
+  };
+}
+
+/// \brief Run checkers for dead symbols.
+void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
+                                               const ExplodedNodeSet &Src,
+                                               SymbolReaper &SymReaper,
+                                               const Stmt *S,
+                                               ExprEngine &Eng) {
+  CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng);
+  expandGraphWithCheckers(C, Dst, Src);
+}
+
+/// \brief True if at least one checker wants to check region changes.
+bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
+  for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
+    if (RegionChangesCheckers[i].WantUpdateFn(state))
+      return true;
+
+  return false;
+}
+
+/// \brief Run checkers for region changes.
+const GRState *
+CheckerManager::runCheckersForRegionChanges(const GRState *state,
+                                            const MemRegion * const *Begin,
+                                            const MemRegion * const *End) {
+  for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
+    // If any checker declares the state infeasible (or if it starts that way),
+    // bail out.
+    if (!state)
+      return NULL;
+    state = RegionChangesCheckers[i].CheckFn(state, Begin, End);
+  }
+  return state;
+}
+
 /// \brief Run checkers for evaluating a call.
 /// Only one checker will evaluate the call.
 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
@@ -324,6 +389,20 @@
   EndPathCheckers.push_back(checkfn);
 }
 
+void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
+  LiveSymbolsCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
+  DeadSymbolsCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
+                                     WantsRegionChangeUpdateFunc wantUpdateFn) {
+  RegionChangesCheckerInfo info = {checkfn, wantUpdateFn};
+  RegionChangesCheckers.push_back(info);
+}
+
 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
   EvalCallCheckers.push_back(checkfn);
 }





More information about the cfe-commits mailing list