From 49513ccaec77e64329a3388b3a3715fed828192b Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Wed, 22 Jul 2009 21:43:51 +0000 Subject: [PATCH] Add support for registering 'Checker' objects with GRExprEngine. Add a 'previsit' stage (that dispatches to registered Checkers) when evaluating the effects of CallExprs. llvm-svn: 76794 --- .../Analysis/PathSensitive/GRExprEngine.h | 11 +++- clang/lib/Analysis/GRExprEngine.cpp | 53 +++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h index 0b3307c31559..534b595c0d35 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -29,6 +29,7 @@ namespace clang { class PathDiagnosticClient; class Diagnostic; class ObjCForCollectionStmt; + class Checker; class GRExprEngine { public: @@ -88,6 +89,7 @@ protected: Selector RaiseSel; llvm::OwningPtr BatchAuditor; + std::vector Checkers; /// PurgeDead - Remove dead bindings before processing a statement. bool PurgeDead; @@ -261,6 +263,10 @@ public: void RegisterInternalChecks(); + void registerCheck(Checker *check) { + Checkers.push_back(check); + } + bool isRetStackAddr(const NodeTy* N) const { return N->isSink() && RetsStackAddr.count(const_cast(N)) != 0; } @@ -491,7 +497,10 @@ public: ProgramPoint::Kind K = ProgramPoint::PostStmtKind, const void *tag = 0); protected: - + /// CheckerVisit - Dispatcher for performing checker-specific logic + /// at specific statements. + void CheckerVisit(Stmt *S, NodeSet &Dst, NodeSet &Src, bool isPrevisit); + /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst); diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index 01cc0330634b..24e4cfaaa1d9 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -15,6 +15,7 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" +#include "clang/Analysis/PathSensitive/Checker.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -36,7 +37,7 @@ using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// -// Engine construction and deletion. +// Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// namespace { @@ -102,6 +103,40 @@ public: } // end anonymous namespace +//===----------------------------------------------------------------------===// +// Checker worklist routines. +//===----------------------------------------------------------------------===// + +void GRExprEngine::CheckerVisit(Stmt *S, NodeSet &Dst, NodeSet &Src, + bool isPrevisit) { + + if (Checkers.empty()) { + Dst = Src; + return; + } + + NodeSet Tmp; + NodeSet *PrevSet = &Src; + + for (std::vector::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + + NodeSet *CurrSet = (I+1 == E) ? &Dst : (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + Checker *checker = *I; + + for (NodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} + //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -135,6 +170,9 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, GRExprEngine::~GRExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; + for (std::vector::iterator I=Checkers.begin(), E=Checkers.end(); + I!=E; ++I) + delete *I; } //===----------------------------------------------------------------------===// @@ -1436,11 +1474,16 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred, // If we reach here we have processed all of the arguments. Evaluate // the callee expression. - - NodeSet DstTmp; + NodeSet DstTmp; Expr* Callee = CE->getCallee()->IgnoreParens(); - - Visit(Callee, Pred, DstTmp); + + { // Enter new scope to make the lifetime of 'DstTmp2' bounded. + NodeSet DstTmp2; + Visit(Callee, Pred, DstTmp2); + + // Perform the previsit of the CallExpr, storing the results in DstTmp. + CheckerVisit(CE, DstTmp, DstTmp2, true); + } // Finally, evaluate the function call. for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { -- 2.34.1