diff options
8 files changed, 201 insertions, 76 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 689d26a9abf..f990b8dcd0e 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -162,11 +162,11 @@ protected: } - typedef SmallVectorImpl<const MemRegion *> RegionList; + typedef SmallVectorImpl<SVal> ValueList; /// \brief Used to specify non-argument regions that will be invalidated as a /// result of this call. - virtual void getExtraInvalidatedRegions(RegionList &Regions) const {} + virtual void getExtraInvalidatedValues(ValueList &Values) const {} public: virtual ~CallEvent() {} @@ -504,7 +504,7 @@ protected: BlockCall(const BlockCall &Other) : SimpleCall(Other) {} virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; public: /// \brief Returns the region associated with this instance of the block. @@ -548,7 +548,7 @@ public: /// it is written. class CXXInstanceCall : public AnyFunctionCall { protected: - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; CXXInstanceCall(const CallExpr *CE, ProgramStateRef St, const LocationContext *LCtx) @@ -731,7 +731,7 @@ protected: CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){} virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; public: virtual const CXXConstructExpr *getOriginExpr() const { @@ -830,7 +830,7 @@ protected: ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {} virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); } - virtual void getExtraInvalidatedRegions(RegionList &Regions) const; + virtual void getExtraInvalidatedValues(ValueList &Values) const; /// Check if the selector may have multiple definitions (may have overrides). virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index fe5325b5d72..6ea7211090b 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -250,6 +250,13 @@ public: ArrayRef<const MemRegion *> ConstRegions = ArrayRef<const MemRegion *>()) const; + ProgramStateRef + invalidateRegions(ArrayRef<SVal> Regions, const Expr *E, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = 0, + const CallEvent *Call = 0, + ArrayRef<SVal> ConstRegions = ArrayRef<SVal>()) const; + /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. ProgramStateRef enterStackFrame(const CallEvent &Call, @@ -419,15 +426,16 @@ private: friend void ProgramStateRetain(const ProgramState *state); friend void ProgramStateRelease(const ProgramState *state); + /// \sa invalidateValues() /// \sa invalidateRegions() ProgramStateRef - invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, + invalidateRegionsImpl(ArrayRef<SVal> Values, const Expr *E, unsigned BlockCount, const LocationContext *LCtx, bool ResultsInSymbolEscape, InvalidatedSymbols &IS, const CallEvent *Call, - ArrayRef<const MemRegion *> ConstRegions) const; + ArrayRef<SVal> ConstValues) const; }; //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 8182f2e5653..1c5519e9e78 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -544,7 +544,8 @@ private: }; } // end ento::loc namespace -} // end GR namespace + +} // end ento namespace } // end clang namespace diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 9ae24c446e9..bbfd5797fff 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -178,30 +178,40 @@ public: /// invalidate additional regions that may have changed based on accessing /// the given regions. Optionally, invalidates non-static globals as well. /// \param[in] store The initial store - /// \param[in] Regions The regions to invalidate. + /// \param[in] Values The values to invalidate. + /// \param[in] ConstValues The values to invalidate; these are known to be + /// const, so only regions accesible from them should be invalidated. /// \param[in] E The current statement being evaluated. Used to conjure /// symbols to mark the values of invalidated regions. /// \param[in] Count The current block count. Used to conjure /// symbols to mark the values of invalidated regions. - /// \param[in,out] IS A set to fill with any symbols that are no longer - /// accessible. Pass \c NULL if this information will not be used. /// \param[in] Call The call expression which will be used to determine which /// globals should get invalidated. + /// \param[in,out] IS A set to fill with any symbols that are no longer + /// accessible. Pass \c NULL if this information will not be used. /// \param[in,out] ConstIS A set to fill with any symbols corresponding to - /// the ConstRegions. + /// the ConstValues. + /// \param[in,out] InvalidatedTopLevel A vector to fill with regions + //// explicitely being invalidated. Pass \c NULL if this + /// information will not be used. + /// \param[in,out] InvalidatedTopLevelConst A vector to fill with const + //// regions explicitely being invalidated. Pass \c NULL if this + /// information will not be used. /// \param[in,out] Invalidated A vector to fill with any regions being /// invalidated. This should include any regions explicitly invalidated /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. virtual StoreRef invalidateRegions(Store store, - ArrayRef<const MemRegion *> Regions, - const Expr *E, unsigned Count, - const LocationContext *LCtx, - InvalidatedSymbols &IS, - const CallEvent *Call, - ArrayRef<const MemRegion *> ConstRegions, - InvalidatedSymbols &ConstIS, - InvalidatedRegions *Invalidated) = 0; + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + const CallEvent *Call, + InvalidatedSymbols &IS, + InvalidatedSymbols &ConstIS, + InvalidatedRegions *InvalidatedTopLevel, + InvalidatedRegions *InvalidatedTopLevelConst, + InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 78400ba3595..45b2e219d9e 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -140,9 +140,10 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, ProgramStateRef Orig) const { ProgramStateRef Result = (Orig ? Orig : getState()); - SmallVector<const MemRegion *, 8> ConstRegions; - SmallVector<const MemRegion *, 8> RegionsToInvalidate; - getExtraInvalidatedRegions(RegionsToInvalidate); + SmallVector<SVal, 8> ConstValues; + SmallVector<SVal, 8> ValuesToInvalidate; + + getExtraInvalidatedValues(ValuesToInvalidate); // Indexes of arguments whose values will be preserved by the call. llvm::SmallSet<unsigned, 4> PreserveArgs; @@ -150,25 +151,21 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, findPtrToConstParams(PreserveArgs, *this); for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) { - const MemRegion *R = getArgSVal(Idx).getAsRegion(); - if (!R) - continue; - // Mark this region for invalidation. We batch invalidate regions // below for efficiency. if (PreserveArgs.count(Idx)) - ConstRegions.push_back(R); + ConstValues.push_back(getArgSVal(Idx)); else - RegionsToInvalidate.push_back(R); + ValuesToInvalidate.push_back(getArgSVal(Idx)); } // Invalidate designated regions using the batch invalidation API. // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. - return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(), + return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, - /*Symbols=*/0, this, ConstRegions); + /*Symbols=*/0, this, ConstValues); } ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, @@ -374,9 +371,8 @@ const FunctionDecl *CXXInstanceCall::getDecl() const { return getSVal(CE->getCallee()).getAsFunctionDecl(); } -void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const { - if (const MemRegion *R = getCXXThisVal().getAsRegion()) - Regions.push_back(R); +void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values) const { + Values.push_back(getCXXThisVal()); } SVal CXXInstanceCall::getCXXThisVal() const { @@ -529,10 +525,10 @@ CallEvent::param_iterator BlockCall::param_end() const { return D->param_end(); } -void BlockCall::getExtraInvalidatedRegions(RegionList &Regions) const { +void BlockCall::getExtraInvalidatedValues(ValueList &Values) const { // FIXME: This also needs to invalidate captured globals. if (const MemRegion *R = getBlockRegion()) - Regions.push_back(R); + Values.push_back(loc::MemRegionVal(R)); } void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx, @@ -550,9 +546,9 @@ SVal CXXConstructorCall::getCXXThisVal() const { return UnknownVal(); } -void CXXConstructorCall::getExtraInvalidatedRegions(RegionList &Regions) const { +void CXXConstructorCall::getExtraInvalidatedValues(ValueList &Values) const { if (Data) - Regions.push_back(static_cast<const MemRegion *>(Data)); + Values.push_back(loc::MemRegionVal(static_cast<const MemRegion *>(Data))); } void CXXConstructorCall::getInitialStackFrameContents( @@ -604,9 +600,8 @@ CallEvent::param_iterator ObjCMethodCall::param_end() const { } void -ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const { - if (const MemRegion *R = getReceiverSVal().getAsRegion()) - Regions.push_back(R); +ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values) const { + Values.push_back(getReceiverSVal()); } SVal ObjCMethodCall::getSelfSVal() const { diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 9aac8df0a22..ebce0c1f4d1 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -141,6 +141,7 @@ ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const { } typedef ArrayRef<const MemRegion *> RegionList; +typedef ArrayRef<SVal> ValueList; ProgramStateRef ProgramState::invalidateRegions(RegionList Regions, @@ -150,54 +151,92 @@ ProgramState::invalidateRegions(RegionList Regions, InvalidatedSymbols *IS, const CallEvent *Call, RegionList ConstRegions) const { + SmallVector<SVal, 8> Values; + for (RegionList::const_iterator I = Regions.begin(), + E = Regions.end(); I != E; ++I) + Values.push_back(loc::MemRegionVal(*I)); + + SmallVector<SVal, 8> ConstValues; + for (RegionList::const_iterator I = ConstRegions.begin(), + E = ConstRegions.end(); I != E; ++I) + ConstValues.push_back(loc::MemRegionVal(*I)); + if (!IS) { InvalidatedSymbols invalidated; - return invalidateRegionsImpl(Regions, E, Count, LCtx, + return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, - invalidated, Call, ConstRegions); + invalidated, Call, ConstValues); } - return invalidateRegionsImpl(Regions, E, Count, LCtx, CausedByPointerEscape, - *IS, Call, ConstRegions); + return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, + *IS, Call, ConstValues); } -ProgramStateRef -ProgramState::invalidateRegionsImpl(RegionList Regions, +ProgramStateRef +ProgramState::invalidateRegions(ValueList Values, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + bool CausedByPointerEscape, + InvalidatedSymbols *IS, + const CallEvent *Call, + ValueList ConstValues) const { + if (!IS) { + InvalidatedSymbols invalidated; + return invalidateRegionsImpl(Values, E, Count, LCtx, + CausedByPointerEscape, + invalidated, Call, ConstValues); + } + return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape, + *IS, Call, ConstValues); +} + +ProgramStateRef +ProgramState::invalidateRegionsImpl(ValueList Values, const Expr *E, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols &IS, const CallEvent *Call, - RegionList ConstRegions) const { + ValueList ConstValues) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); InvalidatedSymbols ConstIS; if (Eng) { + StoreManager::InvalidatedRegions TopLevelInvalidated; + StoreManager::InvalidatedRegions TopLevelConstInvalidated; StoreManager::InvalidatedRegions Invalidated; const StoreRef &newStore - = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS, - Call, ConstRegions, ConstIS, - &Invalidated); + = Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues, + E, Count, LCtx, Call, + IS, ConstIS, + &TopLevelInvalidated, + &TopLevelConstInvalidated, + &Invalidated); ProgramStateRef newState = makeWithStore(newStore); if (CausedByPointerEscape) { - newState = Eng->notifyCheckersOfPointerEscape(newState, - &IS, Regions, Invalidated, Call); - if (!ConstRegions.empty()) { + newState = Eng->notifyCheckersOfPointerEscape(newState, &IS, + TopLevelInvalidated, + Invalidated, Call); + if (!ConstValues.empty()) { StoreManager::InvalidatedRegions Empty; newState = Eng->notifyCheckersOfPointerEscape(newState, &ConstIS, - ConstRegions, Empty, Call, + TopLevelConstInvalidated, + Empty, Call, true); } } - return Eng->processRegionChanges(newState, &IS, Regions, Invalidated, Call); + return Eng->processRegionChanges(newState, &IS, + TopLevelInvalidated, Invalidated, + Call); } const StoreRef &newStore = - Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS, - Call, ConstRegions, ConstIS, NULL); + Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues, + E, Count, LCtx, Call, + IS, ConstIS, NULL, NULL, NULL); return makeWithStore(newStore); } diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 08110dd3b93..514fe256cd6 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -318,6 +318,7 @@ public: //===----------------------------------------------------------------------===// namespace { +class invalidateRegionsWorker; class RegionStoreManager : public StoreManager { public: @@ -331,6 +332,13 @@ private: SValListTy> LazyBindingsMapTy; LazyBindingsMapTy LazyBindingsMap; + /// \brief A helper used to populate the work list with the given set of + /// regions. + void populateWorkList(invalidateRegionsWorker &W, + ArrayRef<SVal> Values, + bool IsArrayOfConstRegions, + InvalidatedRegions *TopLevelRegions); + public: RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f) : StoreManager(mgr), Features(f), @@ -365,14 +373,17 @@ public: RegionBindingsRef B, InvalidatedRegions *Invalidated); - StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions, + StoreRef invalidateRegions(Store store, + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, const Expr *E, unsigned Count, const LocationContext *LCtx, - InvalidatedSymbols &IS, const CallEvent *Call, - ArrayRef<const MemRegion *> ConstRegions, + InvalidatedSymbols &IS, InvalidatedSymbols &ConstIS, - InvalidatedRegions *Invalidated); + InvalidatedRegions *Invalidated, + InvalidatedRegions *InvalidatedTopLevel, + InvalidatedRegions *InvalidatedTopLevelConst); bool scanReachableSymbols(Store S, const MemRegion *R, ScanReachableSymbols &Callbacks); @@ -1062,15 +1073,48 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K, return B; } +void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W, + ArrayRef<SVal> Values, + bool IsArrayOfConstRegions, + InvalidatedRegions *TopLevelRegions) { + for (ArrayRef<SVal>::iterator I = Values.begin(), + E = Values.end(); I != E; ++I) { + SVal V = *I; + if (Optional<nonloc::LazyCompoundVal> LCS = + V.getAs<nonloc::LazyCompoundVal>()) { + + const SValListTy &Vals = getInterestingValues(*LCS); + + for (SValListTy::const_iterator I = Vals.begin(), + E = Vals.end(); I != E; ++I) { + // Note: the last argumet is false here because these are + // non-top-level regions. + if (const MemRegion *R = (*I).getAsRegion()) + W.AddToWorkList(R, /*IsConst=*/ false); + } + continue; + } + + if (const MemRegion *R = V.getAsRegion()) { + if (TopLevelRegions) + TopLevelRegions->push_back(R); + W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions); + continue; + } + } +} + StoreRef RegionStoreManager::invalidateRegions(Store store, - ArrayRef<const MemRegion *> Regions, + ArrayRef<SVal> Values, + ArrayRef<SVal> ConstValues, const Expr *Ex, unsigned Count, const LocationContext *LCtx, - InvalidatedSymbols &IS, const CallEvent *Call, - ArrayRef<const MemRegion *> ConstRegions, + InvalidatedSymbols &IS, InvalidatedSymbols &ConstIS, + InvalidatedRegions *TopLevelRegions, + InvalidatedRegions *TopLevelConstRegions, InvalidatedRegions *Invalidated) { RegionBindingsRef B = RegionStoreManager::getRegionBindings(store); invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS, @@ -1080,15 +1124,10 @@ RegionStoreManager::invalidateRegions(Store store, W.GenerateClusters(); // Add the regions to the worklist. - for (ArrayRef<const MemRegion *>::iterator - I = Regions.begin(), E = Regions.end(); I != E; ++I) - W.AddToWorkList(*I, /*IsConst=*/false); - - for (ArrayRef<const MemRegion *>::iterator I = ConstRegions.begin(), - E = ConstRegions.end(); - I != E; ++I) { - W.AddToWorkList(*I, /*IsConst=*/true); - } + populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false, + TopLevelRegions); + populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true, + TopLevelConstRegions); W.RunWorkList(); diff --git a/clang/test/Analysis/malloc.cpp b/clang/test/Analysis/malloc.cpp index a7c365289f3..54efa1c2bd7 100644 --- a/clang/test/Analysis/malloc.cpp +++ b/clang/test/Analysis/malloc.cpp @@ -5,7 +5,7 @@ void *malloc(size_t); void free(void *); void *realloc(void *ptr, size_t size); void *calloc(size_t nmemb, size_t size); - +char *strdup(const char *s); void checkThatMallocCheckerIsRunning() { malloc(4); @@ -67,3 +67,36 @@ struct X get() { result.a = malloc(4); return result; // no-warning } + +// Ensure that regions accessible through a LazyCompoundVal trigger region escape. +// Malloc checker used to report leaks for the following two test cases. +struct Property { + char* getterName; + Property(char* n) + : getterName(n) {} + +}; +void append(Property x); + +void appendWrapper(char *getterName) { + append(Property(getterName)); +} +void foo(const char* name) { + char* getterName = strdup(name); + appendWrapper(getterName); // no-warning +} + +struct NestedProperty { + Property prop; + NestedProperty(Property p) + : prop(p) {} +}; +void appendNested(NestedProperty x); + +void appendWrapperNested(char *getterName) { + appendNested(NestedProperty(Property(getterName))); +} +void fooNested(const char* name) { + char* getterName = strdup(name); + appendWrapperNested(getterName); // no-warning +}
\ No newline at end of file |