diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/CheckNSError.cpp | 6 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 90 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 170 |
3 files changed, 137 insertions, 129 deletions
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp index 8086da5882..2398285d39 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/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/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 9ed5ba5d02..c0aed2306e 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/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/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index da24192c9d..ca38b05df8 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/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()); } |