diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/CheckerManager.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Core/CheckerManager.cpp | 136 | 
1 files changed, 101 insertions, 35 deletions
| diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index ba7c384e5c36..acacfb0e18c6 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -12,8 +12,9 @@  //===----------------------------------------------------------------------===//  #include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/CheckerProvider.h" +#include "clang/StaticAnalyzer/Core/Checker.h"  #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"  #include "clang/Analysis/ProgramPoint.h"  #include "clang/AST/DeclBase.h" @@ -33,7 +34,8 @@ bool CheckerManager::hasPathSensitiveCheckers() const {           !DeadSymbolsCheckers.empty()       ||           !RegionChangesCheckers.empty()     ||           !EvalAssumeCheckers.empty()        || -         !EvalCallCheckers.empty(); +         !EvalCallCheckers.empty()          || +         !InlineCallCheckers.empty();  }  void CheckerManager::finishedCheckerRegistration() { @@ -122,7 +124,7 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx,  namespace {    struct CheckStmtContext { -    typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; +    typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;      bool IsPreVisit;      const CheckersTy &Checkers;      const Stmt *S; @@ -138,9 +140,12 @@ namespace {      void runChecker(CheckerManager::CheckStmtFunc checkFn,                      ExplodedNodeSet &Dst, ExplodedNode *Pred) {        // FIXME: Remove respondsToCallback from CheckerContext; -      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, -                       IsPreVisit ? ProgramPoint::PreStmtKind : -                                    ProgramPoint::PostStmtKind, 0, S); +      ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind : +                                           ProgramPoint::PostStmtKind; +      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, +                                Pred->getLocationContext(), checkFn.Checker); +      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); +        checkFn(S, C);      }    }; @@ -174,10 +179,12 @@ namespace {      void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,                      ExplodedNodeSet &Dst, ExplodedNode *Pred) { -      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, -                       IsPreVisit ? ProgramPoint::PreStmtKind : -                                    ProgramPoint::PostStmtKind, 0, -                       Msg.getOriginExpr()); +      ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind : +                                           ProgramPoint::PostStmtKind; +      const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(), +                                K, Pred->getLocationContext(), checkFn.Checker); +      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); +        checkFn(Msg, C);      }    }; @@ -214,10 +221,13 @@ namespace {      void runChecker(CheckerManager::CheckLocationFunc checkFn,                      ExplodedNodeSet &Dst, ExplodedNode *Pred) { -      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, -                       IsLoad ? ProgramPoint::PreLoadKind : -                       ProgramPoint::PreStoreKind, 0, S); -      checkFn(Loc, IsLoad, C); +      ProgramPoint::Kind K =  IsLoad ? ProgramPoint::PreLoadKind : +                                       ProgramPoint::PreStoreKind; +      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, +                                Pred->getLocationContext(), checkFn.Checker); +      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + +      checkFn(Loc, IsLoad, S, C);      }    };  } @@ -249,9 +259,12 @@ namespace {      void runChecker(CheckerManager::CheckBindFunc checkFn,                      ExplodedNodeSet &Dst, ExplodedNode *Pred) { -      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, -                       ProgramPoint::PreStmtKind, 0, S); -      checkFn(Loc, Val, C); +      ProgramPoint::Kind K =  ProgramPoint::PreStmtKind; +      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, +                                Pred->getLocationContext(), checkFn.Checker); +      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + +      checkFn(Loc, Val, S, C);      }    };  } @@ -293,7 +306,7 @@ void CheckerManager::runCheckersForBranchCondition(const Stmt *condition,  }  /// \brief Run checkers for live symbols. -void CheckerManager::runCheckersForLiveSymbols(const GRState *state, +void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state,                                                 SymbolReaper &SymReaper) {    for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)      LiveSymbolsCheckers[i](state, SymReaper); @@ -316,8 +329,11 @@ namespace {      void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,                      ExplodedNodeSet &Dst, ExplodedNode *Pred) { -      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, -                       ProgramPoint::PostPurgeDeadSymbolsKind, 0, S); +      ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind; +      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, +                                Pred->getLocationContext(), checkFn.Checker); +      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); +        checkFn(SR, C);      }    }; @@ -334,7 +350,7 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,  }  /// \brief True if at least one checker wants to check region changes. -bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) { +bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) {    for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)      if (RegionChangesCheckers[i].WantUpdateFn(state))        return true; @@ -343,24 +359,25 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {  }  /// \brief Run checkers for region changes. -const GRState * -CheckerManager::runCheckersForRegionChanges(const GRState *state, +const ProgramState * +CheckerManager::runCheckersForRegionChanges(const ProgramState *state,                              const StoreManager::InvalidatedSymbols *invalidated, -                                            const MemRegion * const *Begin, -                                            const MemRegion * const *End) { +                                    ArrayRef<const MemRegion *> ExplicitRegions, +                                          ArrayRef<const MemRegion *> Regions) {    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, invalidated, Begin, End); +    state = RegionChangesCheckers[i].CheckFn(state, invalidated,  +                                             ExplicitRegions, Regions);    }    return state;  }  /// \brief Run checkers for handling assumptions on symbolic values. -const GRState * -CheckerManager::runCheckersForEvalAssume(const GRState *state, +const ProgramState * +CheckerManager::runCheckersForEvalAssume(const ProgramState *state,                                           SVal Cond, bool Assumption) {    for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {      // If any checker declares the state infeasible (or if it starts that way), @@ -379,7 +396,9 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,                                              const CallExpr *CE,                                              ExprEngine &Eng,                                              GraphExpander *defaultEval) { -  if (EvalCallCheckers.empty() && defaultEval == 0) { +  if (EvalCallCheckers.empty()   && +      InlineCallCheckers.empty() && +      defaultEval == 0) {      Dst.insert(Src);      return;    } @@ -389,13 +408,50 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,      ExplodedNode *Pred = *NI;      bool anyEvaluated = false; + +    // First, check if any of the InlineCall callbacks can evaluate the call. +    assert(InlineCallCheckers.size() <= 1 && +           "InlineCall is a special hacky callback to allow intrusive" +           "evaluation of the call (which simulates inlining). It is " +           "currently only used by OSAtomicChecker and should go away " +           "at some point."); +    for (std::vector<InlineCallFunc>::iterator +           EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end(); +         EI != EE; ++EI) { +      ExplodedNodeSet checkDst; +      bool evaluated = (*EI)(CE, Eng, Pred, checkDst); +      assert(!(evaluated && anyEvaluated) +             && "There are more than one checkers evaluating the call"); +      if (evaluated) { +        anyEvaluated = true; +        Dst.insert(checkDst); +#ifdef NDEBUG +        break; // on release don't check that no other checker also evals. +#endif +      } +    } + +#ifdef NDEBUG // on release don't check that no other checker also evals. +    if (anyEvaluated) { +      break; +    } +#endif + +    // Next, check if any of the EvalCall callbacks can evaluate the call.      for (std::vector<EvalCallFunc>::iterator             EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();           EI != EE; ++EI) {        ExplodedNodeSet checkDst; -      CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker, -                       ProgramPoint::PostStmtKind, 0, CE); -      bool evaluated = (*EI)(CE, C); +      ProgramPoint::Kind K = ProgramPoint::PostStmtKind; +      const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, +                                Pred->getLocationContext(), EI->Checker); +      bool evaluated = false; +      { // CheckerContext generates transitions(populates checkDest) on +        // destruction, so introduce the scope to make sure it gets properly +        // populated. +        CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0); +        evaluated = (*EI)(CE, C); +      }        assert(!(evaluated && anyEvaluated)               && "There are more than one checkers evaluating the call");        if (evaluated) { @@ -407,6 +463,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,        }      } +    // If none of the checkers evaluated the call, ask ExprEngine to handle it.      if (!anyEvaluated) {        if (defaultEval)          defaultEval->expandGraph(Dst, Pred); @@ -425,6 +482,14 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit(      EndOfTranslationUnitCheckers[i](TU, mgr, BR);  } +void CheckerManager::runCheckersForPrintState(raw_ostream &Out, +                                              const ProgramState *State, +                                              const char *NL, const char *Sep) { +  for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator +        I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I) +    I->second->printState(Out, State, NL, Sep); +} +  //===----------------------------------------------------------------------===//  // Internal registration functions for AST traversing.  //===----------------------------------------------------------------------===// @@ -504,6 +569,10 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {    EvalCallCheckers.push_back(checkfn);  } +void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) { +  InlineCallCheckers.push_back(checkfn); +} +  void CheckerManager::_registerForEndOfTranslationUnit(                                              CheckEndOfTranslationUnit checkfn) {    EndOfTranslationUnitCheckers.push_back(checkfn); @@ -542,7 +611,4 @@ CheckerManager::~CheckerManager() {  }  // Anchor for the vtable. -CheckerProvider::~CheckerProvider() { } - -// Anchor for the vtable.  GraphExpander::~GraphExpander() { } | 
