diff options
| author | Zhongxing Xu <xuzhongxing@gmail.com> | 2009-10-29 02:09:30 +0000 | 
|---|---|---|
| committer | Zhongxing Xu <xuzhongxing@gmail.com> | 2009-10-29 02:09:30 +0000 | 
| commit | 6b8bfb376b2616759a1199910fee073db8c593c4 (patch) | |
| tree | e5cd9e70361afffd27896684249545b1f6c2fe4b /clang/lib | |
| parent | 810728962452b01ba0f532ba6c78b6ff5df7e019 (diff) | |
| download | bcm5719-llvm-6b8bfb376b2616759a1199910fee073db8c593c4.tar.gz bcm5719-llvm-6b8bfb376b2616759a1199910fee073db8c593c4.zip  | |
Move NullDeref and UndefDeref into their own checker. 
Add a CheckLocation() interface to Checker.
Now ImplicitNullDeref nodes are cached in NullDerefChecker.
More cleanups follow.
llvm-svn: 85471
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Analysis/CheckNSError.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Analysis/GRExprEngine.cpp | 90 | ||||
| -rw-r--r-- | clang/lib/Analysis/GRExprEngineInternalChecks.cpp | 170 | 
3 files changed, 137 insertions, 129 deletions
diff --git a/clang/lib/Analysis/CheckNSError.cpp b/clang/lib/Analysis/CheckNSError.cpp index 8086da58826..2398285d396 100644 --- a/clang/lib/Analysis/CheckNSError.cpp +++ b/clang/lib/Analysis/CheckNSError.cpp @@ -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 @@ void NSErrorCheck::CheckParamDeref(const VarDecl *Param,      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>(); diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index 9ed5ba5d02a..c0aed2306e3 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -118,17 +118,20 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,    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 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,    // 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(AnalysisManager &mgr)  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 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,    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 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,      }    }  #endif - -  // Generate a new node indicating the checks succeed. -  return Builder->generateNode(Ex, StNotNull, Pred, -                               ProgramPoint::PostLocationChecksSucceedKind);  }  //===----------------------------------------------------------------------===// @@ -2895,7 +2862,8 @@ namespace llvm {  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) || diff --git a/clang/lib/Analysis/GRExprEngineInternalChecks.cpp b/clang/lib/Analysis/GRExprEngineInternalChecks.cpp index da24192c9d5..ca38b05df86 100644 --- a/clang/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/clang/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -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 @@ ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) {  //===----------------------------------------------------------------------===//  // 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 @@ public:                                 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 @@ public:    }  }; + +  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 @@ public:    CheckAttrNonNull() : BT(0) {}    ~CheckAttrNonNull() {} -  const void *getTag() { +  static void *getTag() {      static int x = 0;      return &x;    } @@ -676,10 +637,9 @@ public:        C.addTransition(C.GenerateNode(CE, state));    }  }; -} // end anonymous namespace  // Undefined arguments checking. -namespace { +  class VISIBILITY_HIDDEN CheckUndefinedArg    : public CheckerVisitor<CheckUndefinedArg> { @@ -689,7 +649,7 @@ public:    CheckUndefinedArg() : BT(0) {}    ~CheckUndefinedArg() {} -  const void *getTag() { +  static void *getTag() {      static int x = 0;      return &x;    } @@ -721,7 +681,7 @@ public:    CheckBadCall() : BT(0) {}    ~CheckBadCall() {} -  const void *getTag() { +  static void *getTag() {      static int x = 0;      return &x;    } @@ -748,7 +708,7 @@ public:    CheckDivZero() : BT(0) {}    ~CheckDivZero() {} -  const void *getTag() { +  static void *getTag() {      static int x;      return &x;    } @@ -797,7 +757,85 @@ void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C,    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 @@ void GRExprEngine::RegisterInternalChecks() {    // 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 @@ void GRExprEngine::RegisterInternalChecks() {    // 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());  }  | 

