From 537716ad8dd10f984b6cfe6985afade1185c5e3c Mon Sep 17 00:00:00 2001 From: Jordy Rose Date: Sat, 27 Aug 2011 22:51:26 +0000 Subject: [PATCH] [analyzer] Change the check::RegionChanges callback to include the regions explicitly requested for invalidation. Also, allow CallOrObjCMessage to wrap a CXXConstructExpr as well. Finally, this allows us to remove the clunky whitelisting system from CFRefCount/RetainReleaseChecker. Slight regression due to CXXNewExprs not yet being handled in post-statement callbacks (PR forthcoming). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138716 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/StaticAnalyzer/Core/Checker.h | 6 +- .../StaticAnalyzer/Core/CheckerManager.h | 16 +++- .../Core/PathSensitive/ExprEngine.h | 4 +- .../Core/PathSensitive/ObjCMessage.h | 63 ++++++++++----- .../Core/PathSensitive/ProgramState.h | 26 ++----- .../StaticAnalyzer/Core/PathSensitive/Store.h | 5 +- .../Core/PathSensitive/SubEngine.h | 6 +- .../Checkers/CStringChecker.cpp | 15 ++-- lib/StaticAnalyzer/Core/CFRefCount.cpp | 77 +++++++++---------- lib/StaticAnalyzer/Core/CheckerManager.cpp | 7 +- lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 +- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 12 +-- lib/StaticAnalyzer/Core/ObjCMessage.cpp | 38 ++++----- lib/StaticAnalyzer/Core/ProgramState.cpp | 37 ++++----- lib/StaticAnalyzer/Core/RegionStore.cpp | 22 +++--- 15 files changed, 171 insertions(+), 169 deletions(-) diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index c93924dd28..11b665a445 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -262,10 +262,10 @@ class RegionChanges { _checkRegionChanges(void *checker, const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End) { + ArrayRef Explicits, + ArrayRef Regions) { return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated, - Begin, End); + Explicits, Regions); } template static bool _wantsRegionChangeUpdate(void *checker, diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index ffbecedd13..fdc6055bb4 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -238,11 +238,19 @@ public: bool wantsRegionChangeUpdate(const ProgramState *state); /// \brief Run checkers for region changes. + /// + /// This corresponds to the check::RegionChanges callback. + /// \param state The current program state. + /// \param invalidated A set of all symbols potentially touched by the change. + /// \param ExplicitRegions The regions explicitly requested for invalidation. + /// For example, in the case of a function call, these would be arguments. + /// \param Regions The transitive closure of accessible regions, + /// i.e. all regions that may have been touched by this change. const ProgramState * runCheckersForRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End); + ArrayRef ExplicitRegions, + ArrayRef Regions); /// \brief Run checkers for handling assumptions on symbolic values. const ProgramState *runCheckersForEvalAssume(const ProgramState *state, @@ -305,8 +313,8 @@ public: typedef CheckerFn + ArrayRef ExplicitRegions, + ArrayRef Regions)> CheckRegionChangesFunc; typedef CheckerFn WantsRegionChangeUpdateFunc; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 1bdd57291f..bdbcf5b720 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -192,8 +192,8 @@ public: const ProgramState * processRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End); + ArrayRef ExplicitRegions, + ArrayRef Regions); virtual ProgramStateManager& getStateManager() { return StateMgr; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index 247534d7bf..6a8a73e5b7 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -18,6 +18,8 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/ADT/PointerUnion.h" namespace clang { namespace ento { @@ -165,62 +167,81 @@ public: } }; -/// \brief Common wrapper for a call expression or an ObjC message, mainly to -/// provide a common interface for handling their arguments. +/// \brief Common wrapper for a call expression, ObjC message, or C++ +/// constructor, mainly to provide a common interface for their arguments. class CallOrObjCMessage { - const CallExpr *CallE; + llvm::PointerUnion CallE; ObjCMessage Msg; const ProgramState *State; public: CallOrObjCMessage(const CallExpr *callE, const ProgramState *state) : CallE(callE), State(state) {} + CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state) + : CallE(consE), State(state) {} CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state) - : CallE(0), Msg(msg), State(state) {} + : CallE((CallExpr *)0), Msg(msg), State(state) {} QualType getResultType(ASTContext &ctx) const; bool isFunctionCall() const { - return (bool) CallE; + return CallE && CallE.is(); } - + + bool isCXXConstructExpr() const { + return CallE && CallE.is(); + } + + bool isObjCMessage() const { + return !CallE; + } + bool isCXXCall() const { - return CallE && isa(CallE); + const CallExpr *ActualCallE = CallE.dyn_cast(); + return ActualCallE && isa(ActualCallE); } const Expr *getOriginExpr() const { - if (isFunctionCall()) - return CallE; - return Msg.getOriginExpr(); + if (!CallE) + return Msg.getOriginExpr(); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast()) + return Ctor; + return CallE.get(); } SVal getFunctionCallee() const; SVal getCXXCallee() const; unsigned getNumArgs() const { - if (CallE) return CallE->getNumArgs(); - return Msg.getNumArgs(); + if (!CallE) + return Msg.getNumArgs(); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast()) + return Ctor->getNumArgs(); + return CallE.get()->getNumArgs(); } SVal getArgSVal(unsigned i) const { assert(i < getNumArgs()); - if (CallE) - return State->getSVal(CallE->getArg(i)); - return Msg.getArgSVal(i, State); + if (!CallE) + return Msg.getArgSVal(i, State); + return State->getSVal(getArg(i)); } - SVal getArgSValAsScalarOrLoc(unsigned i) const; - const Expr *getArg(unsigned i) const { assert(i < getNumArgs()); - if (CallE) - return CallE->getArg(i); - return Msg.getArgExpr(i); + if (!CallE) + return Msg.getArgExpr(i); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast()) + return Ctor->getArg(i); + return CallE.get()->getArg(i); } SourceRange getArgSourceRange(unsigned i) const { assert(i < getNumArgs()); if (CallE) - return CallE->getArg(i)->getSourceRange(); + return getArg(i)->getSourceRange(); return Msg.getArgSourceRange(i); } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 40aedf35e9..7ec3965fa6 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -216,23 +216,13 @@ public: const ProgramState *unbindLoc(Loc LV) const; - /// invalidateRegion - Returns the state with bindings for the given region - /// cleared from the store. See invalidateRegions. - const ProgramState *invalidateRegion(const MemRegion *R, - const Expr *E, unsigned BlockCount, - StoreManager::InvalidatedSymbols *IS = NULL) - const { - return invalidateRegions(&R, &R+1, E, BlockCount, IS, false); - } - /// invalidateRegions - Returns the state with bindings for the given regions /// cleared from the store. The regions are provided as a continuous array /// from Begin to End. Optionally invalidates global regions as well. - const ProgramState *invalidateRegions(const MemRegion * const *Begin, - const MemRegion * const *End, + const ProgramState *invalidateRegions(ArrayRef Regions, const Expr *E, unsigned BlockCount, - StoreManager::InvalidatedSymbols *IS, - bool invalidateGlobals) const; + StoreManager::InvalidatedSymbols *IS = 0, + bool invalidateGlobals = false) const; /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. @@ -368,11 +358,11 @@ private: --refCount; } - const ProgramState *invalidateRegionsImpl(const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned BlockCount, - StoreManager::InvalidatedSymbols &IS, - bool invalidateGlobals) const; + const ProgramState * + invalidateRegionsImpl(ArrayRef Regions, + const Expr *E, unsigned BlockCount, + StoreManager::InvalidatedSymbols &IS, + bool invalidateGlobals) const; }; class ProgramStateSet { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 71c865c4e2..a688d7f219 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -187,12 +187,11 @@ public: /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. virtual StoreRef invalidateRegions(Store store, - const MemRegion * const *Begin, - const MemRegion * const *End, + ArrayRef Regions, const Expr *E, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, - InvalidatedRegions *Regions) = 0; + InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index ef0cdc43ee..f5a3d4c1be 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -99,14 +99,14 @@ public: virtual const ProgramState * processRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion* const *Begin, - const MemRegion* const *End) = 0; + ArrayRef ExplicitRegions, + ArrayRef Regions) = 0; inline const ProgramState * processRegionChange(const ProgramState *state, const MemRegion* MR) { - return processRegionChanges(state, 0, &MR, &MR+1); + return processRegionChanges(state, 0, MR, MR); } /// Called by CoreEngine when the analysis worklist is either empty or the diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index d043e2d8ae..718d9f3bd9 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -47,8 +47,8 @@ public: const ProgramState * checkRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *, - const MemRegion * const *Begin, - const MemRegion * const *End) const; + ArrayRef ExplicitRegions, + ArrayRef Regions) const; typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *) const; @@ -786,7 +786,7 @@ const ProgramState *CStringChecker::InvalidateBuffer(CheckerContext &C, // Invalidate this region. unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); - return state->invalidateRegion(R, E, Count, NULL); + return state->invalidateRegions(R, E, Count); } // If we have a non-region value by chance, just remove the binding. @@ -1757,8 +1757,8 @@ bool CStringChecker::wantsRegionChangeUpdate(const ProgramState *state) const { const ProgramState * CStringChecker::checkRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *, - const MemRegion * const *Begin, - const MemRegion * const *End) const { + ArrayRef ExplicitRegions, + ArrayRef Regions) const { CStringLength::EntryMap Entries = state->get(); if (Entries.isEmpty()) return state; @@ -1767,8 +1767,9 @@ CStringChecker::checkRegionChanges(const ProgramState *state, llvm::SmallPtrSet SuperRegions; // First build sets for the changed regions and their super-regions. - for ( ; Begin != End; ++Begin) { - const MemRegion *MR = *Begin; + for (ArrayRef::iterator + I = Regions.begin(), E = Regions.end(); I != E; ++I) { + const MemRegion *MR = *I; Invalidated.insert(MR); SuperRegions.insert(MR); diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp index 07487f14e1..5991e5325f 100644 --- a/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -2439,23 +2439,6 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { return RetTy; } - -// HACK: Symbols that have ref-count state that are referenced directly -// (not as structure or array elements, or via bindings) by an argument -// should not have their ref-count state stripped after we have -// done an invalidation pass. -// -// FIXME: This is a global to currently share between CFRefCount and -// RetainReleaseChecker. Eventually all functionality in CFRefCount should -// be migrated to RetainReleaseChecker, and we can make this a non-global. -llvm::DenseSet WhitelistedSymbols; -namespace { -struct ResetWhiteList { - ResetWhiteList() {} - ~ResetWhiteList() { WhitelistedSymbols.clear(); } -}; -} - void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, StmtNodeBuilder &Builder, const CallOrObjCMessage &callOrMsg, @@ -2465,18 +2448,11 @@ void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, const ProgramState *state) { SmallVector RegionsToInvalidate; - - // Use RAII to make sure the whitelist is properly cleared. - ResetWhiteList resetWhiteList; // 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 (SymbolRef Sym = V.getAsLocSymbol()) { - if (state->get(Sym)) - WhitelistedSymbols.insert(Sym); - } if (const MemRegion *region = V.getAsRegion()) RegionsToInvalidate.push_back(region); } @@ -2490,7 +2466,7 @@ void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, } for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) { - SVal V = callOrMsg.getArgSValAsScalarOrLoc(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. @@ -2499,10 +2475,6 @@ void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, else if (!isa(V)) continue; - if (SymbolRef Sym = V.getAsLocSymbol()) - if (state->get(Sym)) - WhitelistedSymbols.insert(Sym); - if (const MemRegion *R = V.getAsRegion()) { // Invalidate the value of the variable passed by reference. @@ -2562,9 +2534,7 @@ void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng, // global variables. // NOTE: RetainReleaseChecker handles the actual invalidation of symbols. state = - state->invalidateRegions(RegionsToInvalidate.data(), - RegionsToInvalidate.data() + - RegionsToInvalidate.size(), + state->invalidateRegions(RegionsToInvalidate, Ex, Count, &IS, /* invalidateGlobals = */ Eng.doesInvalidateGlobals(callOrMsg)); @@ -2611,6 +2581,7 @@ class RetainReleaseChecker check::PostStmt, check::PostStmt, check::PostStmt, + check::PostStmt, check::PostObjCMessage, check::PreStmt, check::RegionChanges, @@ -2770,6 +2741,7 @@ public: void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; + 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; @@ -2779,10 +2751,11 @@ public: const ProgramState *evalAssume(const ProgramState *state, SVal Cond, bool Assumption) const; - const ProgramState *checkRegionChanges(const ProgramState *state, - const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *begin, - const MemRegion * const *end) const; + const ProgramState * + checkRegionChanges(const ProgramState *state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef ExplicitRegions, + ArrayRef Regions) const; bool wantsRegionChangeUpdate(const ProgramState *state) const { return true; @@ -2912,11 +2885,18 @@ const ProgramState *RetainReleaseChecker::evalAssume(const ProgramState *state, const ProgramState * RetainReleaseChecker::checkRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *begin, - const MemRegion * const *end) const { + ArrayRef ExplicitRegions, + ArrayRef Regions) const { if (!invalidated) return state; + llvm::SmallPtrSet WhitelistedSymbols; + for (ArrayRef::iterator I = ExplicitRegions.begin(), + E = ExplicitRegions.end(); I != E; ++I) { + if (const SymbolicRegion *SR = (*I)->StripCasts()->getAs()) + WhitelistedSymbols.insert(SR->getSymbol()); + } + for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), E = invalidated->end(); I!=E; ++I) { SymbolRef sym = *I; @@ -3036,6 +3016,23 @@ void RetainReleaseChecker::checkPostStmt(const CallExpr *CE, checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C); } +void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE, + CheckerContext &C) const { + const CXXConstructorDecl *Ctor = CE->getConstructor(); + if (!Ctor) + return; + + RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext()); + RetainSummary *Summ = Summaries.getSummary(Ctor); + + // If we didn't get a summary, this constructor doesn't affect retain counts. + if (!Summ) + return; + + const ProgramState *state = C.getState(); + checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C); +} + void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const { const ProgramState *state = C.getState(); @@ -3071,7 +3068,7 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ, SymbolRef ErrorSym = 0; for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { - SVal V = CallOrMsg.getArgSValAsScalarOrLoc(idx); + SVal V = CallOrMsg.getArgSVal(idx); if (SymbolRef Sym = V.getAsLocSymbol()) { if (RefBindings::data_type *T = state->get(Sym)) { @@ -3434,7 +3431,7 @@ bool RetainReleaseChecker::evalCall(const CallExpr *CE, // Invalidate the argument region. unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); - state = state->invalidateRegion(ArgRegion, CE, Count); + state = state->invalidateRegions(ArgRegion, CE, Count); // Restore the refcount status of the argument. if (Binding) diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index bcba98fb3a..196376c340 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -346,14 +346,15 @@ bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) { const ProgramState * CheckerManager::runCheckersForRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End) { + ArrayRef ExplicitRegions, + ArrayRef 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; } diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 6c318f756c..997e0789f0 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -192,10 +192,10 @@ bool ExprEngine::wantsRegionChangeUpdate(const ProgramState *state) { const ProgramState * ExprEngine::processRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End) { + ArrayRef Explicits, + ArrayRef Regions) { return getCheckerManager().runCheckersForRegionChanges(state, invalidated, - Begin, End); + Explicits, Regions); } void ExprEngine::processEndWorklist(bool hasWorkRemaining) { diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index d34afbad72..579dcb3f51 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -229,9 +229,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, } // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate.data(), - regionsToInvalidate.data() + - regionsToInvalidate.size(), + state = state->invalidateRegions(regionsToInvalidate, E, blockCount, 0, /* invalidateGlobals = */ true); @@ -317,17 +315,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (ObjTy->isRecordType()) { regionsToInvalidate.push_back(EleReg); // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate.data(), - regionsToInvalidate.data() + - regionsToInvalidate.size(), + state = state->invalidateRegions(regionsToInvalidate, CNE, blockCount, 0, /* invalidateGlobals = */ true); } else { // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate.data(), - regionsToInvalidate.data() + - regionsToInvalidate.size(), + state = state->invalidateRegions(regionsToInvalidate, CNE, blockCount, 0, /* invalidateGlobals = */ true); diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp index 40ed83beb8..82b0e7c305 100644 --- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -112,18 +112,22 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { QualType resultTy; bool isLVal = false; - if (CallE) { - isLVal = CallE->isLValue(); - const Expr *Callee = CallE->getCallee(); - if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) - resultTy = FD->getResultType(); - else - resultTy = CallE->getType(); - } - else { + if (isObjCMessage()) { isLVal = isa(Msg.getOriginExpr()) && Msg.getOriginExpr()->isLValue(); resultTy = Msg.getResultType(ctx); + } else if (const CXXConstructExpr *Ctor = + CallE.dyn_cast()) { + resultTy = Ctor->getType(); + } else { + const CallExpr *FunctionCall = CallE.get(); + + isLVal = FunctionCall->isLValue(); + const Expr *Callee = FunctionCall->getCallee(); + if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) + resultTy = FD->getResultType(); + else + resultTy = FunctionCall->getType(); } if (isLVal) @@ -132,25 +136,17 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { return resultTy; } -SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { - assert(i < getNumArgs()); - if (CallE) return State->getSValAsScalarOrLoc(CallE->getArg(i)); - QualType argT = Msg.getArgType(i); - if (Loc::isLocType(argT) || argT->isIntegerType()) - return Msg.getArgSVal(i, State); - return UnknownVal(); -} - SVal CallOrObjCMessage::getFunctionCallee() const { assert(isFunctionCall()); assert(!isCXXCall()); - const Expr *callee = CallE->getCallee()->IgnoreParens(); - return State->getSVal(callee); + const Expr *Fun = CallE.get()->getCallee()->IgnoreParens(); + return State->getSVal(Fun); } SVal CallOrObjCMessage::getCXXCallee() const { assert(isCXXCall()); + const CallExpr *ActualCall = CallE.get(); const Expr *callee = - cast(CallE)->getImplicitObjectArgument(); + cast(ActualCall)->getImplicitObjectArgument(); return State->getSVal(callee); } diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 046de0d0ff..54a626b676 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -136,41 +136,38 @@ const ProgramState *ProgramState::bindDefault(SVal loc, SVal V) const { new_state; } -const ProgramState *ProgramState::invalidateRegions(const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - StoreManager::InvalidatedSymbols *IS, - bool invalidateGlobals) const { +const ProgramState * +ProgramState::invalidateRegions(ArrayRef Regions, + const Expr *E, unsigned Count, + StoreManager::InvalidatedSymbols *IS, + bool invalidateGlobals) const { if (!IS) { StoreManager::InvalidatedSymbols invalidated; - return invalidateRegionsImpl(Begin, End, E, Count, - invalidated, invalidateGlobals); + return invalidateRegionsImpl(Regions, E, Count, + invalidated, invalidateGlobals); } - return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals); + return invalidateRegionsImpl(Regions, E, Count, *IS, invalidateGlobals); } const ProgramState * -ProgramState::invalidateRegionsImpl(const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - StoreManager::InvalidatedSymbols &IS, - bool invalidateGlobals) const { +ProgramState::invalidateRegionsImpl(ArrayRef Regions, + const Expr *E, unsigned Count, + StoreManager::InvalidatedSymbols &IS, + bool invalidateGlobals) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); if (Eng && Eng->wantsRegionChangeUpdate(this)) { - StoreManager::InvalidatedRegions Regions; + StoreManager::InvalidatedRegions Invalidated; const StoreRef &newStore - = Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS, - invalidateGlobals, &Regions); + = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS, + invalidateGlobals, &Invalidated); const ProgramState *newState = makeWithStore(newStore); - return Eng->processRegionChanges(newState, &IS, - &Regions.front(), - &Regions.back()+1); + return Eng->processRegionChanges(newState, &IS, Regions, Invalidated); } const StoreRef &newStore = - Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS, + Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS, invalidateGlobals, NULL); return makeWithStore(newStore); } diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 30028c78a3..04c274d319 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -236,13 +236,11 @@ public: // Binding values to regions. //===-------------------------------------------------------------------===// - StoreRef invalidateRegions(Store store, - const MemRegion * const *Begin, - const MemRegion * const *End, + StoreRef invalidateRegions(Store store, ArrayRef Regions, const Expr *E, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, - InvalidatedRegions *Regions); + InvalidatedRegions *Invalidated); public: // Made public for helper classes. @@ -721,21 +719,21 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { } StoreRef RegionStoreManager::invalidateRegions(Store store, - const MemRegion * const *I, - const MemRegion * const *E, + ArrayRef Regions, const Expr *Ex, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, - InvalidatedRegions *Regions) { + InvalidatedRegions *Invalidated) { invalidateRegionsWorker W(*this, StateMgr, RegionStoreManager::GetRegionBindings(store), - Ex, Count, IS, Regions, invalidateGlobals); + Ex, Count, IS, Invalidated, invalidateGlobals); // Scan the bindings and generate the clusters. W.GenerateClusters(); - // Add I .. E to the worklist. - for ( ; I != E; ++I) + // Add the regions to the worklist. + for (ArrayRef::iterator + I = Regions.begin(), E = Regions.end(); I != E; ++I) W.AddToWorkList(*I); W.RunWorkList(); @@ -755,8 +753,8 @@ StoreRef RegionStoreManager::invalidateRegions(Store store, // Even if there are no bindings in the global scope, we still need to // record that we touched it. - if (Regions) - Regions->push_back(GS); + if (Invalidated) + Invalidated->push_back(GS); } return StoreRef(B.getRootWithoutRetain(), *this); -- 2.40.0