diff options
author | Anna Zaks <ganna@apple.com> | 2012-01-04 23:54:01 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-01-04 23:54:01 +0000 |
commit | eb31a76d1cdaaf8874c549dc6bd964ff270d3822 (patch) | |
tree | 2431945856d47f0454cf15617fe52bd33e15b095 | |
parent | f063a3b783e22effa7972d05830cee942b2499ce (diff) |
[analyzer] Be less pessimistic about invalidation of global variables
as a result of a call.
Problem:
Global variables, which come in from system libraries should not be
invalidated by all calls. Also, non-system globals should not be
invalidated by system calls.
Solution:
The following solution to invalidation of globals seems flexible enough
for taint (does not invalidate stdin) and should not lead to too
many false positives. We split globals into 3 classes:
* immutable - values are preserved by calls (unless the specific
global is passed in as a parameter):
A : Most system globals and const scalars
* invalidated by functions defined in system headers:
B: errno
* invalidated by all other functions (note, these functions may in
turn contain system calls):
B: errno
C: all other globals (which are not in A nor B)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147569 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 7 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h | 111 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h | 11 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h | 10 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/Store.h | 7 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 15 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 22 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 10 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/MemRegion.cpp | 70 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ProgramState.cpp | 12 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 64 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/Store.cpp | 6 | ||||
-rw-r--r-- | test/Analysis/global-region-invalidation.c | 75 | ||||
-rw-r--r-- | test/Analysis/misc-ps.c | 18 | ||||
-rw-r--r-- | test/Analysis/system-header-simulator.h | 10 |
16 files changed, 325 insertions, 125 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 7409b19e4e..3877cb88b4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -470,13 +470,6 @@ private: const ProgramPointTag *tag, bool isLoad); bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred); - - -public: - /// Returns true if calling the specific function or method would possibly - /// cause global variables to be invalidated. - bool doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const; - }; } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 406cd5a944..b6cf486ec9 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -73,12 +73,16 @@ public: StackArgumentsSpaceRegionKind, HeapSpaceRegionKind, UnknownSpaceRegionKind, - NonStaticGlobalSpaceRegionKind, StaticGlobalSpaceRegionKind, - BEG_GLOBAL_MEMSPACES = NonStaticGlobalSpaceRegionKind, - END_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind, + GlobalInternalSpaceRegionKind, + GlobalSystemSpaceRegionKind, + GlobalImmutableSpaceRegionKind, + BEG_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind, + END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEG_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind, + END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, BEG_MEMSPACES = GenericMemSpaceRegionKind, - END_MEMSPACES = StaticGlobalSpaceRegionKind, + END_MEMSPACES = GlobalImmutableSpaceRegionKind, // Untyped regions. SymbolicRegionKind, AllocaRegionKind, @@ -150,7 +154,7 @@ public: static bool classof(const MemRegion*) { return true; } }; -/// MemSpaceRegion - A memory region that represents and "memory space"; +/// MemSpaceRegion - A memory region that represents a "memory space"; /// for example, the set of global variables, the stack frame, etc. class MemSpaceRegion : public MemRegion { protected: @@ -187,7 +191,11 @@ public: return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES; } }; - + +/// \class The region of the static variables within the current CodeTextRegion +/// scope. +/// Currently, only the static locals are placed there, so we know that these +/// variables do not get invalidated by calls to other functions. class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { friend class MemRegionManager; @@ -207,22 +215,86 @@ public: return R->getKind() == StaticGlobalSpaceRegionKind; } }; - + +/// \class The region for all the non-static global variables. +/// +/// This class is further split into subclasses for efficient implementation of +/// invalidating a set of related global values as is done in +/// RegionStoreManager::invalidateRegions (instead of finding all the dependent +/// globals, we invalidate the whole parent region). class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { friend class MemRegionManager; - NonStaticGlobalSpaceRegion(MemRegionManager *mgr) - : GlobalsSpaceRegion(mgr, NonStaticGlobalSpaceRegionKind) {} +protected: + NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) + : GlobalsSpaceRegion(mgr, k) {} public: void dumpToStream(raw_ostream &os) const; static bool classof(const MemRegion *R) { - return R->getKind() == NonStaticGlobalSpaceRegionKind; + Kind k = R->getKind(); + return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES && + k <= END_NON_STATIC_GLOBAL_MEMSPACES; } }; - + +/// \class The region containing globals which are defined in system/external +/// headers and are considered modifiable by system calls (ex: errno). +class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalSystemSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalSystemSpaceRegionKind; + } +}; + +/// \class The region containing globals which are considered not to be modified +/// or point to data which could be modified as a result of a function call +/// (system or internal). Ex: Const global scalars would be modeled as part of +/// this region. This region also includes most system globals since they have +/// low chance of being modified. +class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalImmutableSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalImmutableSpaceRegionKind; + } +}; + +/// \class The region containing globals which can be modified by calls to +/// "internally" defined functions - (for now just) functions other then system +/// calls. +class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalInternalSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalInternalSpaceRegionKind; + } +}; + class HeapSpaceRegion : public MemSpaceRegion { virtual void anchor(); friend class MemRegionManager; @@ -927,7 +999,10 @@ class MemRegionManager { llvm::BumpPtrAllocator& A; llvm::FoldingSet<MemRegion> Regions; - NonStaticGlobalSpaceRegion *globals; + GlobalInternalSpaceRegion *InternalGlobals; + GlobalSystemSpaceRegion *SystemGlobals; + GlobalImmutableSpaceRegion *ImmutableGlobals; + llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> StackLocalsSpaceRegions; @@ -942,7 +1017,8 @@ class MemRegionManager { public: MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) - : C(c), A(a), globals(0), heap(0), unknown(0), code(0) {} + : C(c), A(a), InternalGlobals(0), SystemGlobals(0), ImmutableGlobals(0), + heap(0), unknown(0), code(0) {} ~MemRegionManager(); @@ -962,7 +1038,9 @@ public: /// getGlobalsRegion - Retrieve the memory region associated with /// global variables. - const GlobalsSpaceRegion *getGlobalsRegion(const CodeTextRegion *R = 0); + const GlobalsSpaceRegion *getGlobalsRegion( + MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind, + const CodeTextRegion *R = 0); /// getHeapRegion - Retrieve the memory region associated with the /// generic "heap". @@ -1059,11 +1137,6 @@ public: const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc = NULL); - bool isGlobalsRegion(const MemRegion* R) { - assert(R); - return R == globals; - } - private: template <typename RegionTy, typename A1> RegionTy* getRegion(const A1 a1); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index ed589f9c44..500f587e85 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -19,6 +19,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/PointerUnion.h" namespace clang { @@ -233,6 +234,16 @@ public: return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE); } + /// Check if the callee is declared in the system header. + bool isInSystemHeader() const { + if (const Decl *FD = getDecl()) { + const SourceManager &SM = + State->getStateManager().getContext().getSourceManager(); + return SM.isInSystemHeader(FD->getLocation()); + } + return false; + } + const Expr *getOriginExpr() const { if (!CallE) return Msg.getOriginExpr(); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 700a26505b..e9d6d6ec96 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -34,8 +34,8 @@ class ASTContext; namespace ento { +class CallOrObjCMessage; class ProgramStateManager; - typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&, SubEngine&); typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&); @@ -219,9 +219,9 @@ public: /// 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(ArrayRef<const MemRegion *> Regions, - const Expr *E, unsigned BlockCount, - StoreManager::InvalidatedSymbols *IS = 0, - bool invalidateGlobals = false) const; + const Expr *E, unsigned BlockCount, + StoreManager::InvalidatedSymbols *IS = 0, + const CallOrObjCMessage *Call = 0) const; /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. @@ -384,7 +384,7 @@ private: invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned BlockCount, StoreManager::InvalidatedSymbols &IS, - bool invalidateGlobals) const; + const CallOrObjCMessage *Call) const; }; class ProgramStateSet { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index e7835dbab8..87586ae2aa 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -29,6 +29,7 @@ class StackFrameContext; namespace ento { +class CallOrObjCMessage; class ProgramState; class ProgramStateManager; class SubRegionMap; @@ -180,8 +181,8 @@ public: /// 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] invalidateGlobals If \c true, any non-static global regions - /// are invalidated as well. + /// \param[in] Call The call expression which will be used to determine which + /// globals should get invalidated. /// \param[in,out] Regions 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 @@ -190,7 +191,7 @@ public: ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, InvalidatedSymbols &IS, - bool invalidateGlobals, + const CallOrObjCMessage *Call, InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 3c7c907a60..dcc7ab95dc 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -407,8 +407,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, default: { const MemSpaceRegion *MS = MR->getMemorySpace(); - switch (MS->getKind()) { - case MemRegion::StackLocalsSpaceRegionKind: { + if (isa<StackLocalsSpaceRegion>(MS)) { const VarRegion *VR = dyn_cast<VarRegion>(MR); const VarDecl *VD; if (VR) @@ -422,7 +421,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, os << "the address of a local stack variable"; return true; } - case MemRegion::StackArgumentsSpaceRegionKind: { + + if (isa<StackArgumentsSpaceRegion>(MS)) { const VarRegion *VR = dyn_cast<VarRegion>(MR); const VarDecl *VD; if (VR) @@ -436,8 +436,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, os << "the address of a parameter"; return true; } - case MemRegion::NonStaticGlobalSpaceRegionKind: - case MemRegion::StaticGlobalSpaceRegionKind: { + + if (isa<GlobalsSpaceRegion>(MS)) { const VarRegion *VR = dyn_cast<VarRegion>(MR); const VarDecl *VD; if (VR) @@ -454,9 +454,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, os << "the address of a global variable"; return true; } - default: - return false; - } + + return false; } } } diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 9b0e66fffb..f7022c6482 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -24,7 +24,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/ImmutableList.h" @@ -158,27 +157,6 @@ const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc) return state; } -bool -ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const -{ - if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) { - SVal calleeV = callOrMessage.getFunctionCallee(); - if (const FunctionTextRegion *codeR = - dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) { - - const FunctionDecl *fd = codeR->getDecl(); - if (const IdentifierInfo *ii = fd->getIdentifier()) { - StringRef fname = ii->getName(); - if (fname == "strlen") - return false; - } - } - } - - // The conservative answer: invalidates globals. - return true; -} - //===----------------------------------------------------------------------===// // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 4134b352be..99752e5408 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -294,15 +294,17 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (ObjTy->isRecordType()) { regionsToInvalidate.push_back(EleReg); // Invalidate the regions. + // TODO: Pass the call to new information as the last argument, to limit + // the globals which will get invalidated. state = state->invalidateRegions(regionsToInvalidate, - CNE, blockCount, 0, - /* invalidateGlobals = */ true); + CNE, blockCount, 0, 0); } else { // Invalidate the regions. + // TODO: Pass the call to new information as the last argument, to limit + // the globals which will get invalidated. state = state->invalidateRegions(regionsToInvalidate, - CNE, blockCount, 0, - /* invalidateGlobals = */ true); + CNE, blockCount, 0, 0); if (CNE->hasInitializer()) { SVal V = state->getSVal(*CNE->constructor_arg_begin()); diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 46ebd84b65..faffee75fb 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -200,7 +200,7 @@ ExprEngine::invalidateArguments(const ProgramState *State, // global variables. return State->invalidateRegions(RegionsToInvalidate, Call.getOriginExpr(), Count, - &IS, doesInvalidateGlobals(Call)); + &IS, &Call); } diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 2ddaed5b05..8af0251ee6 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -19,6 +19,7 @@ #include "clang/Analysis/Support/BumpVector.h" #include "clang/AST/CharUnits.h" #include "clang/AST/RecordLayout.h" +#include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -459,10 +460,6 @@ void FieldRegion::dumpToStream(raw_ostream &os) const { os << superRegion << "->" << *getDecl(); } -void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const { - os << "NonStaticGlobalSpaceRegion"; -} - void ObjCIvarRegion::dumpToStream(raw_ostream &os) const { os << "ivar{" << superRegion << ',' << *getDecl() << '}'; } @@ -491,6 +488,22 @@ void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const { os << "StaticGlobalsMemSpace{" << CR << '}'; } +void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const { + os << "NonStaticGlobalSpaceRegion"; +} + +void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const { + os << "GlobalInternalSpaceRegion"; +} + +void GlobalSystemSpaceRegion::dumpToStream(raw_ostream &os) const { + os << "GlobalSystemSpaceRegion"; +} + +void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const { + os << "GlobalImmutableSpaceRegion"; +} + //===----------------------------------------------------------------------===// // MemRegionManager methods. //===----------------------------------------------------------------------===// @@ -542,10 +555,18 @@ MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) { } const GlobalsSpaceRegion -*MemRegionManager::getGlobalsRegion(const CodeTextRegion *CR) { - if (!CR) - return LazyAllocate(globals); +*MemRegionManager::getGlobalsRegion(MemRegion::Kind K, + const CodeTextRegion *CR) { + if (!CR) { + if (K == MemRegion::GlobalSystemSpaceRegionKind) + return LazyAllocate(SystemGlobals); + if (K == MemRegion::GlobalImmutableSpaceRegionKind) + return LazyAllocate(ImmutableGlobals); + assert(K == MemRegion::GlobalInternalSpaceRegionKind); + return LazyAllocate(InternalGlobals); + } + assert(K == MemRegion::StaticGlobalSpaceRegionKind); StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR]; if (R) return R; @@ -570,7 +591,6 @@ const MemSpaceRegion *MemRegionManager::getCodeRegion() { //===----------------------------------------------------------------------===// // Constructing regions. //===----------------------------------------------------------------------===// - const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str){ return getSubRegion<StringRegion>(Str, getGlobalsRegion()); } @@ -579,9 +599,31 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { const MemRegion *sReg = 0; - if (D->hasGlobalStorage() && !D->isStaticLocal()) - sReg = getGlobalsRegion(); - else { + if (D->hasGlobalStorage() && !D->isStaticLocal()) { + + // First handle the globals defined in system headers. + if (C.getSourceManager().isInSystemHeader(D->getLocation())) { + // Whitelist the system globals which often DO GET modified, assume the + // rest are immutable. + if (D->getName().find("errno") != StringRef::npos) + sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); + else + sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); + + // Treat other globals as GlobalInternal unless they are constants. + } else { + QualType GQT = D->getType(); + const Type *GT = GQT.getTypePtrOrNull(); + // TODO: We could walk the complex types here and see if everything is + // constified. + if (GT && GQT.isConstQualified() && GT->isArithmeticType()) + sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); + else + sReg = getGlobalsRegion(); + } + + // Finally handle static locals. + } else { // FIXME: Once we implement scope handling, we will need to properly lookup // 'D' to the proper LocationContext. const DeclContext *DC = D->getDeclContext(); @@ -599,13 +641,15 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, assert(D->isStaticLocal()); const Decl *D = STC->getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - sReg = getGlobalsRegion(getFunctionTextRegion(FD)); + sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, + getFunctionTextRegion(FD)); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(BD->getSignatureAsWritten()->getType()), STC->getAnalysisDeclContext()); - sReg = getGlobalsRegion(BTR); + sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, + BTR); } else { // FIXME: For ObjC-methods, we need a new CodeTextRegion. For now diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index eac9c1c99c..4b98ce8b0f 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -136,20 +136,20 @@ const ProgramState * ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, StoreManager::InvalidatedSymbols *IS, - bool invalidateGlobals) const { + const CallOrObjCMessage *Call) const { if (!IS) { StoreManager::InvalidatedSymbols invalidated; return invalidateRegionsImpl(Regions, E, Count, - invalidated, invalidateGlobals); + invalidated, Call); } - return invalidateRegionsImpl(Regions, E, Count, *IS, invalidateGlobals); + return invalidateRegionsImpl(Regions, E, Count, *IS, Call); } const ProgramState * ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, StoreManager::InvalidatedSymbols &IS, - bool invalidateGlobals) const { + const CallOrObjCMessage *Call) const { ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); @@ -157,14 +157,14 @@ ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, StoreManager::InvalidatedRegions Invalidated; const StoreRef &newStore = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS, - invalidateGlobals, &Invalidated); + Call, &Invalidated); const ProgramState *newState = makeWithStore(newStore); return Eng->processRegionChanges(newState, &IS, Regions, Invalidated); } const StoreRef &newStore = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS, - invalidateGlobals, NULL); + Call, NULL); return makeWithStore(newStore); } diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 56ce0e13a9..a0d1bada24 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -20,6 +20,7 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" @@ -235,11 +236,16 @@ public: //===-------------------------------------------------------------------===// // Binding values to regions. //===-------------------------------------------------------------------===// + RegionBindings invalidateGlobalRegion(MemRegion::Kind K, + const Expr *Ex, + unsigned Count, + RegionBindings B, + InvalidatedRegions *Invalidated); StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, InvalidatedSymbols &IS, - bool invalidateGlobals, + const CallOrObjCMessage *Call, InvalidatedRegions *Invalidated); public: // Made public for helper classes. @@ -718,15 +724,39 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { B = RM.addBinding(B, baseR, BindingKey::Direct, V); } +RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K, + const Expr *Ex, + unsigned Count, + RegionBindings B, + InvalidatedRegions *Invalidated) { + // Bind the globals memory space to a new symbol that we will use to derive + // the bindings for all globals. + const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K); + SVal V = + svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex, + /* symbol type, doesn't matter */ Ctx.IntTy, + Count); + + B = removeBinding(B, GS); + B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V); + + // Even if there are no bindings in the global scope, we still need to + // record that we touched it. + if (Invalidated) + Invalidated->push_back(GS); + + return B; +} + StoreRef RegionStoreManager::invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions, const Expr *Ex, unsigned Count, InvalidatedSymbols &IS, - bool invalidateGlobals, + const CallOrObjCMessage *Call, InvalidatedRegions *Invalidated) { invalidateRegionsWorker W(*this, StateMgr, RegionStoreManager::GetRegionBindings(store), - Ex, Count, IS, Invalidated, invalidateGlobals); + Ex, Count, IS, Invalidated, false); // Scan the bindings and generate the clusters. W.GenerateClusters(); @@ -741,20 +771,20 @@ StoreRef RegionStoreManager::invalidateRegions(Store store, // Return the new bindings. RegionBindings B = W.getRegionBindings(); - if (invalidateGlobals) { - // Bind the non-static globals memory space to a new symbol that we will - // use to derive the bindings for all non-static globals. - const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(); - SVal V = - svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex, - /* symbol type, doesn't matter */ Ctx.IntTy, - Count); - B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V); - - // Even if there are no bindings in the global scope, we still need to - // record that we touched it. - if (Invalidated) - Invalidated->push_back(GS); + // For all globals which are not static nor immutable: determine which global + // regions should be invalidated and invalidate them. + // TODO: This could possibly be more precise with modules. + // + // System calls invalidate only system globals. + if (Call && Call->isInSystemHeader()) { + B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, + Ex, Count, B, Invalidated); + // Internal calls might invalidate both system and internal globals. + } else { + B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, + Ex, Count, B, Invalidated); + B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, + Ex, Count, B, Invalidated); } return StoreRef(B.getRootWithoutRetain(), *this); diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index 825510e00b..543f87879d 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -101,8 +101,10 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) case MemRegion::StackArgumentsSpaceRegionKind: case MemRegion::HeapSpaceRegionKind: case MemRegion::UnknownSpaceRegionKind: - case MemRegion::NonStaticGlobalSpaceRegionKind: - case MemRegion::StaticGlobalSpaceRegionKind: { + case MemRegion::StaticGlobalSpaceRegionKind: + case MemRegion::GlobalInternalSpaceRegionKind: + case MemRegion::GlobalSystemSpaceRegionKind: + case MemRegion::GlobalImmutableSpaceRegionKind: { llvm_unreachable("Invalid region cast"); } diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c new file mode 100644 index 0000000000..184ffb870f --- /dev/null +++ b/test/Analysis/global-region-invalidation.c @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest -verify %s + +// Note, we do need to include headers here, since the analyzer checks if the function declaration is located in a system header. +#include "system-header-simulator.h" + +// Test that system header does not invalidate the internal global. +int size_rdar9373039 = 1; +int rdar9373039() { + int x; + int j = 0; + + for (int i = 0 ; i < size_rdar9373039 ; ++i) + x = 1; + + // strlen doesn't invalidate the value of 'size_rdar9373039'. + int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned |