From: Jordy Rose Date: Sun, 28 Aug 2011 05:16:28 +0000 (+0000) Subject: [analyzer] Migrate argument invalidation from CFRefCount to ExprEngine. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e38dd95dddb8f1b38469c8d0e28aa1c660489324;p=clang [analyzer] Migrate argument invalidation from CFRefCount to ExprEngine. This is a common path for function and C++ method calls, Objective-C messages and property accesses, and C++ construct-exprs. As support, add message receiver accessors to ObjCMessage and CallOrObjCMessage. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138718 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index bdbcf5b720..7a3b381301 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -410,6 +410,10 @@ protected: void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, ExplodedNode *Pred, const ProgramState *state); + const ProgramState *invalidateArguments(const ProgramState *State, + const CallOrObjCMessage &Call, + const LocationContext *LC); + const ProgramState *MarkBranch(const ProgramState *St, const Stmt *Terminator, bool branchTaken); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index 6a8a73e5b7..bff94bcdb4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -88,6 +88,21 @@ public: return 0; } + SVal getInstanceReceiverSVal(const ProgramState *State, + const LocationContext *LC) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (!isInstanceMessage()) + return UndefinedVal(); + if (const Expr *Ex = getInstanceReceiver()) + return State->getSValAsScalarOrLoc(Ex); + + // An instance message with no expression means we are sending to super. + // In this case the object reference is the same as 'self'. + const ImplicitParamDecl *SelfDecl = LC->getSelfDecl(); + assert(SelfDecl && "No message receiver Expr, but not in an ObjC method"); + return State->getSVal(State->getRegion(SelfDecl, LC)); + } + bool isInstanceMessage() const { assert(isValid() && "This ObjCMessage is uninitialized!"); if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) @@ -98,7 +113,7 @@ public: } const ObjCMethodDecl *getMethodDecl() const; - + const ObjCInterfaceDecl *getReceiverInterface() const; SourceLocation getSuperLoc() const { @@ -108,45 +123,58 @@ public: return cast(MsgOrPropE)->getReceiverLocation(); } - SourceRange getSourceRange() const { - assert(isValid() && "This ObjCMessage is uninitialized!"); + SourceRange getSourceRange() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); return MsgOrPropE->getSourceRange(); } - unsigned getNumArgs() const { - assert(isValid() && "This ObjCMessage is uninitialized!"); - if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) - return msgE->getNumArgs(); - return isPropertySetter() ? 1 : 0; - } - - SVal getArgSVal(unsigned i, const ProgramState *state) const { - assert(isValid() && "This ObjCMessage is uninitialized!"); - assert(i < getNumArgs() && "Invalid index for argument"); - if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) - return state->getSVal(msgE->getArg(i)); - assert(isPropertySetter()); - return SetterArgV; - } - - QualType getArgType(unsigned i) const { - assert(isValid() && "This ObjCMessage is uninitialized!"); - assert(i < getNumArgs() && "Invalid index for argument"); - if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) - return msgE->getArg(i)->getType(); - assert(isPropertySetter()); - return cast(MsgOrPropE)->getType(); - } - - const Expr *getArgExpr(unsigned i) const; - - SourceRange getArgSourceRange(unsigned i) const { - assert(isValid() && "This ObjCMessage is uninitialized!"); - assert(i < getNumArgs() && "Invalid index for argument"); - if (const Expr *argE = getArgExpr(i)) - return argE->getSourceRange(); - return OriginE->getSourceRange(); - } + unsigned getNumArgs() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getNumArgs(); + return isPropertySetter() ? 1 : 0; + } + + SVal getArgSVal(unsigned i, const ProgramState *state) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return state->getSVal(msgE->getArg(i)); + assert(isPropertySetter()); + return SetterArgV; + } + + QualType getArgType(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getArg(i)->getType(); + assert(isPropertySetter()); + return cast(MsgOrPropE)->getType(); + } + + const Expr *getArgExpr(unsigned i) const; + + SourceRange getArgSourceRange(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const Expr *argE = getArgExpr(i)) + return argE->getSourceRange(); + return OriginE->getSourceRange(); + } + + SourceRange getReceiverSourceRange() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) + return msgE->getReceiverRange(); + + const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); + if (propE->isObjectReceiver()) + return propE->getBase()->getSourceRange(); + + // FIXME: This isn't a range. + return propE->getReceiverLocation(); + } }; class ObjCPropertyGetter : public ObjCMessage { @@ -211,6 +239,7 @@ public: SVal getFunctionCallee() const; SVal getCXXCallee() const; + SVal getInstanceMessageReceiver(const LocationContext *LC) const; unsigned getNumArgs() const { if (!CallE) @@ -244,6 +273,11 @@ public: return getArg(i)->getSourceRange(); return Msg.getArgSourceRange(i); } + + SourceRange getReceiverSourceRange() const { + assert(isObjCMessage()); + return Msg.getReceiverSourceRange(); + } }; } diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp index 5991e5325f..7991071a54 100644 --- a/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -40,50 +40,6 @@ using namespace clang; using namespace ento; using llvm::StrInStrNoCase; -namespace { -class InstanceReceiver { - ObjCMessage Msg; - const LocationContext *LC; -public: - InstanceReceiver() : LC(0) { } - InstanceReceiver(const ObjCMessage &msg, - const LocationContext *lc = 0) : Msg(msg), LC(lc) {} - - bool isValid() const { - return Msg.isValid() && Msg.isInstanceMessage(); - } - operator bool() const { - return isValid(); - } - - SVal getSValAsScalarOrLoc(const ProgramState *state) { - assert(isValid()); - // We have an expression for the receiver? Fetch the value - // of that expression. - if (const Expr *Ex = Msg.getInstanceReceiver()) - return state->getSValAsScalarOrLoc(Ex); - - // Otherwise we are sending a message to super. In this case the - // object reference is the same as 'self'. - if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) - return state->getSVal(state->getRegion(SelfDecl, LC)); - - return UnknownVal(); - } - - SourceRange getSourceRange() const { - assert(isValid()); - if (const Expr *Ex = Msg.getInstanceReceiver()) - return Ex->getSourceRange(); - - // Otherwise we are sending a message to super. - SourceLocation L = Msg.getSuperLoc(); - assert(L.isValid()); - return SourceRange(L, L); - } -}; -} - namespace { class GenericNodeBuilderRefCount { StmtNodeBuilder *SNB; @@ -1651,28 +1607,6 @@ public: } const LangOptions& getLangOptions() const { return LOpts; } - - // Calls. - - void evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, - StmtNodeBuilder &Builder, - const CallOrObjCMessage &callOrMsg, - InstanceReceiver Receiver, const MemRegion *Callee, - ExplodedNode *Pred, const ProgramState *state); - - virtual void evalCall(ExplodedNodeSet &Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const CallExpr *CE, SVal L, - ExplodedNode *Pred); - - - virtual void evalObjCMessage(ExplodedNodeSet &Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - ObjCMessage msg, - ExplodedNode *Pred, - const ProgramState *state); }; } // end anonymous namespace @@ -2439,133 +2373,6 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { return RetTy; } -void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, - StmtNodeBuilder &Builder, - const CallOrObjCMessage &callOrMsg, - InstanceReceiver Receiver, - const MemRegion *Callee, - ExplodedNode *Pred, - const ProgramState *state) { - - SmallVector RegionsToInvalidate; - - // Invalidate all instance variables of the receiver of a message. - // FIXME: We should be able to do better with inter-procedural analysis. - if (Receiver) { - SVal V = Receiver.getSValAsScalarOrLoc(state); - if (const MemRegion *region = V.getAsRegion()) - RegionsToInvalidate.push_back(region); - } - - // Invalidate all instance variables for the callee of a C++ method call. - // FIXME: We should be able to do better with inter-procedural analysis. - // FIXME: we can probably do better for const versus non-const methods. - if (callOrMsg.isCXXCall()) { - if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion()) - RegionsToInvalidate.push_back(callee); - } - - for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) { - SVal V = callOrMsg.getArgSVal(idx); - - // If we are passing a location wrapped as an integer, unwrap it and - // invalidate the values referred by the location. - if (nonloc::LocAsInteger *Wrapped = dyn_cast(&V)) - V = Wrapped->getLoc(); - else if (!isa(V)) - continue; - - if (const MemRegion *R = V.getAsRegion()) { - // Invalidate the value of the variable passed by reference. - - // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underying region - // is a variable region then strip off the ElementRegion. - // FIXME: We really need to think about this for the general case - // as sometimes we are reasoning about arrays and other times - // about (char*), etc., is just a form of passing raw bytes. - // e.g., void *p = alloca(); foo((char*)p); - if (const ElementRegion *ER = dyn_cast(R)) { - // Checking for 'integral type' is probably too promiscuous, but - // we'll leave it in for now until we have a systematic way of - // handling all of these cases. Eventually we need to come up - // with an interface to StoreManager so that this logic can be - // approriately delegated to the respective StoreManagers while - // still allowing us to do checker-specific logic (e.g., - // invalidating reference counts), probably via callbacks. - if (ER->getElementType()->isIntegralOrEnumerationType()) { - const MemRegion *superReg = ER->getSuperRegion(); - if (isa(superReg) || isa(superReg) || - isa(superReg)) - R = cast(superReg); - } - // FIXME: What about layers of ElementRegions? - } - - // Mark this region for invalidation. We batch invalidate regions - // below for efficiency. - RegionsToInvalidate.push_back(R); - } else { - // Nuke all other arguments passed by reference. - // FIXME: is this necessary or correct? This handles the non-Region - // cases. Is it ever valid to store to these? - state = state->unbindLoc(cast(V)); - } - } - - // Block calls result in all captured values passed-via-reference to be - // invalidated. - if (const BlockDataRegion *BR = dyn_cast_or_null(Callee)) - RegionsToInvalidate.push_back(BR); - - // Invalidate designated regions using the batch invalidation API. - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned Count = Builder.getCurrentBlockCount(); - StoreManager::InvalidatedSymbols IS; - - const Expr *Ex = callOrMsg.getOriginExpr(); - - // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate - // global variables. - // NOTE: RetainReleaseChecker handles the actual invalidation of symbols. - state = - state->invalidateRegions(RegionsToInvalidate, - Ex, Count, &IS, - /* invalidateGlobals = */ - Eng.doesInvalidateGlobals(callOrMsg)); - - Builder.MakeNode(Dst, Ex, Pred, state); -} - - -void CFRefCount::evalCall(ExplodedNodeSet &Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const CallExpr *CE, SVal L, - ExplodedNode *Pred) { - - evalCallOrMessage(Dst, Eng, Builder, CallOrObjCMessage(CE, Pred->getState()), - InstanceReceiver(), L.getAsRegion(), Pred, - Pred->getState()); -} - -void CFRefCount::evalObjCMessage(ExplodedNodeSet &Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - ObjCMessage msg, - ExplodedNode *Pred, - const ProgramState *state) { - - evalCallOrMessage(Dst, Eng, Builder, CallOrObjCMessage(msg, Pred->getState()), - InstanceReceiver(msg, Pred->getLocationContext()), - /* Callee = */ 0, Pred, state); -} - //===----------------------------------------------------------------------===// // Pieces of the retain/release checker implemented using a CheckerVisitor. // More pieces of the retain/release checker will be migrated to this interface @@ -2744,7 +2551,7 @@ public: void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const; void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call, - InstanceReceiver Receiver, CheckerContext &C) const; + CheckerContext &C) const; bool evalCall(const CallExpr *CE, CheckerContext &C) const; @@ -3013,7 +2820,7 @@ void RetainReleaseChecker::checkPostStmt(const CallExpr *CE, if (!Summ) return; - checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C); + checkSummary(*Summ, CallOrObjCMessage(CE, state), C); } void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE, @@ -3030,7 +2837,7 @@ void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE, return; const ProgramState *state = C.getState(); - checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C); + checkSummary(*Summ, CallOrObjCMessage(CE, state), C); } void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg, @@ -3052,13 +2859,11 @@ void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg, if (!Summ) return; - checkSummary(*Summ, CallOrObjCMessage(Msg, state), - InstanceReceiver(Msg, Pred->getLocationContext()), C); + checkSummary(*Summ, CallOrObjCMessage(Msg, state), C); } void RetainReleaseChecker::checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &CallOrMsg, - InstanceReceiver Receiver, CheckerContext &C) const { const ProgramState *state = C.getState(); @@ -3084,13 +2889,15 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ, // Evaluate the effect on the message receiver. bool ReceiverIsTracked = false; - if (!hasErr && Receiver) { - if (SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol()) { + if (!hasErr && CallOrMsg.isObjCMessage()) { + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC); + if (SymbolRef Sym = Receiver.getAsLocSymbol()) { if (const RefVal *T = state->get(Sym)) { ReceiverIsTracked = true; state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), hasErr); if (hasErr) { - ErrorRange = Receiver.getSourceRange(); + ErrorRange = CallOrMsg.getReceiverSourceRange(); ErrorSym = Sym; } } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 579dcb3f51..de3b312234 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -198,17 +198,6 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, #endif // Default semantics: invalidate all regions passed as arguments. - SmallVector regionsToInvalidate; - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned blockCount = Builder->getCurrentBlockCount(); - - // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate - // global variables. ExplodedNodeSet destCall; for (ExplodedNodeSet::iterator @@ -216,23 +205,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, i != e; ++i) { ExplodedNode *Pred = *i; + const LocationContext *LC = Pred->getLocationContext(); const ProgramState *state = Pred->getState(); - // Accumulate list of regions that are invalidated. - for (CXXConstructExpr::const_arg_iterator - ai = E->arg_begin(), ae = E->arg_end(); - ai != ae; ++ai) - { - SVal val = state->getSVal(*ai); - if (const MemRegion *region = val.getAsRegion()) - regionsToInvalidate.push_back(region); - } - - // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate, - E, blockCount, 0, - /* invalidateGlobals = */ true); - + state = invalidateArguments(state, CallOrObjCMessage(E, state), LC); Builder->MakeNode(destCall, E, Pred, state); } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index e49d376d66..7573208744 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -13,6 +13,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/AST/DeclCXX.h" #include "clang/Analysis/Support/SaveAndRestore.h" @@ -63,6 +64,100 @@ void ExprEngine::processCallExit(CallExitNodeBuilder &B) { B.generateNode(state); } +const ProgramState * +ExprEngine::invalidateArguments(const ProgramState *State, + const CallOrObjCMessage &Call, + const LocationContext *LC) { + SmallVector RegionsToInvalidate; + + if (Call.isObjCMessage()) { + // Invalidate all instance variables of the receiver of an ObjC message. + // FIXME: We should be able to do better with inter-procedural analysis. + if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion()) + RegionsToInvalidate.push_back(MR); + + } else if (Call.isCXXCall()) { + // Invalidate all instance variables for the callee of a C++ method call. + // FIXME: We should be able to do better with inter-procedural analysis. + // FIXME: We can probably do better for const versus non-const methods. + if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion()) + RegionsToInvalidate.push_back(Callee); + + } else if (Call.isFunctionCall()) { + // Block calls invalidate all captured-by-reference values. + if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) { + if (isa(Callee)) + RegionsToInvalidate.push_back(Callee); + } + } + + for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) { + SVal V = Call.getArgSVal(idx); + + // If we are passing a location wrapped as an integer, unwrap it and + // invalidate the values referred by the location. + if (nonloc::LocAsInteger *Wrapped = dyn_cast(&V)) + V = Wrapped->getLoc(); + else if (!isa(V)) + continue; + + if (const MemRegion *R = V.getAsRegion()) { + // Invalidate the value of the variable passed by reference. + + // Are we dealing with an ElementRegion? If the element type is + // a basic integer type (e.g., char, int) and the underying region + // is a variable region then strip off the ElementRegion. + // FIXME: We really need to think about this for the general case + // as sometimes we are reasoning about arrays and other times + // about (char*), etc., is just a form of passing raw bytes. + // e.g., void *p = alloca(); foo((char*)p); + if (const ElementRegion *ER = dyn_cast(R)) { + // Checking for 'integral type' is probably too promiscuous, but + // we'll leave it in for now until we have a systematic way of + // handling all of these cases. Eventually we need to come up + // with an interface to StoreManager so that this logic can be + // approriately delegated to the respective StoreManagers while + // still allowing us to do checker-specific logic (e.g., + // invalidating reference counts), probably via callbacks. + if (ER->getElementType()->isIntegralOrEnumerationType()) { + const MemRegion *superReg = ER->getSuperRegion(); + if (isa(superReg) || isa(superReg) || + isa(superReg)) + R = cast(superReg); + } + // FIXME: What about layers of ElementRegions? + } + + // Mark this region for invalidation. We batch invalidate regions + // below for efficiency. + RegionsToInvalidate.push_back(R); + } else { + // Nuke all other arguments passed by reference. + // FIXME: is this necessary or correct? This handles the non-Region + // cases. Is it ever valid to store to these? + State = State->unbindLoc(cast(V)); + } + } + + // Invalidate designated regions using the batch invalidation API. + + // FIXME: We can have collisions on the conjured symbol if the + // expression *I also creates conjured symbols. We probably want + // to identify conjured symbols by an expression pair: the enclosing + // expression (the context) and the expression itself. This should + // disambiguate conjured symbols. + assert(Builder && "Invalidating arguments outside of a statement context"); + unsigned Count = Builder->getCurrentBlockCount(); + StoreManager::InvalidatedSymbols IS; + + // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate + // global variables. + return State->invalidateRegions(RegionsToInvalidate, + Call.getOriginExpr(), Count, + &IS, doesInvalidateGlobals(Call)); + +} + void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &dst) { // Perform the previsit of the CallExpr. @@ -108,16 +203,19 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, unsigned Count = Builder.getCurrentBlockCount(); SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count); - // Generate a new ExplodedNode with the return value set. + // Generate a new state with the return value set. state = state->BindExpr(CE, RetVal); - Pred = Builder.generateNode(CE, state, Pred); + + // Invalidate the arguments. + const LocationContext *LC = Pred->getLocationContext(); + state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC); // Then handle everything else. unsigned oldSize = Dst.size(); SaveOr OldHasGen(Builder.hasGeneratedNode); // Dispatch to transfer function logic to handle the rest of the call. - Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); + //Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index 6cfe8cdc93..a80b2bfb7e 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -273,7 +273,12 @@ void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, // Bind the return value. state = state->BindExpr(currentStmt, ReturnValue); + // Invalidate the arguments (and the receiver) + const LocationContext *LC = Pred->getLocationContext(); + state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC); + Builder->MakeNode(Dst, msg.getOriginExpr(), Pred, state); + // Now we can handle the other aspects of the message. - getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state); + //getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state); } diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp index 82b0e7c305..112c468210 100644 --- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -150,3 +150,9 @@ SVal CallOrObjCMessage::getCXXCallee() const { cast(ActualCall)->getImplicitObjectArgument(); return State->getSVal(callee); } + +SVal +CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const { + assert(isObjCMessage()); + return Msg.getInstanceReceiverSVal(State, LC); +}