CheckerManager.cpp revision c2e0db82139c70c0eac9d5c165b6bf3250af5bed
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 expandGraphWithCheckers(CHECK_CTX checkCtx, 66 ExplodedNodeSet &Dst, 67 ExplodedNodeSet &Src) { 68 69 typename CHECK_CTX::CheckersTy::const_iterator 70 I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); 71 if (I == E) { 72 Dst.insert(Src); 73 return; 74 } 75 76 ExplodedNodeSet Tmp; 77 ExplodedNodeSet *PrevSet = &Src; 78 79 for (; I != E; ++I) { 80 ExplodedNodeSet *CurrSet = 0; 81 if (I+1 == E) 82 CurrSet = &Dst; 83 else { 84 CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; 85 CurrSet->clear(); 86 } 87 88 for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); 89 NI != NE; ++NI) 90 checkCtx.runChecker(*I, *CurrSet, *NI); 91 92 // Update which NodeSet is the current one. 93 PrevSet = CurrSet; 94 } 95} 96 97namespace { 98 struct CheckStmtContext { 99 typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; 100 bool IsPreVisit; 101 const CheckersTy &Checkers; 102 const Stmt *S; 103 ExprEngine &Eng; 104 105 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 106 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 107 108 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 109 const Stmt *s, ExprEngine &eng) 110 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { } 111 112 void runChecker(CheckerManager::CheckStmtFunc checkFn, 113 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 114 // FIXME: Remove respondsToCallback from CheckerContext; 115 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 116 IsPreVisit ? ProgramPoint::PreStmtKind : 117 ProgramPoint::PostStmtKind, 0, S); 118 checkFn(S, C); 119 } 120 }; 121} 122 123/// \brief Run checkers for visiting Stmts. 124void CheckerManager::runCheckersForStmt(bool isPreVisit, 125 ExplodedNodeSet &Dst, 126 ExplodedNodeSet &Src, 127 const Stmt *S, 128 ExprEngine &Eng) { 129 CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit), 130 S, Eng); 131 expandGraphWithCheckers(C, Dst, Src); 132} 133 134namespace { 135 struct CheckObjCMessageContext { 136 typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; 137 bool IsPreVisit; 138 const CheckersTy &Checkers; 139 const ObjCMessage &Msg; 140 ExprEngine &Eng; 141 142 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 143 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 144 145 CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers, 146 const ObjCMessage &msg, ExprEngine &eng) 147 : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { } 148 149 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 150 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 151 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 152 IsPreVisit ? ProgramPoint::PreStmtKind : 153 ProgramPoint::PostStmtKind, 0, 154 Msg.getOriginExpr()); 155 checkFn(Msg, C); 156 } 157 }; 158} 159 160/// \brief Run checkers for visiting obj-c messages. 161void CheckerManager::runCheckersForObjCMessage(bool isPreVisit, 162 ExplodedNodeSet &Dst, 163 ExplodedNodeSet &Src, 164 const ObjCMessage &msg, 165 ExprEngine &Eng) { 166 CheckObjCMessageContext C(isPreVisit, 167 isPreVisit ? PreObjCMessageCheckers 168 : PostObjCMessageCheckers, 169 msg, Eng); 170 expandGraphWithCheckers(C, Dst, Src); 171} 172 173namespace { 174 struct CheckLocationContext { 175 typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; 176 const CheckersTy &Checkers; 177 SVal Loc; 178 bool IsLoad; 179 const Stmt *S; 180 const GRState *State; 181 ExprEngine &Eng; 182 183 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 184 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 185 186 CheckLocationContext(const CheckersTy &checkers, 187 SVal loc, bool isLoad, const Stmt *s, 188 const GRState *state, ExprEngine &eng) 189 : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), 190 State(state), Eng(eng) { } 191 192 void runChecker(CheckerManager::CheckLocationFunc checkFn, 193 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 194 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 195 IsLoad ? ProgramPoint::PreLoadKind : 196 ProgramPoint::PreStoreKind, 0, S, State); 197 checkFn(Loc, IsLoad, C); 198 } 199 }; 200} 201 202/// \brief Run checkers for load/store of a location. 203void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 204 ExplodedNodeSet &Src, 205 SVal location, bool isLoad, 206 const Stmt *S, 207 const GRState *state, 208 ExprEngine &Eng) { 209 CheckLocationContext C(LocationCheckers, location, isLoad, S, state, Eng); 210 expandGraphWithCheckers(C, Dst, Src); 211} 212 213void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 214 BugReporter &BR, 215 ExprEngine &Eng) { 216 for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i) 217 EndAnalysisCheckers[i](G, BR, Eng); 218} 219 220/// \brief Run checkers for evaluating a call. 221/// Only one checker will evaluate the call. 222void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, 223 const ExplodedNodeSet &Src, 224 const CallExpr *CE, 225 ExprEngine &Eng, 226 GraphExpander *defaultEval) { 227 if (EvalCallCheckers.empty() && defaultEval == 0) { 228 Dst.insert(Src); 229 return; 230 } 231 232 for (ExplodedNodeSet::iterator 233 NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { 234 235 ExplodedNode *Pred = *NI; 236 bool anyEvaluated = false; 237 for (std::vector<EvalCallFunc>::iterator 238 EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); 239 EI != EE; ++EI) { 240 ExplodedNodeSet checkDst; 241 CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker, 242 ProgramPoint::PostStmtKind, 0, CE); 243 bool evaluated = (*EI)(CE, C); 244 assert(!(evaluated && anyEvaluated) 245 && "There are more than one checkers evaluating the call"); 246 if (evaluated) { 247 anyEvaluated = true; 248 Dst.insert(checkDst); 249#ifdef NDEBUG 250 break; // on release don't check that no other checker also evals. 251#endif 252 } 253 } 254 255 if (!anyEvaluated) { 256 if (defaultEval) 257 defaultEval->expandGraph(Dst, Pred); 258 else 259 Dst.insert(Pred); 260 } 261 } 262} 263 264void CheckerManager::registerCheckersToEngine(ExprEngine &eng) { 265 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) 266 Funcs[i](eng); 267} 268 269//===----------------------------------------------------------------------===// 270// Internal registration functions for AST traversing. 271//===----------------------------------------------------------------------===// 272 273void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 274 HandlesDeclFunc isForDeclFn) { 275 DeclCheckerInfo info = { checkfn, isForDeclFn }; 276 DeclCheckers.push_back(info); 277} 278 279void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 280 BodyCheckers.push_back(checkfn); 281} 282 283//===----------------------------------------------------------------------===// 284// Internal registration functions for path-sensitive checking. 285//===----------------------------------------------------------------------===// 286 287void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 288 HandlesStmtFunc isForStmtFn) { 289 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 290 StmtCheckers.push_back(info); 291} 292void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 293 HandlesStmtFunc isForStmtFn) { 294 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 295 StmtCheckers.push_back(info); 296} 297 298void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 299 PreObjCMessageCheckers.push_back(checkfn); 300} 301void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 302 PostObjCMessageCheckers.push_back(checkfn); 303} 304 305void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 306 LocationCheckers.push_back(checkfn); 307} 308 309void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 310 EndAnalysisCheckers.push_back(checkfn); 311} 312 313void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { 314 EvalCallCheckers.push_back(checkfn); 315} 316 317//===----------------------------------------------------------------------===// 318// Implementation details. 319//===----------------------------------------------------------------------===// 320 321CheckerManager::CachedStmtCheckers * 322CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 323 assert(S); 324 325 CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit); 326 CachedStmtCheckers *checkers = 0; 327 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key); 328 if (CCI != CachedStmtCheckersMap.end()) { 329 checkers = &(CCI->second); 330 } else { 331 // Find the checkers that should run for this Stmt and cache them. 332 checkers = &CachedStmtCheckersMap[key]; 333 for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) { 334 StmtCheckerInfo &info = StmtCheckers[i]; 335 if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S)) 336 checkers->push_back(info.CheckFn); 337 } 338 } 339 340 assert(checkers); 341 return checkers; 342} 343 344CheckerManager::~CheckerManager() { 345 for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i) 346 CheckerDtors[i](); 347} 348 349// Anchor for the vtable. 350CheckerProvider::~CheckerProvider() { } 351 352// Anchor for the vtable. 353GraphExpander::~GraphExpander() { } 354