r177570 - [analyzer] Invalidate regions indirectly accessible through const pointers.
Jordan Rose
jordan_rose at apple.com
Wed Mar 20 13:35:53 PDT 2013
Author: jrose
Date: Wed Mar 20 15:35:53 2013
New Revision: 177570
URL: http://llvm.org/viewvc/llvm-project?rev=177570&view=rev
Log:
[analyzer] Invalidate regions indirectly accessible through const pointers.
In this case, the value of 'x' may be changed after the call to indirectAccess:
struct Wrapper {
int *ptr;
};
void indirectAccess(const Wrapper &w);
void test() {
int x = 42;
Wrapper w = { x };
clang_analyzer_eval(x == 42); // TRUE
indirectAccess(w);
clang_analyzer_eval(x == 42); // UNKNOWN
}
This is important for modelling return-by-value objects in C++, to show
that the contents of the struct are escaping in the return copy-constructor.
<rdar://problem/13239826>
Added:
cfe/trunk/test/Analysis/call-invalidation.cpp
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=177570&r1=177569&r2=177570&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Wed Mar 20 15:35:53 2013
@@ -240,12 +240,15 @@ public:
/// \param IS the set of invalidated symbols.
/// \param Call if non-null, the invalidated regions represent parameters to
/// the call and should be considered directly invalidated.
- ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions,
- const Expr *E, unsigned BlockCount,
- const LocationContext *LCtx,
- bool CausesPointerEscape,
- InvalidatedSymbols *IS = 0,
- const CallEvent *Call = 0) const;
+ /// \param ConstRegions the set of regions whose contents are accessible,
+ /// even though the regions themselves should not be invalidated.
+ ProgramStateRef
+ invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
+ unsigned BlockCount, const LocationContext *LCtx,
+ bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
+ const CallEvent *Call = 0,
+ ArrayRef<const MemRegion *> ConstRegions =
+ ArrayRef<const MemRegion *>()) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
@@ -415,14 +418,16 @@ public:
private:
friend void ProgramStateRetain(const ProgramState *state);
friend void ProgramStateRelease(const ProgramState *state);
-
- ProgramStateRef
+
+ /// \sa invalidateRegions()
+ ProgramStateRef
invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned BlockCount,
const LocationContext *LCtx,
bool ResultsInSymbolEscape,
InvalidatedSymbols &IS,
- const CallEvent *Call) const;
+ const CallEvent *Call,
+ ArrayRef<const MemRegion *> ConstRegions) const;
};
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h?rev=177570&r1=177569&r2=177570&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h Wed Mar 20 15:35:53 2013
@@ -197,6 +197,7 @@ public:
const LocationContext *LCtx,
InvalidatedSymbols &IS,
const CallEvent *Call,
+ ArrayRef<const MemRegion *> ConstRegions,
InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=177570&r1=177569&r2=177570&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Wed Mar 20 15:35:53 2013
@@ -125,7 +125,7 @@ static bool isPointerToConst(QualType Ty
// Try to retrieve the function declaration and find the function parameter
// types which are pointers/references to a non-pointer const.
// We will not invalidate the corresponding argument regions.
-static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs,
const CallEvent &Call) {
unsigned Idx = 0;
for (CallEvent::param_type_iterator I = Call.param_type_begin(),
@@ -137,36 +137,29 @@ static void findPtrToConstParams(llvm::S
}
ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
- ProgramStateRef Orig) const {
+ ProgramStateRef Orig) const {
ProgramStateRef Result = (Orig ? Orig : getState());
+ SmallVector<const MemRegion *, 8> ConstRegions;
SmallVector<const MemRegion *, 8> RegionsToInvalidate;
getExtraInvalidatedRegions(RegionsToInvalidate);
// Indexes of arguments whose values will be preserved by the call.
- llvm::SmallSet<unsigned, 1> PreserveArgs;
+ llvm::SmallSet<unsigned, 4> PreserveArgs;
if (!argumentsMayEscape())
findPtrToConstParams(PreserveArgs, *this);
for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
- if (PreserveArgs.count(Idx))
+ const MemRegion *R = getArgSVal(Idx).getAsRegion();
+ if (!R)
continue;
- SVal V = getArgSVal(Idx);
-
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- if (Optional<nonloc::LocAsInteger> Wrapped =
- V.getAs<nonloc::LocAsInteger>())
- V = Wrapped->getLoc();
- else if (!V.getAs<Loc>())
- continue;
-
- if (const MemRegion *R = V.getAsRegion()) {
- // Mark this region for invalidation. We batch invalidate regions
- // below for efficiency.
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
+ if (PreserveArgs.count(Idx))
+ ConstRegions.push_back(R);
+ else
RegionsToInvalidate.push_back(R);
- }
}
// Invalidate designated regions using the batch invalidation API.
@@ -175,7 +168,7 @@ ProgramStateRef CallEvent::invalidateReg
return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
BlockCount, getLocationContext(),
/*CausedByPointerEscape*/ true,
- /*Symbols=*/0, this);
+ /*Symbols=*/0, this, ConstRegions);
}
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=177570&r1=177569&r2=177570&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Wed Mar 20 15:35:53 2013
@@ -140,30 +140,34 @@ ProgramStateRef ProgramState::bindDefaul
new_state;
}
+typedef ArrayRef<const MemRegion *> RegionList;
+
ProgramStateRef
-ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions,
+ProgramState::invalidateRegions(RegionList Regions,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
bool CausedByPointerEscape,
InvalidatedSymbols *IS,
- const CallEvent *Call) const {
+ const CallEvent *Call,
+ RegionList ConstRegions) const {
if (!IS) {
InvalidatedSymbols invalidated;
return invalidateRegionsImpl(Regions, E, Count, LCtx,
CausedByPointerEscape,
- invalidated, Call);
+ invalidated, Call, ConstRegions);
}
return invalidateRegionsImpl(Regions, E, Count, LCtx, CausedByPointerEscape,
- *IS, Call);
+ *IS, Call, ConstRegions);
}
ProgramStateRef
-ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+ProgramState::invalidateRegionsImpl(RegionList Regions,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
bool CausedByPointerEscape,
InvalidatedSymbols &IS,
- const CallEvent *Call) const {
+ const CallEvent *Call,
+ RegionList ConstRegions) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
@@ -171,7 +175,7 @@ ProgramState::invalidateRegionsImpl(Arra
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &newStore
= Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
- Call, &Invalidated);
+ Call, ConstRegions, &Invalidated);
ProgramStateRef newState = makeWithStore(newStore);
@@ -184,7 +188,7 @@ ProgramState::invalidateRegionsImpl(Arra
const StoreRef &newStore =
Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
- Call, NULL);
+ Call, ConstRegions, NULL);
return makeWithStore(newStore);
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=177570&r1=177569&r2=177570&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Wed Mar 20 15:35:53 2013
@@ -370,6 +370,7 @@ public:
const LocationContext *LCtx,
InvalidatedSymbols &IS,
const CallEvent *Call,
+ ArrayRef<const MemRegion *> ConstRegions,
InvalidatedRegions *Invalidated);
bool scanReachableSymbols(Store S, const MemRegion *R,
@@ -595,7 +596,8 @@ template <typename DERIVED>
class ClusterAnalysis {
protected:
typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
- typedef SmallVector<const MemRegion *, 10> WorkList;
+ typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement;
+ typedef SmallVector<WorkListElement, 10> WorkList;
llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
@@ -642,35 +644,35 @@ public:
}
}
- bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) {
+ bool AddToWorkList(WorkListElement E, const ClusterBindings *C) {
if (C && !Visited.insert(C))
return false;
- WL.push_back(R);
+ WL.push_back(E);
return true;
}
- bool AddToWorkList(const MemRegion *R) {
- const MemRegion *baseR = R->getBaseRegion();
- return AddToWorkList(baseR, getCluster(baseR));
+ bool AddToWorkList(const MemRegion *R, bool Flag = false) {
+ const MemRegion *BaseR = R->getBaseRegion();
+ return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR));
}
void RunWorkList() {
while (!WL.empty()) {
- const MemRegion *baseR = WL.pop_back_val();
+ WorkListElement E = WL.pop_back_val();
+ const MemRegion *BaseR = E.getPointer();
- // First visit the cluster.
- if (const ClusterBindings *Cluster = getCluster(baseR))
- static_cast<DERIVED*>(this)->VisitCluster(baseR, *Cluster);
-
- // Next, visit the base region.
- static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR),
+ E.getInt());
}
}
-public:
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitBaseRegion(const MemRegion *baseR) {}
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C) {}
+
+ void VisitCluster(const MemRegion *BaseR, const ClusterBindings *C,
+ bool Flag) {
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, C);
+ }
};
}
@@ -884,10 +886,8 @@ public:
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
Ex(ex), Count(count), LCtx(lctx), IS(is), Regions(r) {}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitBaseRegion(const MemRegion *baseR);
-
-private:
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C,
+ bool Flag);
void VisitBinding(SVal V);
};
}
@@ -917,18 +917,16 @@ void invalidateRegionsWorker::VisitBindi
}
}
-void invalidateRegionsWorker::VisitCluster(const MemRegion *BaseR,
- const ClusterBindings &C) {
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
- VisitBinding(I.getData());
-
- B = B.remove(BaseR);
-}
+void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
+ const ClusterBindings *C,
+ bool IsConst) {
+ if (C) {
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
+ VisitBinding(I.getData());
-void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
- // Symbolic region? Mark that symbol touched by the invalidation.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
- IS.insert(SR->getSymbol());
+ if (!IsConst)
+ B = B.remove(baseR);
+ }
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
@@ -957,6 +955,13 @@ void invalidateRegionsWorker::VisitBaseR
return;
}
+ if (IsConst)
+ return;
+
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ IS.insert(SR->getSymbol());
+
// Otherwise, we have a normal data region. Record that we touched the region.
if (Regions)
Regions->push_back(baseR);
@@ -1043,10 +1048,11 @@ RegionStoreManager::invalidateRegions(St
const LocationContext *LCtx,
InvalidatedSymbols &IS,
const CallEvent *Call,
+ ArrayRef<const MemRegion *> ConstRegions,
InvalidatedRegions *Invalidated) {
- invalidateRegionsWorker W(*this, StateMgr,
- RegionStoreManager::getRegionBindings(store),
- Ex, Count, LCtx, IS, Invalidated, false);
+ RegionBindingsRef B = RegionStoreManager::getRegionBindings(store);
+ invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS,
+ Invalidated, false);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
@@ -1054,12 +1060,18 @@ RegionStoreManager::invalidateRegions(St
// Add the regions to the worklist.
for (ArrayRef<const MemRegion *>::iterator
I = Regions.begin(), E = Regions.end(); I != E; ++I)
- W.AddToWorkList(*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);
+ }
W.RunWorkList();
// Return the new bindings.
- RegionBindingsRef B = W.getRegionBindings();
+ B = W.getRegionBindings();
// For all globals which are not static nor immutable: determine which global
// regions should be invalidated and invalidate them.
@@ -2051,7 +2063,8 @@ public:
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
+ using ClusterAnalysis::VisitCluster;
bool UpdatePostponed();
void VisitBinding(SVal V);
@@ -2094,13 +2107,16 @@ void removeDeadBindingsWorker::VisitAdde
}
void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
- const ClusterBindings &C) {
+ const ClusterBindings *C) {
+ if (!C)
+ return;
+
// Mark the symbol for any SymbolicRegion with live bindings as live itself.
// This means we should continue to track that symbol.
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
VisitBinding(I.getData());
}
Added: cfe/trunk/test/Analysis/call-invalidation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/call-invalidation.cpp?rev=177570&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/call-invalidation.cpp (added)
+++ cfe/trunk/test/Analysis/call-invalidation.cpp Wed Mar 20 15:35:53 2013
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(bool);
+
+void usePointer(int * const *);
+void useReference(int * const &);
+
+void testPointer() {
+ int x;
+ int *p;
+
+ p = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ usePointer(&p);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ p = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useReference(p);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ int * const cp1 = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ usePointer(&cp1);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ int * const cp2 = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useReference(cp2);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
+
+struct Wrapper {
+ int *ptr;
+};
+
+void useStruct(Wrapper &w);
+void useConstStruct(const Wrapper &w);
+
+void testPointerStruct() {
+ int x;
+ Wrapper w;
+
+ w.ptr = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ w.ptr = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useConstStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
+
+struct RefWrapper {
+ int &ref;
+};
+
+void useStruct(RefWrapper &w);
+void useConstStruct(const RefWrapper &w);
+
+void testReferenceStruct() {
+ int x;
+ RefWrapper w = { x };
+
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
+// FIXME: This test is split into two functions because region invalidation
+// does not preserve reference bindings. <rdar://problem/13320347>
+void testConstReferenceStruct() {
+ int x;
+ RefWrapper w = { x };
+
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useConstStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
More information about the cfe-commits
mailing list