r179553 - [analyzer] Properly invalidate global regions on opaque function calls.
Jordan Rose
jordan_rose at apple.com
Mon Apr 15 13:39:41 PDT 2013
Author: jrose
Date: Mon Apr 15 15:39:41 2013
New Revision: 179553
URL: http://llvm.org/viewvc/llvm-project?rev=179553&view=rev
Log:
[analyzer] Properly invalidate global regions on opaque function calls.
This fixes a regression where a call to a function we can't reason about
would not actually invalidate global regions that had explicit bindings.
void test_that_now_works() {
globalInt = 42;
clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
invalidateGlobals();
clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
}
This has probably been around since the initial "cluster" refactoring of
RegionStore, if not longer.
<rdar://problem/13464044>
Modified:
cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
cfe/trunk/test/Analysis/global_region_invalidation.mm
Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=179553&r1=179552&r2=179553&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Mon Apr 15 15:39:41 2013
@@ -604,6 +604,17 @@ ento::CreateFieldsOnlyRegionStoreManager
//===----------------------------------------------------------------------===//
namespace {
+/// Used to determine which global regions are automatically included in the
+/// initial worklist of a ClusterAnalysis.
+enum GlobalsFilterKind {
+ /// Don't include any global regions.
+ GFK_None,
+ /// Only include system globals.
+ GFK_SystemOnly,
+ /// Include all global regions.
+ GFK_All
+};
+
template <typename DERIVED>
class ClusterAnalysis {
protected:
@@ -620,19 +631,36 @@ protected:
SValBuilder &svalBuilder;
RegionBindingsRef B;
-
- const bool includeGlobals;
+private:
+ GlobalsFilterKind GlobalsFilter;
+
+protected:
const ClusterBindings *getCluster(const MemRegion *R) {
return B.lookup(R);
}
+ /// Returns true if the memory space of the given region is one of the global
+ /// regions specially included at the start of analysis.
+ bool isInitiallyIncludedGlobalRegion(const MemRegion *R) {
+ switch (GlobalsFilter) {
+ case GFK_None:
+ return false;
+ case GFK_SystemOnly:
+ return isa<GlobalSystemSpaceRegion>(R->getMemorySpace());
+ case GFK_All:
+ return isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace());
+ }
+
+ llvm_unreachable("unknown globals filter");
+ }
+
public:
ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr,
- RegionBindingsRef b, const bool includeGlobals)
+ RegionBindingsRef b, GlobalsFilterKind GFK)
: RM(rm), Ctx(StateMgr.getContext()),
svalBuilder(StateMgr.getSValBuilder()),
- B(b), includeGlobals(includeGlobals) {}
+ B(b), GlobalsFilter(GFK) {}
RegionBindingsRef getRegionBindings() const { return B; }
@@ -650,9 +678,9 @@ public:
assert(!Cluster.isEmpty() && "Empty clusters should be removed");
static_cast<DERIVED*>(this)->VisitAddedToCluster(Base, Cluster);
- if (includeGlobals)
- if (isa<NonStaticGlobalSpaceRegion>(Base->getMemorySpace()))
- AddToWorkList(Base, &Cluster);
+ // If this is an interesting global region, add it the work list up front.
+ if (isInitiallyIncludedGlobalRegion(Base))
+ AddToWorkList(WorkListElement(Base), &Cluster);
}
}
@@ -905,8 +933,8 @@ public:
InvalidatedSymbols &is,
InvalidatedSymbols &inConstIS,
StoreManager::InvalidatedRegions *r,
- bool includeGlobals)
- : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
+ GlobalsFilterKind GFK)
+ : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK),
Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){}
/// \param IsConst Specifies if the region we are invalidating is constant.
@@ -1032,8 +1060,7 @@ void invalidateRegionsWorker::VisitClust
return;
}
- if (includeGlobals &&
- isa<NonStaticGlobalSpaceRegion>(baseR->getMemorySpace())) {
+ if (isInitiallyIncludedGlobalRegion(baseR)) {
// If the region is a global and we are invalidating all globals,
// just erase the entry. This causes all globals to be lazily
// symbolicated from the same base symbol.
@@ -1116,9 +1143,19 @@ RegionStoreManager::invalidateRegions(St
InvalidatedRegions *TopLevelRegions,
InvalidatedRegions *TopLevelConstRegions,
InvalidatedRegions *Invalidated) {
- RegionBindingsRef B = RegionStoreManager::getRegionBindings(store);
+ GlobalsFilterKind GlobalsFilter;
+ if (Call) {
+ if (Call->isInSystemHeader())
+ GlobalsFilter = GFK_SystemOnly;
+ else
+ GlobalsFilter = GFK_All;
+ } else {
+ GlobalsFilter = GFK_None;
+ }
+
+ RegionBindingsRef B = getRegionBindings(store);
invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS,
- Invalidated, false);
+ Invalidated, GlobalsFilter);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
@@ -1138,14 +1175,17 @@ RegionStoreManager::invalidateRegions(St
// invalidate them. (Note that function-static and immutable globals are never
// invalidated by this.)
// TODO: This could possibly be more precise with modules.
- if (Call) {
+ switch (GlobalsFilter) {
+ case GFK_All:
+ B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
+ Ex, Count, LCtx, B, Invalidated);
+ // FALLTHROUGH
+ case GFK_SystemOnly:
B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
-
- if (!Call->isInSystemHeader()) {
- B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
- Ex, Count, LCtx, B, Invalidated);
- }
+ // FALLTHROUGH
+ case GFK_None:
+ break;
}
return StoreRef(B.asStore(), *this);
@@ -2115,8 +2155,7 @@ public:
ProgramStateManager &stateMgr,
RegionBindingsRef b, SymbolReaper &symReaper,
const StackFrameContext *LCtx)
- : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b,
- /* includeGlobals = */ false),
+ : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, GFK_None),
SymReaper(symReaper), CurrentLCtx(LCtx) {}
// Called by ClusterAnalysis.
Modified: cfe/trunk/test/Analysis/global_region_invalidation.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/global_region_invalidation.mm?rev=179553&r1=179552&r2=179553&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/global_region_invalidation.mm (original)
+++ cfe/trunk/test/Analysis/global_region_invalidation.mm Mon Apr 15 15:39:41 2013
@@ -19,27 +19,37 @@ void testGlobalRef() {
}
extern int globalInt;
+extern struct {
+ int value;
+} globalStruct;
extern void invalidateGlobals();
void testGlobalInvalidation() {
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
+
if (globalInt != 42)
return;
+ if (globalStruct.value != 43)
+ return;
clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{TRUE}}
invalidateGlobals();
clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
}
-
-//---------------------------------
-// False negatives
-//---------------------------------
-
void testGlobalInvalidationWithDirectBinding() {
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
+
globalInt = 42;
+ globalStruct.value = 43;
clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{TRUE}}
invalidateGlobals();
- // FIXME: Should be UNKNOWN.
- clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
}
More information about the cfe-commits
mailing list