diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2011-02-26 22:09:03 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2011-02-26 22:09:03 +0000 | 
| commit | c3b054d250cdca485c71845089c316e10610ebad (patch) | |
| tree | abae0246ec9156cc1a7cbb947b2b0dfe95fa3189 /include/clang/StaticAnalyzer | |
| parent | bca07a4524feb4edec581062d631a13116320a24 (diff) | |
Diffstat (limited to 'include/clang/StaticAnalyzer')
13 files changed, 760 insertions, 201 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h index 42feb78b4174..afba12dc0620 100644 --- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h +++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h @@ -40,7 +40,6 @@ TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,                                    const LangOptions& lopts);  void RegisterExperimentalChecks(ExprEngine &Eng); -void RegisterExperimentalInternalChecks(ExprEngine &Eng);  void RegisterCallInliner(ExprEngine &Eng); diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 1786fe610d6b..93d795831d3c 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -72,6 +72,7 @@ protected:    friend class BugReportEquivClass;    virtual void Profile(llvm::FoldingSetNodeID& hash) const { +    hash.AddPointer(&BT);      hash.AddInteger(getLocation().getRawEncoding());      hash.AddString(Description);    } @@ -277,6 +278,8 @@ private:    void FlushReport(BugReportEquivClass& EQ); +  llvm::FoldingSet<BugReportEquivClass> EQClasses; +  protected:    BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),                                              D(d) {} @@ -302,6 +305,10 @@ public:    iterator begin() { return BugTypes.begin(); }    iterator end() { return BugTypes.end(); } +  typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; +  EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } +  EQClasses_iterator EQClasses_end() { return EQClasses.end(); } +    ASTContext& getContext() { return D.getASTContext(); }    SourceManager& getSourceManager() { return D.getSourceManager(); } @@ -344,6 +351,13 @@ public:    }    static bool classof(const BugReporter* R) { return true; } + +private: +  llvm::StringMap<BugType *> StrBugTypes; + +  /// \brief Returns a BugType that is associated with the given name and +  /// category. +  BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);  };  // FIXME: Get rid of GRBugReporter.  It's the wrong abstraction. diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h index 2793284e298f..7b9bb03d8d05 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -29,8 +29,6 @@ class BugType {  private:    const std::string Name;    const std::string Category; -  llvm::FoldingSet<BugReportEquivClass> EQClasses; -  friend class BugReporter;    bool SuppressonSink;  public:    BugType(llvm::StringRef name, llvm::StringRef cat) @@ -48,14 +46,6 @@ public:    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 { diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 65c8b80aa2a8..276819549d1a 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -14,23 +14,92 @@  #ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H  #define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H +#include "clang/Basic/LangOptions.h"  #include "llvm/ADT/SmallVector.h"  #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h"  #include <vector>  namespace clang {    class Decl; +  class Stmt; +  class CallExpr;  namespace ento {    class ExprEngine;    class AnalysisManager;    class BugReporter; +  class CheckerContext; +  class ObjCMessage; +  class SVal; +  class ExplodedNode; +  class ExplodedNodeSet; +  class ExplodedGraph; +  class GRState; +  class EndOfFunctionNodeBuilder; +  class MemRegion; +  class SymbolReaper; + +class GraphExpander { +public: +  virtual ~GraphExpander(); +  virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0; +}; + +struct VoidCheckerFnParm {}; +template <typename P1=VoidCheckerFnParm, typename P2=VoidCheckerFnParm, +          typename P3=VoidCheckerFnParm, typename P4=VoidCheckerFnParm> +class CheckerFn { +  typedef void (*Func)(void *, P1, P2, P3, P4); +  Func Fn; +public: +  void *Checker; +  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } +  void operator()(P1 p1, P2 p2, P3 p3, P4 p4) { Fn(Checker, p1, p2, p3, p4); }  +}; + +template <typename P1, typename P2, typename P3> +class CheckerFn<P1, P2, P3, VoidCheckerFnParm> { +  typedef void (*Func)(void *, P1, P2, P3); +  Func Fn; +public: +  void *Checker; +  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } +  void operator()(P1 p1, P2 p2, P3 p3) { Fn(Checker, p1, p2, p3); }  +}; + +template <typename P1, typename P2> +class CheckerFn<P1, P2, VoidCheckerFnParm, VoidCheckerFnParm> { +  typedef void (*Func)(void *, P1, P2); +  Func Fn; +public: +  void *Checker; +  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } +  void operator()(P1 p1, P2 p2) { Fn(Checker, p1, p2); }  +}; + +template <> +class CheckerFn<VoidCheckerFnParm, VoidCheckerFnParm, VoidCheckerFnParm, +                VoidCheckerFnParm> { +  typedef void (*Func)(void *); +  Func Fn; +public: +  void *Checker; +  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } +  void operator()() { Fn(Checker); }  +};  class CheckerManager { +  const LangOptions LangOpts; +  public: +  CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { }    ~CheckerManager(); +  const LangOptions &getLangOptions() const { return LangOpts; } +    typedef void *CheckerRef; +  typedef CheckerFn<> CheckerDtor;  //===----------------------------------------------------------------------===//  // registerChecker @@ -40,17 +109,12 @@ public:    template <typename CHECKER>    void registerChecker() {      CHECKER *checker = new CHECKER(); -    Checkers.push_back(std::pair<CheckerRef, Dtor>(checker, destruct<CHECKER>)); +    CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));      CHECKER::_register(checker, *this);    } -  typedef void (*RegisterToEngFunc)(ExprEngine &Eng); -  void addCheckerRegisterFunction(RegisterToEngFunc fn) { -    Funcs.push_back(fn); -  } -  //===----------------------------------------------------------------------===// -// Functions for running checkers. +// Functions for running checkers for AST traversing..  //===----------------------------------------------------------------------===//    /// \brief Run checkers handling Decls. @@ -62,48 +126,290 @@ public:                              BugReporter &BR);  //===----------------------------------------------------------------------===// -// Internal registration functions. +// Functions for running checkers for path-sensitive checking. +//===----------------------------------------------------------------------===// + +  /// \brief Run checkers for pre-visiting Stmts. +  void runCheckersForPreStmt(ExplodedNodeSet &Dst, +                             const ExplodedNodeSet &Src, +                             const Stmt *S, +                             ExprEngine &Eng) { +    runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); +  } + +  /// \brief Run checkers for post-visiting Stmts. +  void runCheckersForPostStmt(ExplodedNodeSet &Dst, +                              const ExplodedNodeSet &Src, +                              const Stmt *S, +                              ExprEngine &Eng) { +    runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng); +  } + +  /// \brief Run checkers for visiting Stmts. +  void runCheckersForStmt(bool isPreVisit, +                          ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, +                          const Stmt *S, ExprEngine &Eng); + +  /// \brief Run checkers for pre-visiting obj-c messages. +  void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, +                                    const ExplodedNodeSet &Src, +                                    const ObjCMessage &msg, +                                    ExprEngine &Eng) { +    runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng); +  } + +  /// \brief Run checkers for post-visiting obj-c messages. +  void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, +                                     const ExplodedNodeSet &Src, +                                     const ObjCMessage &msg, +                                     ExprEngine &Eng) { +    runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng); +  } + +  /// \brief Run checkers for visiting obj-c messages. +  void runCheckersForObjCMessage(bool isPreVisit, +                                 ExplodedNodeSet &Dst, +                                 const ExplodedNodeSet &Src, +                                 const ObjCMessage &msg, ExprEngine &Eng); + +  /// \brief Run checkers for load/store of a location. +  void runCheckersForLocation(ExplodedNodeSet &Dst, +                              const ExplodedNodeSet &Src, +                              SVal location, bool isLoad, +                              const Stmt *S, +                              ExprEngine &Eng); + +  /// \brief Run checkers for end of analysis. +  void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, +                                 ExprEngine &Eng); + +  /// \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, +                              const CallExpr *CE, ExprEngine &Eng, +                              GraphExpander *defaultEval = 0); + +//===----------------------------------------------------------------------===// +// Internal registration functions for AST traversing.  //===----------------------------------------------------------------------===//    // Functions used by the registration mechanism, checkers should not touch    // these directly. -  typedef void (*CheckDeclFunc)(CheckerRef checker, const Decl *D, -                                AnalysisManager& mgr, BugReporter &BR); +  typedef CheckerFn<const Decl *, AnalysisManager&, BugReporter &> +      CheckDeclFunc; +  typedef CheckerFn<const Stmt *, CheckerContext &> CheckStmtFunc; +    typedef bool (*HandlesDeclFunc)(const Decl *D); -  void _registerForDecl(CheckerRef checker, CheckDeclFunc checkfn, -                        HandlesDeclFunc isForDeclFn); +  void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); -  void _registerForBody(CheckerRef checker, CheckDeclFunc checkfn); -   -  void registerCheckersToEngine(ExprEngine &eng); +  void _registerForBody(CheckDeclFunc checkfn); + +//===----------------------------------------------------------------------===// +// Internal registration functions for path-sensitive checking. +//===----------------------------------------------------------------------===// + +  typedef CheckerFn<const ObjCMessage &, CheckerContext &> CheckObjCMessageFunc; +  typedef CheckerFn<const SVal &/*location*/, bool/*isLoad*/, CheckerContext &> +      CheckLocationFunc; +  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, +                           HandlesStmtFunc isForStmtFn); +  void _registerForPostStmt(CheckStmtFunc checkfn, +                            HandlesStmtFunc isForStmtFn); + +  void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); +  void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); + +  void _registerForLocation(CheckLocationFunc checkfn); + +  void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); + +  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; +  public: +    void *Checker; +    EvalCallFunc(void *checker, Func fn) : Fn(fn), Checker(checker) { } +    bool operator()(const CallExpr *CE, CheckerContext &C) { +      return Fn(Checker, CE, C); +    }  +  }; + +  void _registerForEvalCall(EvalCallFunc checkfn); + +//===----------------------------------------------------------------------===// +// Implementation details. +//===----------------------------------------------------------------------===//  private:    template <typename CHECKER>    static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } -  std::vector<RegisterToEngFunc> Funcs; +  std::vector<CheckerDtor> CheckerDtors;    struct DeclCheckerInfo { -    CheckerRef Checker;      CheckDeclFunc CheckFn;      HandlesDeclFunc IsForDeclFn;    };    std::vector<DeclCheckerInfo> DeclCheckers; -  std::vector<std::pair<CheckerRef, CheckDeclFunc> > BodyCheckers; - -  typedef void (*Dtor)(void *); -  std::vector<std::pair<CheckerRef, Dtor> > Checkers; +  std::vector<CheckDeclFunc> BodyCheckers; -  typedef llvm::SmallVector<std::pair<CheckerRef, CheckDeclFunc>, 4> -      CachedDeclCheckers; +  typedef llvm::SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;    typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;    CachedDeclCheckersMapTy CachedDeclCheckersMap; + +  struct StmtCheckerInfo { +    CheckStmtFunc CheckFn; +    HandlesStmtFunc IsForStmtFn; +    bool IsPreVisit; +  }; +  std::vector<StmtCheckerInfo> StmtCheckers; + +  struct CachedStmtCheckersKey { +    unsigned StmtKind; +    bool IsPreVisit; + +    CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { } +    CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit) +      : StmtKind(stmtKind), IsPreVisit(isPreVisit) { } + +    static CachedStmtCheckersKey getSentinel() { +      return CachedStmtCheckersKey(~0U, 0); +    } +    unsigned getHashValue() const { +      llvm::FoldingSetNodeID ID; +      ID.AddInteger(StmtKind); +      ID.AddBoolean(IsPreVisit); +      return ID.ComputeHash(); +    } +    bool operator==(const CachedStmtCheckersKey &RHS) const { +      return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit; +    } +  }; +  friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>; + +  typedef llvm::SmallVector<CheckStmtFunc, 4> CachedStmtCheckers; +  typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers> +      CachedStmtCheckersMapTy; +  CachedStmtCheckersMapTy CachedStmtCheckersMap; + +  CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit); + +  std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; +  std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; + +  std::vector<CheckLocationFunc> LocationCheckers; + +  std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; + +  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;  };  } // end ento namespace  } // end clang namespace +namespace llvm { +  /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key +  /// in DenseMap and DenseSets. +  template <> +  struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> { +    static inline clang::ento::CheckerManager::CachedStmtCheckersKey +        getEmptyKey() { +      return clang::ento::CheckerManager::CachedStmtCheckersKey(); +    } +    static inline clang::ento::CheckerManager::CachedStmtCheckersKey +        getTombstoneKey() { +      return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel(); +    } + +    static unsigned +        getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) { +      return S.getHashValue(); +    } + +    static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS, +                       clang::ento::CheckerManager::CachedStmtCheckersKey RHS) { +      return LHS == RHS; +    } +  }; +} // end namespace llvm +  #endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h index 414ad92b2a5a..40b838e75886 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h +++ b/include/clang/StaticAnalyzer/Core/CheckerProvider.h @@ -17,6 +17,10 @@  #include "llvm/ADT/StringRef.h"  #include <vector> +namespace llvm { +  class raw_ostream; +} +  namespace clang {  namespace ento { @@ -45,6 +49,7 @@ public:    virtual ~CheckerProvider();    virtual void registerCheckers(CheckerManager &checkerMgr,                            CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0; +  virtual void printHelp(llvm::raw_ostream &OS) = 0;  };  } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/CheckerV2.h index 8c96866f1c99..e080d190ab75 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerV2.h +++ b/include/clang/StaticAnalyzer/Core/CheckerV2.h @@ -41,7 +41,9 @@ class ASTDecl {  public:    template <typename CHECKER>    static void _register(CHECKER *checker, CheckerManager &mgr) { -    mgr._registerForDecl(checker, _checkDecl<CHECKER>, _handlesDecl); +    mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker, +                                                       _checkDecl<CHECKER>), +                         _handlesDecl);    }  }; @@ -55,12 +57,197 @@ class ASTCodeBody {  public:    template <typename CHECKER>    static void _register(CHECKER *checker, CheckerManager &mgr) { -    mgr._registerForBody(checker, _checkBody<CHECKER>); +    mgr._registerForBody(CheckerManager::CheckDeclFunc(checker, +                                                       _checkBody<CHECKER>)); +  } +}; + +template <typename STMT> +class PreStmt { +  template <typename CHECKER> +  static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { +    ((const CHECKER *)checker)->checkPreStmt(llvm::cast<STMT>(S), C); +  } + +  static bool _handlesStmt(const Stmt *S) { +    return llvm::isa<STMT>(S); +  } +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker, +                                                          _checkStmt<CHECKER>), +                            _handlesStmt); +  } +}; + +template <typename STMT> +class PostStmt { +  template <typename CHECKER> +  static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { +    ((const CHECKER *)checker)->checkPostStmt(llvm::cast<STMT>(S), C); +  } + +  static bool _handlesStmt(const Stmt *S) { +    return llvm::isa<STMT>(S); +  } +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker, +                                                           _checkStmt<CHECKER>), +                             _handlesStmt); +  } +}; + +class PreObjCMessage { +  template <typename CHECKER> +  static void _checkObjCMessage(void *checker, const ObjCMessage &msg, +                                CheckerContext &C) { +    ((const CHECKER *)checker)->checkPreObjCMessage(msg, C); +  } + +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForPreObjCMessage( +     CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); +  } +}; + +class PostObjCMessage { +  template <typename CHECKER> +  static void _checkObjCMessage(void *checker, const ObjCMessage &msg, +                                CheckerContext &C) { +    ((const CHECKER *)checker)->checkPostObjCMessage(msg, C); +  } + +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForPostObjCMessage( +     CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); +  } +}; + +class Location { +  template <typename CHECKER> +  static void _checkLocation(void *checker, const SVal &location, bool isLoad, +                             CheckerContext &C) { +    ((const CHECKER *)checker)->checkLocation(location, isLoad, C); +  } + +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForLocation( +           CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>)); +  } +}; + +class EndAnalysis { +  template <typename CHECKER> +  static void _checkEndAnalysis(void *checker, ExplodedGraph &G, +                                BugReporter &BR, ExprEngine &Eng) { +    ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); +  } + +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForEndAnalysis( +     CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>)); +  } +}; + +class EndPath { +  template <typename CHECKER> +  static void _checkEndPath(void *checker, EndOfFunctionNodeBuilder &B, +                            ExprEngine &Eng) { +    ((const CHECKER *)checker)->checkEndPath(B, Eng); +  } + +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForEndPath( +     CheckerManager::CheckEndPathFunc(checker, _checkEndPath<CHECKER>)); +  } +}; + +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 { + +class Call { +  template <typename CHECKER> +  static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) { +    return ((const CHECKER *)checker)->evalCall(CE, C); +  } + +public: +  template <typename CHECKER> +  static void _register(CHECKER *checker, CheckerManager &mgr) { +    mgr._registerForEvalCall( +                     CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>)); +  } +}; + +} // end eval namespace +  template <typename CHECK1, typename CHECK2=check::_VoidCheck,            typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,            typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h index 22c202749ba7..627bc0ab3516 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h @@ -15,8 +15,7 @@  #ifndef LLVM_CLANG_GR_CHECKER  #define LLVM_CLANG_GR_CHECKER -#include "clang/Analysis/Support/SaveAndRestore.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"  //===----------------------------------------------------------------------===//  // Checker interface. @@ -26,163 +25,6 @@ namespace clang {  namespace ento { -class CheckerContext { -  ExplodedNodeSet &Dst; -  StmtNodeBuilder &B; -  ExprEngine &Eng; -  ExplodedNode *Pred; -  SaveAndRestore<bool> OldSink; -  const void *checkerTag; -  SaveAndRestore<ProgramPoint::Kind> OldPointKind; -  SaveOr OldHasGen; -  const GRState *ST; -  const Stmt *statement; -  const unsigned size; -public: -  bool *respondsToCallback; -public: -  CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder, -                 ExprEngine &eng, ExplodedNode *pred, -                 const void *tag, ProgramPoint::Kind K, -                 bool *respondsToCB = 0, -                 const Stmt *stmt = 0, const GRState *st = 0) -    : Dst(dst), B(builder), Eng(eng), Pred(pred), -      OldSink(B.BuildSinks), -      checkerTag(tag), -      OldPointKind(B.PointKind, K), -      OldHasGen(B.hasGeneratedNode), -      ST(st), statement(stmt), size(Dst.size()), -      respondsToCallback(respondsToCB) {} - -  ~CheckerContext(); - -  ExprEngine &getEngine() { -    return Eng; -  } - -  AnalysisManager &getAnalysisManager() { -    return Eng.getAnalysisManager(); -  } - -  ConstraintManager &getConstraintManager() { -    return Eng.getConstraintManager(); -  } - -  StoreManager &getStoreManager() { -    return Eng.getStoreManager(); -  } - -  ExplodedNodeSet &getNodeSet() { return Dst; } -  StmtNodeBuilder &getNodeBuilder() { return B; } -  ExplodedNode *&getPredecessor() { return Pred; } -  const GRState *getState() { return ST ? ST : B.GetState(Pred); } - -  ASTContext &getASTContext() { -    return Eng.getContext(); -  } -   -  BugReporter &getBugReporter() { -    return Eng.getBugReporter(); -  } -   -  SourceManager &getSourceManager() { -    return getBugReporter().getSourceManager(); -  } - -  SValBuilder &getSValBuilder() { -    return Eng.getSValBuilder(); -  } - -  ExplodedNode *generateNode(bool autoTransition = true) { -    assert(statement && "Only transitions with statements currently supported"); -    ExplodedNode *N = generateNodeImpl(statement, getState(), false, -                                       checkerTag); -    if (N && autoTransition) -      Dst.Add(N); -    return N; -  } -   -  ExplodedNode *generateNode(const Stmt *stmt, const GRState *state, -                             bool autoTransition = true, const void *tag = 0) { -    assert(state); -    ExplodedNode *N = generateNodeImpl(stmt, state, false, -                                       tag ? tag : checkerTag); -    if (N && autoTransition) -      addTransition(N); -    return N; -  } - -  ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred, -                             bool autoTransition = true) { -   assert(statement && "Only transitions with statements currently supported"); -    ExplodedNode *N = generateNodeImpl(statement, state, pred, false); -    if (N && autoTransition) -      addTransition(N); -    return N; -  } - -  ExplodedNode *generateNode(const GRState *state, bool autoTransition = true, -                             const void *tag = 0) { -    assert(statement && "Only transitions with statements currently supported"); -    ExplodedNode *N = generateNodeImpl(statement, state, false, -                                       tag ? tag : checkerTag); -    if (N && autoTransition) -      addTransition(N); -    return N; -  } - -  ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) { -    return generateNodeImpl(stmt, state ? state : getState(), true, -                            checkerTag); -  } -   -  ExplodedNode *generateSink(const GRState *state = 0) { -    assert(statement && "Only transitions with statements currently supported"); -    return generateNodeImpl(statement, state ? state : getState(), true, -                            checkerTag); -  } - -  void addTransition(ExplodedNode *node) { -    Dst.Add(node); -  } -   -  void addTransition(const GRState *state, const void *tag = 0) { -    assert(state); -    // If the 'state' is not new, we need to check if the cached state 'ST' -    // is new. -    if (state != getState() || (ST && ST != B.GetState(Pred))) -      // state is new or equals to ST. -      generateNode(state, true, tag); -    else -      Dst.Add(Pred); -  } - -  void EmitReport(BugReport *R) { -    Eng.getBugReporter().EmitReport(R); -  } - -  AnalysisContext *getCurrentAnalysisContext() const { -    return Pred->getLocationContext()->getAnalysisContext(); -  } - -private: -  ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, -                             bool markAsSink, const void *tag) { -    ExplodedNode *node = B.generateNode(stmt, state, Pred, tag); -    if (markAsSink && node) -      node->markAsSink(); -    return node; -  } - -  ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, -                                 ExplodedNode *pred, bool markAsSink) { -   ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag); -    if (markAsSink && node) -      node->markAsSink(); -    return node; -  } -}; -  class Checker {  private:    friend class ExprEngine; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h new file mode 100644 index 000000000000..4429c6b2a7ad --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -0,0 +1,187 @@ +//== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file defines CheckerContext that provides contextual info for +// path-sensitive checkers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT +#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT + +#include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" + +namespace clang { + +namespace ento { + +class CheckerContext { +  ExplodedNodeSet &Dst; +  StmtNodeBuilder &B; +  ExprEngine &Eng; +  ExplodedNode *Pred; +  SaveAndRestore<bool> OldSink; +  const void *checkerTag; +  SaveAndRestore<ProgramPoint::Kind> OldPointKind; +  SaveOr OldHasGen; +  const GRState *ST; +  const Stmt *statement; +  const unsigned size; +public: +  bool *respondsToCallback; +public: +  CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder, +                 ExprEngine &eng, ExplodedNode *pred, +                 const void *tag, ProgramPoint::Kind K, +                 bool *respondsToCB = 0, +                 const Stmt *stmt = 0, const GRState *st = 0) +    : Dst(dst), B(builder), Eng(eng), Pred(pred), +      OldSink(B.BuildSinks), +      checkerTag(tag), +      OldPointKind(B.PointKind, K), +      OldHasGen(B.hasGeneratedNode), +      ST(st), statement(stmt), size(Dst.size()), +      respondsToCallback(respondsToCB) {} + +  ~CheckerContext(); + +  ExprEngine &getEngine() { +    return Eng; +  } + +  AnalysisManager &getAnalysisManager() { +    return Eng.getAnalysisManager(); +  } + +  ConstraintManager &getConstraintManager() { +    return Eng.getConstraintManager(); +  } + +  StoreManager &getStoreManager() { +    return Eng.getStoreManager(); +  } + +  ExplodedNodeSet &getNodeSet() { return Dst; } +  StmtNodeBuilder &getNodeBuilder() { return B; } +  ExplodedNode *&getPredecessor() { return Pred; } +  const GRState *getState() { return ST ? ST : B.GetState(Pred); } +  const Stmt *getStmt() const { return statement; } + +  ASTContext &getASTContext() { +    return Eng.getContext(); +  } +   +  BugReporter &getBugReporter() { +    return Eng.getBugReporter(); +  } +   +  SourceManager &getSourceManager() { +    return getBugReporter().getSourceManager(); +  } + +  SValBuilder &getSValBuilder() { +    return Eng.getSValBuilder(); +  } + +  ExplodedNode *generateNode(bool autoTransition = true) { +    assert(statement && "Only transitions with statements currently supported"); +    ExplodedNode *N = generateNodeImpl(statement, getState(), false, +                                       checkerTag); +    if (N && autoTransition) +      Dst.Add(N); +    return N; +  } +   +  ExplodedNode *generateNode(const Stmt *stmt, const GRState *state, +                             bool autoTransition = true, const void *tag = 0) { +    assert(state); +    ExplodedNode *N = generateNodeImpl(stmt, state, false, +                                       tag ? tag : checkerTag); +    if (N && autoTransition) +      addTransition(N); +    return N; +  } + +  ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred, +                             bool autoTransition = true) { +   assert(statement && "Only transitions with statements currently supported"); +    ExplodedNode *N = generateNodeImpl(statement, state, pred, false); +    if (N && autoTransition) +      addTransition(N); +    return N; +  } + +  ExplodedNode *generateNode(const GRState *state, bool autoTransition = true, +                             const void *tag = 0) { +    assert(statement && "Only transitions with statements currently supported"); +    ExplodedNode *N = generateNodeImpl(statement, state, false, +                                       tag ? tag : checkerTag); +    if (N && autoTransition) +      addTransition(N); +    return N; +  } + +  ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) { +    return generateNodeImpl(stmt, state ? state : getState(), true, +                            checkerTag); +  } +   +  ExplodedNode *generateSink(const GRState *state = 0) { +    assert(statement && "Only transitions with statements currently supported"); +    return generateNodeImpl(statement, state ? state : getState(), true, +                            checkerTag); +  } + +  void addTransition(ExplodedNode *node) { +    Dst.Add(node); +  } +   +  void addTransition(const GRState *state, const void *tag = 0) { +    assert(state); +    // If the 'state' is not new, we need to check if the cached state 'ST' +    // is new. +    if (state != getState() || (ST && ST != B.GetState(Pred))) +      // state is new or equals to ST. +      generateNode(state, true, tag); +    else +      Dst.Add(Pred); +  } + +  void EmitReport(BugReport *R) { +    Eng.getBugReporter().EmitReport(R); +  } + +  AnalysisContext *getCurrentAnalysisContext() const { +    return Pred->getLocationContext()->getAnalysisContext(); +  } + +private: +  ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, +                             bool markAsSink, const void *tag) { +    ExplodedNode *node = B.generateNode(stmt, state, Pred, tag); +    if (markAsSink && node) +      node->markAsSink(); +    return node; +  } + +  ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, +                                 ExplodedNode *pred, bool markAsSink) { +   ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag); +    if (markAsSink && node) +      node->markAsSink(); +    return node; +  } +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 800e63a4cdeb..25c644734232 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -447,16 +447,22 @@ class EndOfFunctionNodeBuilder {    CoreEngine &Eng;    const CFGBlock& B;    ExplodedNode* Pred; +  void *Tag;  public:    bool hasGeneratedNode;  public: -  EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e) -    : Eng(*e), B(*b), Pred(N), hasGeneratedNode(false) {} +  EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e, +                           void *checkerTag = 0) +    : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {}    ~EndOfFunctionNodeBuilder(); +  EndOfFunctionNodeBuilder withCheckerTag(void *tag) { +    return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag); +  } +    WorkList &getWorkList() { return *Eng.WList; }    ExplodedNode* getPredecessor() const { return Pred; } @@ -471,8 +477,8 @@ public:                                             B.getBlockID());    } -  ExplodedNode* generateNode(const GRState* State, const void *tag = 0, -                             ExplodedNode *P = 0); +  ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0, +                             const void *tag = 0);    void GenerateCallExitNode(const GRState *state); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 767644a03292..16f54ee7468d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -137,6 +137,10 @@ public:    virtual AnalysisManager &getAnalysisManager() { return AMgr; } +  CheckerManager &getCheckerManager() const { +    return *AMgr.getCheckerManager(); +  } +    SValBuilder &getSValBuilder() { return svalBuilder; }    TransferFuncs& getTF() { return *TF; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h index 411441f8fe34..07cdbf523427 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h @@ -151,7 +151,21 @@ namespace ento {      typedef bool data_type;      static inline data_type MakeData(void* const* p) { -      return (bool) (uintptr_t) p; +      return p ? (data_type) (uintptr_t) *p +               : data_type(); +    } +    static inline void *MakeVoidPtr(data_type d) { +      return (void*) (uintptr_t) d; +    } +  }; +   +  // Partial specialization for unsigned. +  template <> struct GRStatePartialTrait<unsigned> { +    typedef unsigned data_type; + +    static inline data_type MakeData(void* const* p) { +      return p ? (data_type) (uintptr_t) *p +               : data_type();      }      static inline void *MakeVoidPtr(data_type d) {        return (void*) (uintptr_t) d; diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h index 4c3e379f3345..9d6298f36e3b 100644 --- a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -12,12 +12,15 @@  namespace clang {    class AnalyzerOptions; +  class LangOptions;    class Diagnostic;  namespace ento {    class CheckerManager; -CheckerManager *registerCheckers(const AnalyzerOptions &opts,Diagnostic &diags); +CheckerManager *registerCheckers(const AnalyzerOptions &opts, +                                 const LangOptions &langOpts, +                                 Diagnostic &diags);  } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index e3867a2a2478..f01418175281 100644 --- a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -26,6 +26,8 @@ protected:                                           llvm::StringRef InFile);  }; +void printCheckerHelp(llvm::raw_ostream &OS); +  } // end GR namespace  } // end namespace clang  | 
