CheckerManager.cpp revision 57c033621dacd8720ac9ff65a09025f14f70e22f
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 5a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// This file is distributed under the University of Illinois Open Source 6a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// License. See LICENSE.TXT for details. 7a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// 8a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch//===----------------------------------------------------------------------===// 9a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// 10a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// Defines the Static Analyzer Checker Manager. 11a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// 12a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch//===----------------------------------------------------------------------===// 13a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 14a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "clang/StaticAnalyzer/Core/CheckerManager.h" 15a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "clang/StaticAnalyzer/Core/Checker.h" 16a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 17a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 18a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "clang/Analysis/ProgramPoint.h" 19a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "clang/AST/DeclBase.h" 20a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 21a3f7b4e666c476898878fa745f637129375cd889Ben Murdochusing namespace clang; 22a3f7b4e666c476898878fa745f637129375cd889Ben Murdochusing namespace ento; 23a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 24a3f7b4e666c476898878fa745f637129375cd889Ben Murdochbool CheckerManager::hasPathSensitiveCheckers() const { 25a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return !StmtCheckers.empty() || 26a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !PreObjCMessageCheckers.empty() || 27a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !PostObjCMessageCheckers.empty() || 28a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !PreCallCheckers.empty() || 29a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !PostCallCheckers.empty() || 30a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !LocationCheckers.empty() || 31a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !BindCheckers.empty() || 32a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !EndAnalysisCheckers.empty() || 33a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !EndPathCheckers.empty() || 34a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !BranchConditionCheckers.empty() || 35a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !LiveSymbolsCheckers.empty() || 36a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !DeadSymbolsCheckers.empty() || 37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !RegionChangesCheckers.empty() || 38a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !EvalAssumeCheckers.empty() || 39a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !EvalCallCheckers.empty() || 40a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch !InlineCallCheckers.empty(); 41a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 42a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 43a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid CheckerManager::finishedCheckerRegistration() { 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#ifndef NDEBUG 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Make sure that for every event that has listeners, there is at least 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // one dispatcher registered for it. 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (llvm::DenseMap<EventTag, EventInfo>::iterator 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci I = Events.begin(), E = Events.end(); I != E; ++I) 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert(I->second.HasDispatcher && "No dispatcher registered for an event"); 50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#endif 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 52a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 53a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch//===----------------------------------------------------------------------===// 54a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// Functions for running checkers for AST traversing.. 55a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch//===----------------------------------------------------------------------===// 56a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 57a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 58a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch BugReporter &BR) { 59a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch assert(D); 60a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 61a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch unsigned DeclKind = D->getKind(); 62a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch CachedDeclCheckers *checkers = 0; 63a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); 64a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (CCI != CachedDeclCheckersMap.end()) { 65a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch checkers = &(CCI->second); 66a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } else { 67a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // Find the checkers that should run for this Decl and cache them. 68a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch checkers = &CachedDeclCheckersMap[DeclKind]; 69a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) { 70a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch DeclCheckerInfo &info = DeclCheckers[i]; 71a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (info.IsForDeclFn(D)) 72a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch checkers->push_back(info.CheckFn); 73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 74 } 75 76 assert(checkers); 77 for (CachedDeclCheckers::iterator 78 I = checkers->begin(), E = checkers->end(); I != E; ++I) 79 (*I)(D, mgr, BR); 80} 81 82void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 83 BugReporter &BR) { 84 assert(D && D->hasBody()); 85 86 for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) 87 BodyCheckers[i](D, mgr, BR); 88} 89 90//===----------------------------------------------------------------------===// 91// Functions for running checkers for path-sensitive checking. 92//===----------------------------------------------------------------------===// 93 94template <typename CHECK_CTX> 95static void expandGraphWithCheckers(CHECK_CTX checkCtx, 96 ExplodedNodeSet &Dst, 97 const ExplodedNodeSet &Src) { 98 const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); 99 if (Src.empty()) 100 return; 101 102 typename CHECK_CTX::CheckersTy::const_iterator 103 I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); 104 if (I == E) { 105 Dst.insert(Src); 106 return; 107 } 108 109 ExplodedNodeSet Tmp1, Tmp2; 110 const ExplodedNodeSet *PrevSet = &Src; 111 112 for (; I != E; ++I) { 113 ExplodedNodeSet *CurrSet = 0; 114 if (I+1 == E) 115 CurrSet = &Dst; 116 else { 117 CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; 118 CurrSet->clear(); 119 } 120 121 NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); 122 for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); 123 NI != NE; ++NI) { 124 checkCtx.runChecker(*I, B, *NI); 125 } 126 127 // If all the produced transitions are sinks, stop. 128 if (CurrSet->empty()) 129 return; 130 131 // Update which NodeSet is the current one. 132 PrevSet = CurrSet; 133 } 134} 135 136namespace { 137 struct CheckStmtContext { 138 typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; 139 bool IsPreVisit; 140 const CheckersTy &Checkers; 141 const Stmt *S; 142 ExprEngine &Eng; 143 bool WasInlined; 144 145 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 146 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 147 148 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 149 const Stmt *s, ExprEngine &eng, bool wasInlined = false) 150 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), 151 WasInlined(wasInlined) {} 152 153 void runChecker(CheckerManager::CheckStmtFunc checkFn, 154 NodeBuilder &Bldr, ExplodedNode *Pred) { 155 // FIXME: Remove respondsToCallback from CheckerContext; 156 ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : 157 ProgramPoint::PostStmtKind; 158 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 159 Pred->getLocationContext(), checkFn.Checker); 160 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 161 checkFn(S, C); 162 } 163 }; 164} 165 166/// \brief Run checkers for visiting Stmts. 167void CheckerManager::runCheckersForStmt(bool isPreVisit, 168 ExplodedNodeSet &Dst, 169 const ExplodedNodeSet &Src, 170 const Stmt *S, 171 ExprEngine &Eng, 172 bool WasInlined) { 173 CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit), 174 S, Eng, WasInlined); 175 expandGraphWithCheckers(C, Dst, Src); 176} 177 178namespace { 179 struct CheckObjCMessageContext { 180 typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; 181 bool IsPreVisit, WasInlined; 182 const CheckersTy &Checkers; 183 const ObjCMethodCall &Msg; 184 ExprEngine &Eng; 185 186 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 187 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 188 189 CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers, 190 const ObjCMethodCall &msg, ExprEngine &eng, 191 bool wasInlined) 192 : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), 193 Msg(msg), Eng(eng) { } 194 195 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 196 NodeBuilder &Bldr, ExplodedNode *Pred) { 197 const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); 198 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 199 200 checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); 201 } 202 }; 203} 204 205/// \brief Run checkers for visiting obj-c messages. 206void CheckerManager::runCheckersForObjCMessage(bool isPreVisit, 207 ExplodedNodeSet &Dst, 208 const ExplodedNodeSet &Src, 209 const ObjCMethodCall &msg, 210 ExprEngine &Eng, 211 bool WasInlined) { 212 CheckObjCMessageContext C(isPreVisit, 213 isPreVisit ? PreObjCMessageCheckers 214 : PostObjCMessageCheckers, 215 msg, Eng, WasInlined); 216 expandGraphWithCheckers(C, Dst, Src); 217} 218 219namespace { 220 // FIXME: This has all the same signatures as CheckObjCMessageContext. 221 // Is there a way we can merge the two? 222 struct CheckCallContext { 223 typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy; 224 bool IsPreVisit, WasInlined; 225 const CheckersTy &Checkers; 226 const CallEvent &Call; 227 ExprEngine &Eng; 228 229 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 230 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 231 232 CheckCallContext(bool isPreVisit, const CheckersTy &checkers, 233 const CallEvent &call, ExprEngine &eng, 234 bool wasInlined) 235 : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), 236 Call(call), Eng(eng) { } 237 238 void runChecker(CheckerManager::CheckCallFunc checkFn, 239 NodeBuilder &Bldr, ExplodedNode *Pred) { 240 const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); 241 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 242 243 checkFn(*Call.cloneWithState(Pred->getState()), C); 244 } 245 }; 246} 247 248/// \brief Run checkers for visiting an abstract call event. 249void CheckerManager::runCheckersForCallEvent(bool isPreVisit, 250 ExplodedNodeSet &Dst, 251 const ExplodedNodeSet &Src, 252 const CallEvent &Call, 253 ExprEngine &Eng, 254 bool WasInlined) { 255 CheckCallContext C(isPreVisit, 256 isPreVisit ? PreCallCheckers 257 : PostCallCheckers, 258 Call, Eng, WasInlined); 259 expandGraphWithCheckers(C, Dst, Src); 260} 261 262namespace { 263 struct CheckLocationContext { 264 typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; 265 const CheckersTy &Checkers; 266 SVal Loc; 267 bool IsLoad; 268 const Stmt *NodeEx; /* Will become a CFGStmt */ 269 const Stmt *BoundEx; 270 ExprEngine &Eng; 271 272 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 273 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 274 275 CheckLocationContext(const CheckersTy &checkers, 276 SVal loc, bool isLoad, const Stmt *NodeEx, 277 const Stmt *BoundEx, 278 ExprEngine &eng) 279 : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), 280 BoundEx(BoundEx), Eng(eng) {} 281 282 void runChecker(CheckerManager::CheckLocationFunc checkFn, 283 NodeBuilder &Bldr, ExplodedNode *Pred) { 284 ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : 285 ProgramPoint::PreStoreKind; 286 const ProgramPoint &L = 287 ProgramPoint::getProgramPoint(NodeEx, K, 288 Pred->getLocationContext(), 289 checkFn.Checker); 290 CheckerContext C(Bldr, Eng, Pred, L); 291 checkFn(Loc, IsLoad, BoundEx, C); 292 } 293 }; 294} 295 296/// \brief Run checkers for load/store of a location. 297 298void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 299 const ExplodedNodeSet &Src, 300 SVal location, bool isLoad, 301 const Stmt *NodeEx, 302 const Stmt *BoundEx, 303 ExprEngine &Eng) { 304 CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, 305 BoundEx, Eng); 306 expandGraphWithCheckers(C, Dst, Src); 307} 308 309namespace { 310 struct CheckBindContext { 311 typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy; 312 const CheckersTy &Checkers; 313 SVal Loc; 314 SVal Val; 315 const Stmt *S; 316 ExprEngine &Eng; 317 ProgramPoint::Kind PointKind; 318 319 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 320 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 321 322 CheckBindContext(const CheckersTy &checkers, 323 SVal loc, SVal val, const Stmt *s, ExprEngine &eng, 324 ProgramPoint::Kind PK) 325 : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {} 326 327 void runChecker(CheckerManager::CheckBindFunc checkFn, 328 NodeBuilder &Bldr, ExplodedNode *Pred) { 329 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind, 330 Pred->getLocationContext(), checkFn.Checker); 331 CheckerContext C(Bldr, Eng, Pred, L); 332 333 checkFn(Loc, Val, S, C); 334 } 335 }; 336} 337 338/// \brief Run checkers for binding of a value to a location. 339void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, 340 const ExplodedNodeSet &Src, 341 SVal location, SVal val, 342 const Stmt *S, ExprEngine &Eng, 343 ProgramPoint::Kind PointKind) { 344 CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind); 345 expandGraphWithCheckers(C, Dst, Src); 346} 347 348void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 349 BugReporter &BR, 350 ExprEngine &Eng) { 351 for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i) 352 EndAnalysisCheckers[i](G, BR, Eng); 353} 354 355/// \brief Run checkers for end of path. 356// Note, We do not chain the checker output (like in expandGraphWithCheckers) 357// for this callback since end of path nodes are expected to be final. 358void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC, 359 ExplodedNodeSet &Dst, 360 ExprEngine &Eng) { 361 ExplodedNode *Pred = BC.Pred; 362 363 // We define the builder outside of the loop bacause if at least one checkers 364 // creates a sucsessor for Pred, we do not need to generate an 365 // autotransition for it. 366 NodeBuilder Bldr(Pred, Dst, BC); 367 for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) { 368 CheckEndPathFunc checkFn = EndPathCheckers[i]; 369 370 const ProgramPoint &L = BlockEntrance(BC.Block, 371 Pred->getLocationContext(), 372 checkFn.Checker); 373 CheckerContext C(Bldr, Eng, Pred, L); 374 checkFn(C); 375 } 376} 377 378namespace { 379 struct CheckBranchConditionContext { 380 typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy; 381 const CheckersTy &Checkers; 382 const Stmt *Condition; 383 ExprEngine &Eng; 384 385 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 386 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 387 388 CheckBranchConditionContext(const CheckersTy &checkers, 389 const Stmt *Cond, ExprEngine &eng) 390 : Checkers(checkers), Condition(Cond), Eng(eng) {} 391 392 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, 393 NodeBuilder &Bldr, ExplodedNode *Pred) { 394 ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), 395 checkFn.Checker); 396 CheckerContext C(Bldr, Eng, Pred, L); 397 checkFn(Condition, C); 398 } 399 }; 400} 401 402/// \brief Run checkers for branch condition. 403void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, 404 ExplodedNodeSet &Dst, 405 ExplodedNode *Pred, 406 ExprEngine &Eng) { 407 ExplodedNodeSet Src; 408 Src.insert(Pred); 409 CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); 410 expandGraphWithCheckers(C, Dst, Src); 411} 412 413/// \brief Run checkers for live symbols. 414void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, 415 SymbolReaper &SymReaper) { 416 for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i) 417 LiveSymbolsCheckers[i](state, SymReaper); 418} 419 420namespace { 421 struct CheckDeadSymbolsContext { 422 typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy; 423 const CheckersTy &Checkers; 424 SymbolReaper &SR; 425 const Stmt *S; 426 ExprEngine &Eng; 427 ProgramPoint::Kind ProgarmPointKind; 428 429 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 430 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 431 432 CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, 433 const Stmt *s, ExprEngine &eng, 434 ProgramPoint::Kind K) 435 : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) { } 436 437 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, 438 NodeBuilder &Bldr, ExplodedNode *Pred) { 439 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, 440 Pred->getLocationContext(), checkFn.Checker); 441 CheckerContext C(Bldr, Eng, Pred, L); 442 443 // Note, do not pass the statement to the checkers without letting them 444 // differentiate if we ran remove dead bindings before or after the 445 // statement. 446 checkFn(SR, C); 447 } 448 }; 449} 450 451/// \brief Run checkers for dead symbols. 452void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, 453 const ExplodedNodeSet &Src, 454 SymbolReaper &SymReaper, 455 const Stmt *S, 456 ExprEngine &Eng, 457 ProgramPoint::Kind K) { 458 CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); 459 expandGraphWithCheckers(C, Dst, Src); 460} 461 462/// \brief True if at least one checker wants to check region changes. 463bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) { 464 for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) 465 if (RegionChangesCheckers[i].WantUpdateFn(state)) 466 return true; 467 468 return false; 469} 470 471/// \brief Run checkers for region changes. 472ProgramStateRef 473CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, 474 const StoreManager::InvalidatedSymbols *invalidated, 475 ArrayRef<const MemRegion *> ExplicitRegions, 476 ArrayRef<const MemRegion *> Regions, 477 const CallEvent *Call) { 478 for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { 479 // If any checker declares the state infeasible (or if it starts that way), 480 // bail out. 481 if (!state) 482 return NULL; 483 state = RegionChangesCheckers[i].CheckFn(state, invalidated, 484 ExplicitRegions, Regions, Call); 485 } 486 return state; 487} 488 489/// \brief Run checkers for handling assumptions on symbolic values. 490ProgramStateRef 491CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, 492 SVal Cond, bool Assumption) { 493 for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { 494 // If any checker declares the state infeasible (or if it starts that way), 495 // bail out. 496 if (!state) 497 return NULL; 498 state = EvalAssumeCheckers[i](state, Cond, Assumption); 499 } 500 return state; 501} 502 503/// \brief Run checkers for evaluating a call. 504/// Only one checker will evaluate the call. 505void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, 506 const ExplodedNodeSet &Src, 507 const SimpleCall &Call, 508 ExprEngine &Eng) { 509 const CallExpr *CE = Call.getOriginExpr(); 510 for (ExplodedNodeSet::iterator 511 NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { 512 513 ExplodedNode *Pred = *NI; 514 bool anyEvaluated = false; 515 516 // First, check if any of the InlineCall callbacks can evaluate the call. 517 assert(InlineCallCheckers.size() <= 1 && 518 "InlineCall is a special hacky callback to allow intrusive" 519 "evaluation of the call (which simulates inlining). It is " 520 "currently only used by OSAtomicChecker and should go away " 521 "at some point."); 522 for (std::vector<InlineCallFunc>::iterator 523 EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end(); 524 EI != EE; ++EI) { 525 ExplodedNodeSet checkDst; 526 bool evaluated = (*EI)(CE, Eng, Pred, checkDst); 527 assert(!(evaluated && anyEvaluated) 528 && "There are more than one checkers evaluating the call"); 529 if (evaluated) { 530 anyEvaluated = true; 531 Dst.insert(checkDst); 532#ifdef NDEBUG 533 break; // on release don't check that no other checker also evals. 534#endif 535 } 536 } 537 538#ifdef NDEBUG // on release don't check that no other checker also evals. 539 if (anyEvaluated) { 540 break; 541 } 542#endif 543 544 ExplodedNodeSet checkDst; 545 NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); 546 // Next, check if any of the EvalCall callbacks can evaluate the call. 547 for (std::vector<EvalCallFunc>::iterator 548 EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); 549 EI != EE; ++EI) { 550 ProgramPoint::Kind K = ProgramPoint::PostStmtKind; 551 const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, 552 Pred->getLocationContext(), EI->Checker); 553 bool evaluated = false; 554 { // CheckerContext generates transitions(populates checkDest) on 555 // destruction, so introduce the scope to make sure it gets properly 556 // populated. 557 CheckerContext C(B, Eng, Pred, L); 558 evaluated = (*EI)(CE, C); 559 } 560 assert(!(evaluated && anyEvaluated) 561 && "There are more than one checkers evaluating the call"); 562 if (evaluated) { 563 anyEvaluated = true; 564 Dst.insert(checkDst); 565#ifdef NDEBUG 566 break; // on release don't check that no other checker also evals. 567#endif 568 } 569 } 570 571 // If none of the checkers evaluated the call, ask ExprEngine to handle it. 572 if (!anyEvaluated) { 573 NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); 574 Eng.defaultEvalCall(B, Pred, Call); 575 } 576 } 577} 578 579/// \brief Run checkers for the entire Translation Unit. 580void CheckerManager::runCheckersOnEndOfTranslationUnit( 581 const TranslationUnitDecl *TU, 582 AnalysisManager &mgr, 583 BugReporter &BR) { 584 for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i) 585 EndOfTranslationUnitCheckers[i](TU, mgr, BR); 586} 587 588void CheckerManager::runCheckersForPrintState(raw_ostream &Out, 589 ProgramStateRef State, 590 const char *NL, const char *Sep) { 591 for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator 592 I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I) 593 I->second->printState(Out, State, NL, Sep); 594} 595 596//===----------------------------------------------------------------------===// 597// Internal registration functions for AST traversing. 598//===----------------------------------------------------------------------===// 599 600void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 601 HandlesDeclFunc isForDeclFn) { 602 DeclCheckerInfo info = { checkfn, isForDeclFn }; 603 DeclCheckers.push_back(info); 604} 605 606void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 607 BodyCheckers.push_back(checkfn); 608} 609 610//===----------------------------------------------------------------------===// 611// Internal registration functions for path-sensitive checking. 612//===----------------------------------------------------------------------===// 613 614void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 615 HandlesStmtFunc isForStmtFn) { 616 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 617 StmtCheckers.push_back(info); 618} 619void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 620 HandlesStmtFunc isForStmtFn) { 621 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 622 StmtCheckers.push_back(info); 623} 624 625void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 626 PreObjCMessageCheckers.push_back(checkfn); 627} 628void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 629 PostObjCMessageCheckers.push_back(checkfn); 630} 631 632void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { 633 PreCallCheckers.push_back(checkfn); 634} 635void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { 636 PostCallCheckers.push_back(checkfn); 637} 638 639void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 640 LocationCheckers.push_back(checkfn); 641} 642 643void CheckerManager::_registerForBind(CheckBindFunc checkfn) { 644 BindCheckers.push_back(checkfn); 645} 646 647void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 648 EndAnalysisCheckers.push_back(checkfn); 649} 650 651void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) { 652 EndPathCheckers.push_back(checkfn); 653} 654 655void CheckerManager::_registerForBranchCondition( 656 CheckBranchConditionFunc checkfn) { 657 BranchConditionCheckers.push_back(checkfn); 658} 659 660void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { 661 LiveSymbolsCheckers.push_back(checkfn); 662} 663 664void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { 665 DeadSymbolsCheckers.push_back(checkfn); 666} 667 668void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn, 669 WantsRegionChangeUpdateFunc wantUpdateFn) { 670 RegionChangesCheckerInfo info = {checkfn, wantUpdateFn}; 671 RegionChangesCheckers.push_back(info); 672} 673 674void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { 675 EvalAssumeCheckers.push_back(checkfn); 676} 677 678void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { 679 EvalCallCheckers.push_back(checkfn); 680} 681 682void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) { 683 InlineCallCheckers.push_back(checkfn); 684} 685 686void CheckerManager::_registerForEndOfTranslationUnit( 687 CheckEndOfTranslationUnit checkfn) { 688 EndOfTranslationUnitCheckers.push_back(checkfn); 689} 690 691//===----------------------------------------------------------------------===// 692// Implementation details. 693//===----------------------------------------------------------------------===// 694 695CheckerManager::CachedStmtCheckers * 696CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 697 assert(S); 698 699 CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit); 700 CachedStmtCheckers *checkers = 0; 701 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key); 702 if (CCI != CachedStmtCheckersMap.end()) { 703 checkers = &(CCI->second); 704 } else { 705 // Find the checkers that should run for this Stmt and cache them. 706 checkers = &CachedStmtCheckersMap[key]; 707 for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) { 708 StmtCheckerInfo &info = StmtCheckers[i]; 709 if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S)) 710 checkers->push_back(info.CheckFn); 711 } 712 } 713 714 assert(checkers); 715 return checkers; 716} 717 718CheckerManager::~CheckerManager() { 719 for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i) 720 CheckerDtors[i](); 721} 722