diff options
author | Ted Kremenek <kremenek@apple.com> | 2008-07-11 18:37:32 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2008-07-11 18:37:32 +0000 |
commit | bdb435ddaafd5069becd543d638112f68825b89d (patch) | |
tree | 30dce306d94ac6df42cb6183d97230db1239bb91 /lib/Analysis/GRExprEngine.cpp | |
parent | f5eeb055ecbadbc25c83df0867cdada2c2559dcf (diff) |
Refactored auditor interface within GRExprEngine and GRCoreEngine to use a "batch auditor" to dispatch to specialized auditors instead of having a separate vector for each audited Expr*. This not only provides a much cleaner implementation, but also allows us to install auditors for any expression.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53464 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/GRExprEngine.cpp')
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 96e7fae7e3..fa8009f3ef 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -13,12 +13,13 @@ // //===----------------------------------------------------------------------===// +#include "clang/Analysis/PathSensitive/BasicStore.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Streams.h" - -#include "clang/Analysis/PathSensitive/BasicStore.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/Support/Compiler.h" #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" @@ -34,6 +35,79 @@ using llvm::APSInt; // Engine construction and deletion. //===----------------------------------------------------------------------===// +namespace { + +class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck { + typedef llvm::ImmutableList<GRSimpleAPICheck*> Checks; + typedef llvm::DenseMap<void*,Checks> MapTy; + + MapTy M; + Checks::Factory F; + +public: + MappedBatchAuditor(llvm::BumpPtrAllocator& Alloc) : F(Alloc) {} + + virtual ~MappedBatchAuditor() { + llvm::DenseSet<GRSimpleAPICheck*> AlreadyVisited; + + for (MapTy::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) + for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E;++I){ + + GRSimpleAPICheck* check = *I; + + if (AlreadyVisited.count(check)) + continue; + + AlreadyVisited.insert(check); + delete check; + } + } + + void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) { + assert (A && "Check cannot be null."); + void* key = reinterpret_cast<void*>((uintptr_t) C); + MapTy::iterator I = M.find(key); + M[key] = F.Concat(A, I == M.end() ? F.GetEmptyList() : I->second); + } + + virtual void EmitWarnings(BugReporter& BR) { + llvm::DenseSet<GRSimpleAPICheck*> AlreadyVisited; + + for (MapTy::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) + for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E;++I){ + + GRSimpleAPICheck* check = *I; + + if (AlreadyVisited.count(check)) + continue; + + check->EmitWarnings(BR); + } + } + + virtual bool Audit(NodeTy* N) { + Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); + void* key = reinterpret_cast<void*>((uintptr_t) S->getStmtClass()); + MapTy::iterator MI = M.find(key); + + if (MI == M.end()) + return false; + + bool isSink = false; + + for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E; ++I) + isSink |= (*I)->Audit(N); + + return isSink; + } +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Engine construction and deletion. +//===----------------------------------------------------------------------===// + static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(0, &II); @@ -58,14 +132,7 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, GRExprEngine::~GRExprEngine() { for (BugTypeSet::iterator I = BugTypes.begin(), E = BugTypes.end(); I!=E; ++I) delete *I; - - for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end(); - I != E; ++I) - delete *I; - - for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end(); - I != E; ++I) - delete *I; + delete [] NSExceptionInstanceRaiseSelectors; } @@ -104,16 +171,9 @@ void GRExprEngine::EmitWarnings(BugReporterData& BRData) { (*I)->EmitWarnings(BR); } - for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end(); - I != E; ++I) { - GRBugReporter BR(BRData, *this); - (*I)->EmitWarnings(BR); - } - - for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end(); - I != E; ++I) { + if (BatchAuditor) { GRBugReporter BR(BRData, *this); - (*I)->EmitWarnings(BR); + BatchAuditor->EmitWarnings(BR); } } @@ -122,12 +182,11 @@ void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { TF->RegisterChecks(*this); } -void GRExprEngine::AddCallCheck(GRSimpleAPICheck* A) { - CallChecks.push_back(A); -} - -void GRExprEngine::AddObjCMessageExprCheck(GRSimpleAPICheck* A) { - MsgExprChecks.push_back(A); +void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) { + if (!BatchAuditor) + BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator())); + + ((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A, C); } const ValueState* GRExprEngine::getInitialState() { @@ -186,26 +245,14 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { CurrentStmt = S; // Set up our simple checks. + if (BatchAuditor) + Builder->setAuditor(BatchAuditor.get()); - // FIXME: This can probably be installed directly in GRCoreEngine, obviating - // the need to do a copy every time we hit a block-level statement. - - if (!MsgExprChecks.empty()) - Builder->setObjCMsgExprAuditors((GRAuditor<ValueState>**) &MsgExprChecks[0], - (GRAuditor<ValueState>**) (&MsgExprChecks[0] + MsgExprChecks.size())); - - - if (!CallChecks.empty()) - Builder->setCallExprAuditors((GRAuditor<ValueState>**) &CallChecks[0], - (GRAuditor<ValueState>**) (&CallChecks[0] + CallChecks.size())); - - // Create the cleaned state. - + // Create the cleaned state. CleanedState = StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, Liveness, DeadSymbols); // Process any special transfer function for dead symbols. - NodeSet Tmp; if (DeadSymbols.empty()) |