CheckerManager.cpp revision 30726c6baee1417307236e854f1474fdb3cedb98
1//===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Defines the Static Analyzer Checker Manager. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/StaticAnalyzer/Core/CheckerManager.h" 15#include "clang/StaticAnalyzer/Core/CheckerProvider.h" 16#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 17#include "clang/Analysis/ProgramPoint.h" 18#include "clang/AST/DeclBase.h" 19 20using namespace clang; 21using namespace ento; 22 23//===----------------------------------------------------------------------===// 24// Functions for running checkers for AST traversing.. 25//===----------------------------------------------------------------------===// 26 27void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 28 BugReporter &BR) { 29 assert(D); 30 31 unsigned DeclKind = D->getKind(); 32 CachedDeclCheckers *checkers = 0; 33 CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); 34 if (CCI != CachedDeclCheckersMap.end()) { 35 checkers = &(CCI->second); 36 } else { 37 // Find the checkers that should run for this Decl and cache them. 38 checkers = &CachedDeclCheckersMap[DeclKind]; 39 for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) { 40 DeclCheckerInfo &info = DeclCheckers[i]; 41 if (info.IsForDeclFn(D)) 42 checkers->push_back(info.CheckFn); 43 } 44 } 45 46 assert(checkers); 47 for (CachedDeclCheckers::iterator 48 I = checkers->begin(), E = checkers->end(); I != E; ++I) 49 (*I)(D, mgr, BR); 50} 51 52void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 53 BugReporter &BR) { 54 assert(D && D->hasBody()); 55 56 for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) 57 BodyCheckers[i](D, mgr, BR); 58} 59 60//===----------------------------------------------------------------------===// 61// Functions for running checkers for path-sensitive checking. 62//===----------------------------------------------------------------------===// 63 64template <typename CHECK_CTX> 65static void runPathSensitiveCheckers(CHECK_CTX checkCtx, 66 ExplodedNodeSet &Dst, 67 ExplodedNodeSet &Src) { 68 69 if (checkCtx.Checkers.empty()) { 70 Dst.insert(Src); 71 return; 72 } 73 74 ExplodedNodeSet Tmp; 75 ExplodedNodeSet *PrevSet = &Src; 76 77 for (typename CHECK_CTX::CheckersTy::const_iterator 78 I= checkCtx.Checkers.begin(), E= checkCtx.Checkers.end(); I!=E; ++I) { 79 ExplodedNodeSet *CurrSet = 0; 80 if (I+1 == E) 81 CurrSet = &Dst; 82 else { 83 CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; 84 CurrSet->clear(); 85 } 86 87 for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); 88 NI != NE; ++NI) 89 checkCtx.runChecker(*I, *CurrSet, *NI); 90 91 // Update which NodeSet is the current one. 92 PrevSet = CurrSet; 93 } 94} 95 96namespace { 97 struct CheckStmtContext { 98 typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; 99 bool IsPreVisit; 100 const CheckersTy &Checkers; 101 const Stmt *S; 102 ExprEngine &Eng; 103 104 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 105 const Stmt *s, ExprEngine &eng) 106 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { } 107 108 void runChecker(CheckerManager::CheckStmtFunc checkFn, 109 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 110 // FIXME: Remove respondsToCallback from CheckerContext; 111 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 112 IsPreVisit ? ProgramPoint::PreStmtKind : 113 ProgramPoint::PostStmtKind, 0, S); 114 checkFn(S, C); 115 } 116 }; 117} 118 119/// \brief Run checkers for visiting Stmts. 120void CheckerManager::runCheckersForStmt(bool isPreVisit, 121 ExplodedNodeSet &Dst, 122 ExplodedNodeSet &Src, 123 const Stmt *S, 124 ExprEngine &Eng) { 125 CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit), 126 S, Eng); 127 runPathSensitiveCheckers(C, Dst, Src); 128} 129 130namespace { 131 struct CheckObjCMessageContext { 132 typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; 133 bool IsPreVisit; 134 const CheckersTy &Checkers; 135 const ObjCMessage &Msg; 136 ExprEngine &Eng; 137 138 CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers, 139 const ObjCMessage &msg, ExprEngine &eng) 140 : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { } 141 142 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 143 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 144 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 145 IsPreVisit ? ProgramPoint::PreStmtKind : 146 ProgramPoint::PostStmtKind, 0, 147 Msg.getOriginExpr()); 148 checkFn(Msg, C); 149 } 150 }; 151} 152 153/// \brief Run checkers for visiting obj-c messages. 154void CheckerManager::runCheckersForObjCMessage(bool isPreVisit, 155 ExplodedNodeSet &Dst, 156 ExplodedNodeSet &Src, 157 const ObjCMessage &msg, 158 ExprEngine &Eng) { 159 CheckObjCMessageContext C(isPreVisit, 160 isPreVisit ? PreObjCMessageCheckers 161 : PostObjCMessageCheckers, 162 msg, Eng); 163 runPathSensitiveCheckers(C, Dst, Src); 164} 165 166namespace { 167 struct CheckLocationContext { 168 typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; 169 const CheckersTy &Checkers; 170 SVal Loc; 171 bool IsLoad; 172 const Stmt *S; 173 const GRState *State; 174 ExprEngine &Eng; 175 176 CheckLocationContext(const CheckersTy &checkers, 177 SVal loc, bool isLoad, const Stmt *s, 178 const GRState *state, ExprEngine &eng) 179 : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), 180 State(state), Eng(eng) { } 181 182 void runChecker(CheckerManager::CheckLocationFunc checkFn, 183 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 184 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 185 IsLoad ? ProgramPoint::PreLoadKind : 186 ProgramPoint::PreStoreKind, 0, S, State); 187 checkFn(Loc, IsLoad, C); 188 } 189 }; 190} 191 192/// \brief Run checkers for load/store of a location. 193void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 194 ExplodedNodeSet &Src, 195 SVal location, bool isLoad, 196 const Stmt *S, 197 const GRState *state, 198 ExprEngine &Eng) { 199 CheckLocationContext C(LocationCheckers, location, isLoad, S, state, Eng); 200 runPathSensitiveCheckers(C, Dst, Src); 201} 202 203void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 204 BugReporter &BR, 205 ExprEngine &Eng) { 206 for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i) 207 EndAnalysisCheckers[i](G, BR, Eng); 208} 209 210void CheckerManager::registerCheckersToEngine(ExprEngine &eng) { 211 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) 212 Funcs[i](eng); 213} 214 215//===----------------------------------------------------------------------===// 216// Internal registration functions for AST traversing. 217//===----------------------------------------------------------------------===// 218 219void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 220 HandlesDeclFunc isForDeclFn) { 221 DeclCheckerInfo info = { checkfn, isForDeclFn }; 222 DeclCheckers.push_back(info); 223} 224 225void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 226 BodyCheckers.push_back(checkfn); 227} 228 229//===----------------------------------------------------------------------===// 230// Internal registration functions for path-sensitive checking. 231//===----------------------------------------------------------------------===// 232 233void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 234 HandlesStmtFunc isForStmtFn) { 235 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 236 StmtCheckers.push_back(info); 237} 238void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 239 HandlesStmtFunc isForStmtFn) { 240 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 241 StmtCheckers.push_back(info); 242} 243 244void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 245 PreObjCMessageCheckers.push_back(checkfn); 246} 247void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 248 PostObjCMessageCheckers.push_back(checkfn); 249} 250 251void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 252 LocationCheckers.push_back(checkfn); 253} 254 255void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 256 EndAnalysisCheckers.push_back(checkfn); 257} 258 259//===----------------------------------------------------------------------===// 260// Implementation details. 261//===----------------------------------------------------------------------===// 262 263CheckerManager::CachedStmtCheckers * 264CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 265 assert(S); 266 267 CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit); 268 CachedStmtCheckers *checkers = 0; 269 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key); 270 if (CCI != CachedStmtCheckersMap.end()) { 271 checkers = &(CCI->second); 272 } else { 273 // Find the checkers that should run for this Stmt and cache them. 274 checkers = &CachedStmtCheckersMap[key]; 275 for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) { 276 StmtCheckerInfo &info = StmtCheckers[i]; 277 if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S)) 278 checkers->push_back(info.CheckFn); 279 } 280 } 281 282 assert(checkers); 283 return checkers; 284} 285 286CheckerManager::~CheckerManager() { 287 for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i) 288 CheckerDtors[i](); 289} 290 291// Anchor for the vtable. 292CheckerProvider::~CheckerProvider() { } 293