aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-08-12 23:04:46 +0000
committerTed Kremenek <kremenek@apple.com>2011-08-12 23:04:46 +0000
commitca804539d908d3a0e8c72a0df5f1f571d29490bb (patch)
tree1c94c42841ae275c45b74b27fb8831fab62b4e7f /lib/StaticAnalyzer
parent79c9c75737cb22fd74d186999eccc10672eef8c0 (diff)
[analyzer] change "tag" in ProgramPoint from "void*" to a ProgramPointTag*.
Having a notion of an actual ProgramPointTag will aid in introspection of the analyzer's behavior. For example, the GraphViz output of the analyzer will pretty-print the tags in a useful manner. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137529 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Core/Checker.cpp22
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp43
8 files changed, 99 insertions, 43 deletions
diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
index 82801317cb..72d064ef81 100644
--- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
@@ -87,12 +87,9 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
if (theValueTypePointee != newValueType)
return false;
- static unsigned magic_load = 0;
- static unsigned magic_store = 0;
-
- const void *OSAtomicLoadTag = &magic_load;
- const void *OSAtomicStoreTag = &magic_store;
-
+ static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
+ static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
+
// Load 'theValue'.
ExprEngine &Engine = C.getEngine();
const GRState *state = C.getState();
@@ -111,7 +108,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
LoadTy = TR->getValueType();
}
Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(),
- state, location, OSAtomicLoadTag, LoadTy);
+ state, location, &OSAtomicLoadTag, LoadTy);
if (Tmp.empty()) {
// If no nodes were generated, other checkers must generated sinks. But
@@ -148,7 +145,8 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
SValBuilder &svalBuilder = Engine.getSValBuilder();
// Perform the comparison.
- DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
+ DefinedOrUnknownSVal Cmp =
+ svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
const GRState *stateEqual = stateLoad->assume(Cmp, true);
@@ -165,7 +163,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
}
Engine.evalStore(TmpStore, NULL, theValueExpr, N,
- stateEqual, location, val, OSAtomicStoreTag);
+ stateEqual, location, val, &OSAtomicStoreTag);
if (TmpStore.empty()) {
// If no nodes were generated, other checkers must generated sinks. But
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index ad809e7649..46aacd473f 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -88,11 +88,11 @@ namespace {
class GenericNodeBuilderRefCount {
StmtNodeBuilder *SNB;
const Stmt *S;
- const void *tag;
+ const ProgramPointTag *tag;
EndOfFunctionNodeBuilder *ENB;
public:
GenericNodeBuilderRefCount(StmtNodeBuilder &snb, const Stmt *s,
- const void *t)
+ const ProgramPointTag *t)
: SNB(&snb), S(s), tag(t), ENB(0) {}
GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb)
@@ -1671,9 +1671,11 @@ public:
BugType *overAutorelease;
BugType *returnNotOwnedForOwned;
BugReporter *BR;
+
+ llvm::DenseMap<SymbolRef, const SimpleProgramPointTag*> DeadSymbolTags;
- const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E,
- RefVal::Kind& hasErr);
+ const GRState * Update(const GRState * state, SymbolRef sym, RefVal V,
+ ArgEffect E, RefVal::Kind& hasErr);
void ProcessNonLeakError(ExplodedNodeSet& Dst,
StmtNodeBuilder& Builder,
@@ -1699,7 +1701,11 @@ public:
leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
returnNotOwnedForOwned(0), BR(0) {}
- virtual ~CFRefCount() {}
+ virtual ~CFRefCount() {
+ for (llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *>::iterator
+ it = DeadSymbolTags.begin(), ei = DeadSymbolTags.end(); it != ei; ++it)
+ delete it->second;
+ }
void RegisterChecks(ExprEngine &Eng);
@@ -1757,6 +1763,8 @@ public:
const GRState* state,
SymbolReaper& SymReaper);
+ const ProgramPointTag *getDeadSymbolTag(SymbolRef sym);
+
std::pair<ExplodedNode*, const GRState *>
HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilderRefCount Bd,
ExplodedNode* Pred, ExprEngine &Eng,
@@ -2968,7 +2976,7 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
return;
// Update the autorelease counts.
- static unsigned autoreleasetag = 0;
+ static SimpleProgramPointTag autoreleasetag("CFRefCount : Autorelease");
GenericNodeBuilderRefCount Bd(Builder, S, &autoreleasetag);
bool stop = false;
llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym,
@@ -3031,7 +3039,8 @@ void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst,
if (hasError) {
// Generate an error node.
- static int ReturnOwnLeakTag = 0;
+ static SimpleProgramPointTag
+ ReturnOwnLeakTag("CFRefCount : ReturnsOwnLeak");
state = state->set<RefBindings>(Sym, X);
ExplodedNode *N =
Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
@@ -3051,8 +3060,8 @@ void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst,
if (RE.isOwned()) {
// Trying to return a not owned object to a caller expecting an
// owned object.
-
- static int ReturnNotOwnedForOwnedTag = 0;
+ static SimpleProgramPointTag
+ ReturnNotOwnedForOwnedTag("CFRefCount : ReturnNotOwnedForOwned");
state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
if (ExplodedNode *N =
Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
@@ -3375,6 +3384,17 @@ void CFRefCount::evalEndPath(ExprEngine& Eng,
ProcessLeaks(state, Leaked, Bd, Eng, Pred);
}
+const ProgramPointTag *CFRefCount::getDeadSymbolTag(SymbolRef sym) {
+ const SimpleProgramPointTag *&tag = DeadSymbolTags[sym];
+ if (!tag) {
+ llvm::SmallString<128> buf;
+ llvm::raw_svector_ostream out(buf);
+ out << "CFRefCount : Dead Symbol : " << sym->getSymbolID();
+ tag = new SimpleProgramPointTag(out.str());
+ }
+ return tag;
+}
+
void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst,
ExprEngine& Eng,
StmtNodeBuilder& Builder,
@@ -3391,7 +3411,7 @@ void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst,
if (const RefVal* T = B.lookup(Sym)){
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
- GenericNodeBuilderRefCount Bd(Builder, S, Sym);
+ GenericNodeBuilderRefCount Bd(Builder, S, getDeadSymbolTag(Sym));
bool stop = false;
llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
Sym, *T, stop);
@@ -3409,7 +3429,7 @@ void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst,
state = HandleSymbolDeath(state, *I, *T, Leaked);
}
- static unsigned LeakPPTag = 0;
+ static SimpleProgramPointTag LeakPPTag("CFRefCount : Leak");
{
GenericNodeBuilderRefCount Bd(Builder, S, &LeakPPTag);
Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred);
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index dac928d56c..8c5580f741 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangStaticAnalyzerCore
BugReporterVisitors.cpp
CFRefCount.cpp
CXXExprEngine.cpp
+ Checker.cpp
CheckerContext.cpp
CheckerHelpers.cpp
CheckerManager.cpp
diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp
new file mode 100644
index 0000000000..a3bf2c236f
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/Checker.cpp
@@ -0,0 +1,22 @@
+//== Checker.cpp - Registration mechanism for checkers -----------*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines Checker, used to create and register checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/Checker.h"
+
+using namespace clang;
+using namespace ento;
+
+StringRef CheckerBase::getTagDescription() const {
+ // FIXME: We want to return the package + name of the checker here.
+ return "A Checker";
+}
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 3920a4990a..5356edc752 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -24,7 +24,7 @@ CheckerContext::~CheckerContext() {
// add it as a transition.
if (Dst.size() == size && !B.BuildSinks && !B.hasGeneratedNode) {
if (ST && ST != Pred->getState()) {
- static int autoTransitionTag = 0;
+ static SimpleProgramPointTag autoTransitionTag("CheckerContext : auto");
addTransition(ST, &autoTransitionTag);
}
else
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 6dae640b23..a0840ffb28 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/DeclBase.h"
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 4b966285ac..7a0dc412db 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -546,7 +546,8 @@ ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
}
static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
- const LocationContext *LC, const void *tag){
+ const LocationContext *LC,
+ const ProgramPointTag *tag){
switch (K) {
default:
assert(false && "Unhandled ProgramPoint kind");
@@ -571,11 +572,12 @@ static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
ExplodedNode*
StmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
- ExplodedNode* Pred,
- ProgramPoint::Kind K,
- const void *tag) {
+ ExplodedNode* Pred,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag) {
- const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
+ const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),
+ tag);
return generateNodeInternal(L, state, Pred);
}
@@ -732,7 +734,8 @@ EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
ExplodedNode*
EndOfFunctionNodeBuilder::generateNode(const GRState* State,
- ExplodedNode* P, const void *tag) {
+ ExplodedNode* P,
+ const ProgramPointTag *tag) {
hasGeneratedNode = true;
bool IsNew;
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 9db55577f4..f6ddf355eb 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -243,7 +243,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
"Error evaluating statement");
// A tag to track convenience transitions, which can be removed at cleanup.
- static unsigned tag;
+ static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node");
Builder = &builder;
EntryNode = builder.getPredecessor();
@@ -273,7 +273,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
// up. Since no symbols are dead, we can optimize and not clean out
// the constraint manager.
CleanedNode =
- Builder->generateNode(currentStmt, CleanedState, EntryNode, &tag);
+ Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
Tmp.Add(CleanedNode);
} else {
@@ -318,7 +318,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
ExplodedNode *CleanedNode = Builder->generateNode(currentStmt,
CleanedCheckerSt, *I,
- &tag);
+ &cleanupTag);
Tmp.Add(CleanedNode);
}
}
@@ -835,8 +835,7 @@ void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
if (nodeBuilder.getBlockCounter().getNumVisited(
pred->getLocationContext()->getCurrentStackFrame(),
block->getBlockID()) >= AMgr.getMaxVisit()) {
-
- static int tag = 0;
+ static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
}
}
@@ -846,10 +845,11 @@ void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
//===----------------------------------------------------------------------===//
ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St,
- ProgramPoint::Kind K, const void *tag) {
+ ExplodedNode* Pred, const GRState* St,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag) {
assert (Builder && "StmtNodeBuilder not present.");
- SaveAndRestore<const void*> OldTag(Builder->Tag);
+ SaveAndRestore<const ProgramPointTag*> OldTag(Builder->Tag);
Builder->Tag = tag;
return Builder->MakeNode(Dst, S, Pred, St, K);
}
@@ -1476,7 +1476,7 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
const Expr* LocationE,
ExplodedNode* Pred,
const GRState* state, SVal location, SVal Val,
- const void *tag) {
+ const ProgramPointTag *tag) {
assert(Builder && "StmtNodeBuilder must be defined.");
@@ -1510,7 +1510,7 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
ExplodedNode* Pred,
const GRState* state, SVal location,
- const void *tag, QualType LoadTy) {
+ const ProgramPointTag *tag, QualType LoadTy) {
assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
if (isa<loc::ObjCPropRef>(location)) {
@@ -1527,7 +1527,8 @@ void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
QualType ValTy = TR->getValueType();
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
- static int loadReferenceTag = 0;
+ static SimpleProgramPointTag
+ loadReferenceTag("ExprEngine : Load Reference");
ExplodedNodeSet Tmp;
evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
@@ -1548,7 +1549,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
ExplodedNode* Pred,
const GRState* state, SVal location,
- const void *tag, QualType LoadTy) {
+ const ProgramPointTag *tag, QualType LoadTy) {
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
@@ -1584,7 +1585,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
ExplodedNode* Pred,
const GRState* state, SVal location,
- const void *tag, bool isLoad) {
+ const ProgramPointTag *tag, bool isLoad) {
// Early checks for performance reason.
if (location.isUnknown()) {
Dst.Add(Pred);
@@ -1603,7 +1604,11 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
// "p = 0" is not noted as "Null pointer value stored to 'p'" but
// instead "int *p" is noted as
// "Variable 'p' initialized to a null pointer value"
- ExplodedNode *N = Builder->generateNode(S, state, Pred, this);
+
+ // FIXME: why is 'tag' not used instead of etag?
+ static SimpleProgramPointTag etag("ExprEngine: Location");
+
+ ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag);
Src.Add(N ? N : Pred);
}
getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
@@ -2653,7 +2658,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
// Record the returned expression in the state. It will be used in
// processCallExit to bind the return value to the call expr.
{
- static int tag = 0;
+ static SimpleProgramPointTag tag("ExprEngine: ReturnStmt");
const GRState *state = Pred->getState();
state = state->set<ReturnExpr>(RetE);
Pred = Builder->generateNode(RetE, state, Pred, &tag);
@@ -3024,7 +3029,13 @@ struct DOTGraphTraits<ExplodedNode*> :
Out << "\\|StateID: " << (void*) state
<< " NodeID: " << (void*) N << "\\|";
state->printDOT(Out, *N->getLocationContext()->getCFG());
- Out << "\\l";
+
+ Out << "\\l";
+
+ if (const ProgramPointTag *tag = Loc.getTag()) {
+ Out << "\\|Tag: " << tag->getTagDescription();
+ Out << "\\l";
+ }
return Out.str();
}
};