From: Ted Kremenek Date: Fri, 12 Aug 2011 23:04:46 +0000 (+0000) Subject: [analyzer] change "tag" in ProgramPoint from "void*" to a ProgramPointTag*. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ca804539d908d3a0e8c72a0df5f1f571d29490bb;p=clang [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 --- diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 07b4dea987..0e6a659e39 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -21,15 +21,18 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Casting.h" +#include "llvm/ADT/StringRef.h" #include #include +#include namespace clang { -class LocationContext; class AnalysisContext; class FunctionDecl; - +class LocationContext; +class ProgramPointTag; + class ProgramPoint { public: enum Kind { BlockEdgeKind, @@ -58,15 +61,17 @@ private: // The LocationContext could be NULL to allow ProgramPoint to be used in // context insensitive analysis. const LocationContext *L; - const void *Tag; + const ProgramPointTag *Tag; + ProgramPoint(); + protected: ProgramPoint(const void* P, Kind k, const LocationContext *l, - const void *tag = 0) + const ProgramPointTag *tag = 0) : Data(P, static_cast(NULL)), K(k), L(l), Tag(tag) {} ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l, - const void *tag = 0) + const ProgramPointTag *tag = 0) : Data(P1, P2), K(k), L(l), Tag(tag) {} protected: @@ -76,7 +81,7 @@ protected: public: Kind getKind() const { return K; } - const void *getTag() const { return Tag; } + const ProgramPointTag *getTag() const { return Tag; } const LocationContext *getLocationContext() const { return L; } @@ -109,7 +114,7 @@ public: class BlockEntrance : public ProgramPoint { public: BlockEntrance(const CFGBlock* B, const LocationContext *L, - const void *tag = 0) + const ProgramPointTag *tag = 0) : ProgramPoint(B, BlockEntranceKind, L, tag) {} const CFGBlock* getBlock() const { @@ -123,7 +128,7 @@ public: /// Create a new BlockEntrance object that is the same as the original /// except for using the specified tag value. - BlockEntrance withTag(const void *tag) { + BlockEntrance withTag(const ProgramPointTag *tag) { return BlockEntrance(getBlock(), getLocationContext(), tag); } @@ -153,7 +158,7 @@ public: class StmtPoint : public ProgramPoint { public: StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, - const void *tag) + const ProgramPointTag *tag) : ProgramPoint(S, p2, k, L, tag) {} const Stmt *getStmt() const { return (const Stmt*) getData1(); } @@ -170,7 +175,7 @@ public: class PreStmt : public StmtPoint { public: - PreStmt(const Stmt *S, const LocationContext *L, const void *tag, + PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, const Stmt *SubStmt = 0) : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} @@ -184,15 +189,16 @@ public: class PostStmt : public StmtPoint { protected: PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L, - const void *tag =0) + const ProgramPointTag *tag =0) : StmtPoint(S, data, k, L, tag) {} public: explicit PostStmt(const Stmt* S, Kind k, - const LocationContext *L, const void *tag = 0) + const LocationContext *L, const ProgramPointTag *tag = 0) : StmtPoint(S, NULL, k, L, tag) {} - explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) + explicit PostStmt(const Stmt* S, const LocationContext *L, + const ProgramPointTag *tag = 0) : StmtPoint(S, NULL, PostStmtKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -225,7 +231,8 @@ public: // PostCondition represents the post program point of a branch condition. class PostCondition : public PostStmt { public: - PostCondition(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostCondition(const Stmt* S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostConditionKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -236,7 +243,7 @@ public: class LocationCheck : public StmtPoint { protected: LocationCheck(const Stmt *S, const LocationContext *L, - ProgramPoint::Kind K, const void *tag) + ProgramPoint::Kind K, const ProgramPointTag *tag) : StmtPoint(S, NULL, K, L, tag) {} static bool classof(const ProgramPoint *location) { @@ -247,7 +254,8 @@ protected: class PreLoad : public LocationCheck { public: - PreLoad(const Stmt *S, const LocationContext *L, const void *tag = 0) + PreLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : LocationCheck(S, L, PreLoadKind, tag) {} static bool classof(const ProgramPoint *location) { @@ -257,7 +265,8 @@ public: class PreStore : public LocationCheck { public: - PreStore(const Stmt *S, const LocationContext *L, const void *tag = 0) + PreStore(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : LocationCheck(S, L, PreStoreKind, tag) {} static bool classof(const ProgramPoint *location) { @@ -267,7 +276,8 @@ public: class PostLoad : public PostStmt { public: - PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostLoad(const Stmt* S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostLoadKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -277,7 +287,8 @@ public: class PostStore : public PostStmt { public: - PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostStore(const Stmt* S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostStoreKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -287,7 +298,8 @@ public: class PostLValue : public PostStmt { public: - PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostLValue(const Stmt* S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostLValueKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -298,7 +310,7 @@ public: class PostPurgeDeadSymbols : public PostStmt { public: PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L, - const void *tag = 0) + const ProgramPointTag *tag = 0) : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -365,6 +377,28 @@ public: } }; +/// ProgramPoints can be "tagged" as representing points specific to a given +/// analysis entity. Tags are abstract annotations, with an associated +/// description and potentially other information. +class ProgramPointTag { +public: + ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} + virtual ~ProgramPointTag(); + virtual StringRef getTagDescription() const = 0; + +protected: + const void *getTagKind() { return TagKind; } + +private: + const void *TagKind; +}; + +class SimpleProgramPointTag : public ProgramPointTag { + std::string desc; +public: + SimpleProgramPointTag(StringRef description); + StringRef getTagDescription() const; +}; } // end namespace clang diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index eb38bd8951..26476454a6 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SA_CORE_CHECKER #define LLVM_CLANG_SA_CORE_CHECKER +#include "clang/Analysis/ProgramPoint.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/Support/Casting.h" @@ -329,6 +330,11 @@ public: } // end eval namespace +class CheckerBase : public ProgramPointTag { +public: + StringRef getTagDescription() const; +}; + template class Checker { + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck> + : public CheckerBase +{ public: static void _register(void *checker, CheckerManager &mgr) { } }; diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index c275c19b40..42e6bd1b18 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -27,6 +27,7 @@ namespace clang { class CallExpr; namespace ento { + class CheckerBase; class ExprEngine; class AnalysisManager; class BugReporter; @@ -55,8 +56,8 @@ class CheckerFn { typedef RET (*Func)(void *, P1, P2, P3, P4); Func Fn; public: - void *Checker; - CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { return Fn(Checker, p1, p2, p3, p4); } @@ -67,8 +68,8 @@ class CheckerFn { typedef RET (*Func)(void *, P1, P2, P3); Func Fn; public: - void *Checker; - CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); } }; @@ -77,8 +78,8 @@ class CheckerFn { typedef RET (*Func)(void *, P1, P2); Func Fn; public: - void *Checker; - CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); } }; @@ -87,8 +88,8 @@ class CheckerFn { typedef RET (*Func)(void *, P1); Func Fn; public: - void *Checker; - CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1) const { return Fn(Checker, p1); } }; @@ -97,8 +98,8 @@ class CheckerFn { typedef RET (*Func)(void *); Func Fn; public: - void *Checker; - CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { } + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()() const { return Fn(Checker); } }; @@ -115,8 +116,8 @@ public: const LangOptions &getLangOptions() const { return LangOpts; } - typedef void *CheckerRef; - typedef void *CheckerTag; + typedef CheckerBase *CheckerRef; + typedef const void *CheckerTag; typedef CheckerFn CheckerDtor; //===----------------------------------------------------------------------===// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index 62887cd2e2..4b3df1262e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -28,7 +28,7 @@ class CheckerContext { ExprEngine &Eng; ExplodedNode *Pred; SaveAndRestore OldSink; - const void *checkerTag; + const ProgramPointTag *checkerTag; SaveAndRestore OldPointKind; SaveOr OldHasGen; const GRState *ST; @@ -39,7 +39,7 @@ public: public: CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder, ExprEngine &eng, ExplodedNode *pred, - const void *tag, ProgramPoint::Kind K, + const ProgramPointTag *tag, ProgramPoint::Kind K, bool *respondsToCB = 0, const Stmt *stmt = 0, const GRState *st = 0) : Dst(dst), B(builder), Eng(eng), Pred(pred), @@ -104,7 +104,7 @@ public: } ExplodedNode *generateNode(const Stmt *stmt, const GRState *state, - bool autoTransition = true, const void *tag = 0) { + bool autoTransition = true, const ProgramPointTag *tag = 0) { assert(state); ExplodedNode *N = generateNodeImpl(stmt, state, false, tag ? tag : checkerTag); @@ -123,7 +123,7 @@ public: } ExplodedNode *generateNode(const GRState *state, bool autoTransition = true, - const void *tag = 0) { + const ProgramPointTag *tag = 0) { assert(statement && "Only transitions with statements currently supported"); ExplodedNode *N = generateNodeImpl(statement, state, false, tag ? tag : checkerTag); @@ -147,7 +147,7 @@ public: Dst.Add(node); } - void addTransition(const GRState *state, const void *tag = 0) { + void addTransition(const GRState *state, const ProgramPointTag *tag = 0) { assert(state); // If the 'state' is not new, we need to check if the cached state 'ST' // is new. @@ -168,7 +168,7 @@ public: private: ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, - bool markAsSink, const void *tag) { + bool markAsSink, const ProgramPointTag *tag) { ExplodedNode *node = B.generateNode(stmt, state, Pred, tag); if (markAsSink && node) node->markAsSink(); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 19daeda6b5..31e862fdd0 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -24,6 +24,8 @@ namespace clang { +class ProgramPointTag; + namespace ento { //===----------------------------------------------------------------------===// @@ -170,7 +172,7 @@ public: bool BuildSinks; bool hasGeneratedNode; ProgramPoint::Kind PointKind; - const void *Tag; + const ProgramPointTag *Tag; typedef llvm::SmallPtrSet DeferredTy; DeferredTy Deferred; @@ -203,7 +205,7 @@ public: ExplodedNode* generateNode(const Stmt *S, const GRState *St, ExplodedNode *Pred, ProgramPoint::Kind K, - const void *tag = 0) { + const ProgramPointTag *tag = 0) { hasGeneratedNode = true; if (PurgingDeadSymbols) @@ -213,7 +215,8 @@ public: } ExplodedNode* generateNode(const Stmt *S, const GRState *St, - ExplodedNode *Pred, const void *tag = 0) { + ExplodedNode *Pred, + const ProgramPointTag *tag = 0) { return generateNode(S, St, Pred, PointKind, tag); } @@ -230,7 +233,7 @@ public: ExplodedNode* generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred, ProgramPoint::Kind K = ProgramPoint::PostStmtKind, - const void *tag = 0); + const ProgramPointTag *tag = 0); /// getStmt - Return the current block-level expression associated with /// this builder. @@ -367,7 +370,7 @@ class SwitchNodeBuilder { public: SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src, - const Expr* condition, CoreEngine* eng) + const Expr* condition, CoreEngine* eng) : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} class iterator { @@ -443,7 +446,7 @@ public: : GenericNodeBuilderImpl(eng, pr, p) {} ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred, - const void *tag, bool asSink) { + const ProgramPointTag *tag, bool asSink) { return generateNodeImpl(state, pred, cast(pp).withTag(tag), asSink); } @@ -455,19 +458,19 @@ class EndOfFunctionNodeBuilder { CoreEngine &Eng; const CFGBlock& B; ExplodedNode* Pred; - void *Tag; + const ProgramPointTag *Tag; public: bool hasGeneratedNode; public: EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e, - void *checkerTag = 0) - : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {} + const ProgramPointTag *tag = 0) + : Eng(*e), B(*b), Pred(N), Tag(tag), hasGeneratedNode(false) {} ~EndOfFunctionNodeBuilder(); - EndOfFunctionNodeBuilder withCheckerTag(void *tag) { + EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) { return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag); } @@ -486,7 +489,7 @@ public: } ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0, - const void *tag = 0); + const ProgramPointTag *tag = 0); void GenerateCallExitNode(const GRState *state); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index ee89f314d9..5649f71b86 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -226,7 +226,7 @@ public: ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S, ExplodedNode* Pred, const GRState* St, ProgramPoint::Kind K = ProgramPoint::PostStmtKind, - const void *tag = 0); + const ProgramPointTag *tag = 0); /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. @@ -430,24 +430,24 @@ public: // same as state->getLValue(Ex). /// Simulate a read of the result of Ex. void evalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred, - const GRState* St, SVal location, const void *tag = 0, + const GRState* St, SVal location, const ProgramPointTag *tag = 0, QualType LoadTy = QualType()); // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. void evalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE, ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, - const void *tag = 0); + const ProgramPointTag *tag = 0); private: void evalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred, - const GRState* St, SVal location, const void *tag, + const GRState* St, SVal location, const ProgramPointTag *tag, QualType LoadTy); // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred, const GRState* St, SVal location, - const void *tag, bool isLoad); + const ProgramPointTag *tag, bool isLoad); bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred); diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 967fc2930f..eb7e2356cd 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(clangAnalysis FormatString.cpp LiveVariables.cpp PrintfFormatString.cpp + ProgramPoint.cpp PseudoConstantAnalysis.cpp ReachableCode.cpp ScanfFormatString.cpp diff --git a/lib/Analysis/ProgramPoint.cpp b/lib/Analysis/ProgramPoint.cpp new file mode 100644 index 0000000000..9b7df2c042 --- /dev/null +++ b/lib/Analysis/ProgramPoint.cpp @@ -0,0 +1,26 @@ +//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- 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 the interface ProgramPoint, which identifies a +// distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/ProgramPoint.h" + +using namespace clang; + +ProgramPointTag::~ProgramPointTag() {} + +SimpleProgramPointTag::SimpleProgramPointTag(StringRef description) + : desc(description) {} + +StringRef SimpleProgramPointTag::getTagDescription() const { + return desc; +} 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 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::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 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(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(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 OldTag(Builder->Tag); + SaveAndRestore 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(location) && "location cannot be a NonLoc."); if (isa(location)) { @@ -1527,7 +1527,8 @@ void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex, QualType ValTy = TR->getValueType(); if (const ReferenceType *RT = ValTy->getAs()) { - 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(RetE); Pred = Builder->generateNode(RetE, state, Pred, &tag); @@ -3024,7 +3029,13 @@ struct DOTGraphTraits : 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(); } };