summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp107
1 files changed, 24 insertions, 83 deletions
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index ee055ad..1ccf339 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -16,8 +16,8 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -25,7 +25,7 @@ using namespace clang;
using namespace ento;
namespace {
-typedef llvm::SmallVector<SymbolRef, 2> SymbolVector;
+typedef SmallVector<SymbolRef, 2> SymbolVector;
struct StreamState {
private:
@@ -50,8 +50,7 @@ public:
class SimpleStreamChecker : public Checker<check::PostCall,
check::PreCall,
check::DeadSymbols,
- check::Bind,
- check::RegionChanges> {
+ check::PointerEscape> {
mutable IdentifierInfo *IIfopen, *IIfclose;
@@ -80,20 +79,11 @@ public:
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- /// Deal with symbol escape as a byproduct of a bind.
- void checkBind(SVal location, SVal val, const Stmt*S,
- CheckerContext &C) const;
-
- /// Deal with symbol escape as a byproduct of a region change.
- ProgramStateRef
- checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const;
- bool wantsRegionChangeUpdate(ProgramStateRef state) const {
- return true;
- }
+ /// Stop tracking addresses which escape.
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
};
} // end anonymous namespace
@@ -237,7 +227,7 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
ExplodedNode *ErrNode) const {
// Attach bug reports to the leak node.
// TODO: Identify the leaked file descriptor.
- for (llvm::SmallVector<SymbolRef, 2>::iterator
+ for (SmallVector<SymbolRef, 2>::iterator
I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
BugReport *R = new BugReport(*LeakBugType,
"Opened file is never closed; potential resource leak", ErrNode);
@@ -246,45 +236,6 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
}
}
-// Check various ways a symbol can be invalidated.
-// Stop tracking symbols when a value escapes as a result of checkBind.
-// A value escapes in three possible cases:
-// (1) We are binding to something that is not a memory region.
-// (2) We are binding to a MemRegion that does not have stack storage
-// (3) We are binding to a MemRegion with stack storage that the store
-// does not understand.
-void SimpleStreamChecker::checkBind(SVal loc, SVal val, const Stmt *S,
- CheckerContext &C) const {
- // Are we storing to something that causes the value to "escape"?
- bool escapes = true;
- ProgramStateRef state = C.getState();
-
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
- escapes = !regionLoc->getRegion()->hasStackStorage();
-
- if (!escapes) {
- // To test (3), generate a new state with the binding added. If it is
- // the same state, then it escapes (since the store cannot represent
- // the binding). Do this only if we know that the store is not supposed
- // to generate the same state.
- SVal StoredVal = state->getSVal(regionLoc->getRegion());
- if (StoredVal != val)
- escapes = (state == (state->bindLoc(*regionLoc, val)));
- }
- }
-
- // If our store can represent the binding and we aren't storing to something
- // that doesn't have local storage then just return the state and
- // continue as is.
- if (!escapes)
- return;
-
- // Otherwise, find all symbols referenced by 'val' that we are tracking
- // and stop tracking them.
- state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
- C.addTransition(state);
-}
-
bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
// If it's not in a system header, assume it might close a file.
if (!Call.isInSystemHeader())
@@ -300,38 +251,28 @@ bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
return true;
}
-// If the symbol we are tracking is invalidated, do not track the symbol as
+// If the pointer we are tracking escaped, do not track the symbol as
// we cannot reason about it anymore.
ProgramStateRef
-SimpleStreamChecker::checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const {
-
- if (!invalidated || invalidated->empty())
+SimpleStreamChecker::checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ // If we know that the call cannot close a file, there is nothing to do.
+ if ((Kind == PSK_DirectEscapeOnCall ||
+ Kind == PSK_IndirectEscapeOnCall) &&
+ guaranteedNotToCloseFile(*Call)) {
return State;
-
- // If it's a call which might close the file, we assume that all regions
- // (explicit and implicit) escaped. Otherwise, whitelist explicit pointers
- // (the parameters to the call); we still can track them.
- llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
- if (!Call || guaranteedNotToCloseFile(*Call)) {
- for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
- E = ExplicitRegions.end(); I != E; ++I) {
- if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
- WhitelistedSymbols.insert(R->getSymbol());
- }
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
- E = invalidated->end(); I!=E; ++I) {
- SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end();
+ I != E; ++I) {
+ SymbolRef Sym = *I;
+
// The symbol escaped. Optimistically, assume that the corresponding file
// handle will be closed somewhere else.
- State = State->remove<StreamMap>(sym);
+ State = State->remove<StreamMap>(Sym);
}
return State;
}
OpenPOWER on IntegriCloud