diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Analysis/CFRefCount.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Analysis/CallAndMessageChecker.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Analysis/GRExprEngine.cpp | 98 |
3 files changed, 73 insertions, 83 deletions
diff --git a/clang/lib/Analysis/CFRefCount.cpp b/clang/lib/Analysis/CFRefCount.cpp index b95f981275e..0e4c1b1a017 100644 --- a/clang/lib/Analysis/CFRefCount.cpp +++ b/clang/lib/Analysis/CFRefCount.cpp @@ -1985,7 +1985,7 @@ public: Expr* Receiver, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred); + ExplodedNode* Pred, const GRState *state); virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, @@ -1998,7 +1998,8 @@ public: GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); + ExplodedNode* Pred, + const GRState *state); bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, GRExprEngine& Engine, @@ -2777,10 +2778,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, Expr* Receiver, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred) { - - // Get the state. - const GRState *state = Builder.GetState(Pred); + ExplodedNode* Pred, const GRState *state) { // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; @@ -3013,34 +3011,23 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, assert(Summ); EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, - CE->arg_begin(), CE->arg_end(), Pred); + CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred)); } void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred) { - // FIXME: Since we moved the nil check into a checker, we could get nil - // receiver here. Need a better way to check such case. - if (Expr* Receiver = ME->getReceiver()) { - const GRState *state = Pred->getState(); - DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); - if (!state->Assume(L, true)) { - Dst.Add(Pred); - return; - } - } - + ExplodedNode* Pred, + const GRState *state) { RetainSummary *Summ = ME->getReceiver() - ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred), - Pred->getLocationContext()) + ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) : Summaries.getClassMethodSummary(ME); assert(Summ && "RetainSummary is null"); EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, - ME->arg_begin(), ME->arg_end(), Pred); + ME->arg_begin(), ME->arg_end(), Pred, state); } namespace { diff --git a/clang/lib/Analysis/CallAndMessageChecker.cpp b/clang/lib/Analysis/CallAndMessageChecker.cpp index d8dd16c57b8..c287354650b 100644 --- a/clang/lib/Analysis/CallAndMessageChecker.cpp +++ b/clang/lib/Analysis/CallAndMessageChecker.cpp @@ -41,6 +41,7 @@ public: void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME); private: void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); @@ -148,28 +149,12 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, } } } +} - // Check if the receiver was nil and then returns a value that may - // be garbage. - if (const Expr *Receiver = ME->getReceiver()) { - DefinedOrUnknownSVal receiverVal = - cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); - - const GRState *notNullState, *nullState; - llvm::tie(notNullState, nullState) = state->Assume(receiverVal); - - if (nullState && !notNullState) { - HandleNilReceiver(C, nullState, ME); - C.setDoneEvaluating(); // FIXME: eventually remove. - return; - } - - assert(notNullState); - state = notNullState; - } - - // Add a state transition if the state has changed. - C.addTransition(state); +bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C, + const ObjCMessageExpr *ME) { + HandleNilReceiver(C, C.getState(), ME); + return true; // Nil receiver is not handled elsewhere. } void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index 20820d4f383..c361e933842 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -116,20 +116,18 @@ public: // Checker worklist routines. //===----------------------------------------------------------------------===// -bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, +void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit) { if (Checkers.empty()) { - Dst.insert(Src); - return false; + Dst = Src; + return; } ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; - bool stopProcessingAfterCurrentChecker = false; - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst : (PrevSet == &Tmp) ? &Src : &Tmp; @@ -138,31 +136,26 @@ bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - // FIXME: Halting evaluation of the checkers is something we may - // not support later. The design is still evolving. - if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, - tag, isPrevisit)) { - if (CurrSet != &Dst) - Dst.insert(*CurrSet); - - stopProcessingAfterCurrentChecker = true; - continue; - } - assert(stopProcessingAfterCurrentChecker == false && - "Inconsistent setting of 'stopProcessingAfterCurrentChecker'"); - } - - if (stopProcessingAfterCurrentChecker) - return true; - - // Continue on to the next checker. Update the current NodeSet. + NI != NE; ++NI) + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); PrevSet = CurrSet; } // Don't autotransition. The CheckerContext objects should do this // automatically. - return false; +} + +void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred) { + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_EvalNilReceiver(Dst, *Builder, *this, ME, Pred, state, tag)) + break; + } } // FIXME: This is largely copy-paste from CheckerVisit(). Need to @@ -1922,10 +1915,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNodeSet Src, DstTmp; Src.Add(Pred); - if (CheckerVisit(ME, DstTmp, Src, true)) { - Dst.insert(DstTmp); - return; - } + CheckerVisit(ME, DstTmp, Src, true); unsigned size = Dst.size(); @@ -1934,10 +1924,38 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, Pred = *DI; bool RaisesException = false; - if (ME->getReceiver()) { + if (const Expr *Receiver = ME->getReceiver()) { + const GRState *state = Pred->getState(); + + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = + cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->Assume(receiverVal); + + // There are three cases: can be nil or non-nil, must be nil, must be + // non-nil. We handle must be nil, and merge the rest two into non-nil. + if (nilState && !notNilState) { + CheckerEvalNilReceiver(ME, Dst, nilState, Pred); + return; + } + + assert(notNilState); + // Check if the "raise" message was sent. if (ME->getSelector() == RaiseSel) RaisesException = true; + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred, notNilState); } else { @@ -1984,17 +2002,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, RaisesException = true; break; } } - } - // Check if we raise an exception. For now treat these as sinks. Eventually - // we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - if (RaisesException) - Builder->BuildSinks = true; + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; - // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred); + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred)); + } } // Handle the case where no nodes where generated. Auto-generate that |