1 //===- CheckerManager.cpp - Static Analyzer Checker Manager ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Defines the Static Analyzer Checker Manager. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 14 #include "clang/AST/DeclBase.h" 15 #include "clang/AST/Stmt.h" 16 #include "clang/Analysis/ProgramPoint.h" 17 #include "clang/Basic/LLVM.h" 18 #include "clang/Driver/DriverDiagnostic.h" 19 #include "clang/StaticAnalyzer/Core/Checker.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 25 #include "llvm/ADT/SmallVector.h" 26 #include "llvm/Support/Casting.h" 27 #include "llvm/Support/ErrorHandling.h" 28 #include <cassert> 29 #include <vector> 30 31 using namespace clang; 32 using namespace ento; 33 34 bool CheckerManager::hasPathSensitiveCheckers() const { 35 return !StmtCheckers.empty() || 36 !PreObjCMessageCheckers.empty() || 37 !PostObjCMessageCheckers.empty() || 38 !PreCallCheckers.empty() || 39 !PostCallCheckers.empty() || 40 !LocationCheckers.empty() || 41 !BindCheckers.empty() || 42 !EndAnalysisCheckers.empty() || 43 !EndFunctionCheckers.empty() || 44 !BranchConditionCheckers.empty() || 45 !LiveSymbolsCheckers.empty() || 46 !DeadSymbolsCheckers.empty() || 47 !RegionChangesCheckers.empty() || 48 !EvalAssumeCheckers.empty() || 49 !EvalCallCheckers.empty(); 50 } 51 52 void CheckerManager::finishedCheckerRegistration() { 53 #ifndef NDEBUG 54 // Make sure that for every event that has listeners, there is at least 55 // one dispatcher registered for it. 56 for (const auto &Event : Events) 57 assert(Event.second.HasDispatcher && 58 "No dispatcher registered for an event"); 59 #endif 60 } 61 62 void CheckerManager::reportInvalidCheckerOptionValue( 63 const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) { 64 65 Context.getDiagnostics() 66 .Report(diag::err_analyzer_checker_option_invalid_input) 67 << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() 68 << ExpectedValueDesc; 69 } 70 71 //===----------------------------------------------------------------------===// 72 // Functions for running checkers for AST traversing.. 73 //===----------------------------------------------------------------------===// 74 75 void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 76 BugReporter &BR) { 77 assert(D); 78 79 unsigned DeclKind = D->getKind(); 80 CachedDeclCheckers *checkers = nullptr; 81 CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); 82 if (CCI != CachedDeclCheckersMap.end()) { 83 checkers = &(CCI->second); 84 } else { 85 // Find the checkers that should run for this Decl and cache them. 86 checkers = &CachedDeclCheckersMap[DeclKind]; 87 for (const auto &info : DeclCheckers) 88 if (info.IsForDeclFn(D)) 89 checkers->push_back(info.CheckFn); 90 } 91 92 assert(checkers); 93 for (const auto checker : *checkers) 94 checker(D, mgr, BR); 95 } 96 97 void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 98 BugReporter &BR) { 99 assert(D && D->hasBody()); 100 101 for (const auto BodyChecker : BodyCheckers) 102 BodyChecker(D, mgr, BR); 103 } 104 105 //===----------------------------------------------------------------------===// 106 // Functions for running checkers for path-sensitive checking. 107 //===----------------------------------------------------------------------===// 108 109 template <typename CHECK_CTX> 110 static void expandGraphWithCheckers(CHECK_CTX checkCtx, 111 ExplodedNodeSet &Dst, 112 const ExplodedNodeSet &Src) { 113 const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); 114 if (Src.empty()) 115 return; 116 117 typename CHECK_CTX::CheckersTy::const_iterator 118 I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); 119 if (I == E) { 120 Dst.insert(Src); 121 return; 122 } 123 124 ExplodedNodeSet Tmp1, Tmp2; 125 const ExplodedNodeSet *PrevSet = &Src; 126 127 for (; I != E; ++I) { 128 ExplodedNodeSet *CurrSet = nullptr; 129 if (I+1 == E) 130 CurrSet = &Dst; 131 else { 132 CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; 133 CurrSet->clear(); 134 } 135 136 NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); 137 for (const auto &NI : *PrevSet) 138 checkCtx.runChecker(*I, B, NI); 139 140 // If all the produced transitions are sinks, stop. 141 if (CurrSet->empty()) 142 return; 143 144 // Update which NodeSet is the current one. 145 PrevSet = CurrSet; 146 } 147 } 148 149 namespace { 150 151 struct CheckStmtContext { 152 using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>; 153 154 bool IsPreVisit; 155 const CheckersTy &Checkers; 156 const Stmt *S; 157 ExprEngine &Eng; 158 bool WasInlined; 159 160 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 161 const Stmt *s, ExprEngine &eng, bool wasInlined = false) 162 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), 163 WasInlined(wasInlined) {} 164 165 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 166 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 167 168 void runChecker(CheckerManager::CheckStmtFunc checkFn, 169 NodeBuilder &Bldr, ExplodedNode *Pred) { 170 // FIXME: Remove respondsToCallback from CheckerContext; 171 ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : 172 ProgramPoint::PostStmtKind; 173 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 174 Pred->getLocationContext(), checkFn.Checker); 175 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 176 checkFn(S, C); 177 } 178 }; 179 180 } // namespace 181 182 /// Run checkers for visiting Stmts. 183 void CheckerManager::runCheckersForStmt(bool isPreVisit, 184 ExplodedNodeSet &Dst, 185 const ExplodedNodeSet &Src, 186 const Stmt *S, 187 ExprEngine &Eng, 188 bool WasInlined) { 189 CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), 190 S, Eng, WasInlined); 191 expandGraphWithCheckers(C, Dst, Src); 192 } 193 194 namespace { 195 196 struct CheckObjCMessageContext { 197 using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>; 198 199 ObjCMessageVisitKind Kind; 200 bool WasInlined; 201 const CheckersTy &Checkers; 202 const ObjCMethodCall &Msg; 203 ExprEngine &Eng; 204 205 CheckObjCMessageContext(ObjCMessageVisitKind visitKind, 206 const CheckersTy &checkers, 207 const ObjCMethodCall &msg, ExprEngine &eng, 208 bool wasInlined) 209 : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg), 210 Eng(eng) {} 211 212 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 213 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 214 215 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 216 NodeBuilder &Bldr, ExplodedNode *Pred) { 217 bool IsPreVisit; 218 219 switch (Kind) { 220 case ObjCMessageVisitKind::Pre: 221 IsPreVisit = true; 222 break; 223 case ObjCMessageVisitKind::MessageNil: 224 case ObjCMessageVisitKind::Post: 225 IsPreVisit = false; 226 break; 227 } 228 229 const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); 230 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 231 232 checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); 233 } 234 }; 235 236 } // namespace 237 238 /// Run checkers for visiting obj-c messages. 239 void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, 240 ExplodedNodeSet &Dst, 241 const ExplodedNodeSet &Src, 242 const ObjCMethodCall &msg, 243 ExprEngine &Eng, 244 bool WasInlined) { 245 auto &checkers = getObjCMessageCheckers(visitKind); 246 CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined); 247 expandGraphWithCheckers(C, Dst, Src); 248 } 249 250 const std::vector<CheckerManager::CheckObjCMessageFunc> & 251 CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { 252 switch (Kind) { 253 case ObjCMessageVisitKind::Pre: 254 return PreObjCMessageCheckers; 255 break; 256 case ObjCMessageVisitKind::Post: 257 return PostObjCMessageCheckers; 258 case ObjCMessageVisitKind::MessageNil: 259 return ObjCMessageNilCheckers; 260 } 261 llvm_unreachable("Unknown Kind"); 262 } 263 264 namespace { 265 266 // FIXME: This has all the same signatures as CheckObjCMessageContext. 267 // Is there a way we can merge the two? 268 struct CheckCallContext { 269 using CheckersTy = std::vector<CheckerManager::CheckCallFunc>; 270 271 bool IsPreVisit, WasInlined; 272 const CheckersTy &Checkers; 273 const CallEvent &Call; 274 ExprEngine &Eng; 275 276 CheckCallContext(bool isPreVisit, const CheckersTy &checkers, 277 const CallEvent &call, ExprEngine &eng, 278 bool wasInlined) 279 : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), 280 Call(call), Eng(eng) {} 281 282 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 283 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 284 285 void runChecker(CheckerManager::CheckCallFunc checkFn, 286 NodeBuilder &Bldr, ExplodedNode *Pred) { 287 const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); 288 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 289 290 checkFn(*Call.cloneWithState(Pred->getState()), C); 291 } 292 }; 293 294 } // namespace 295 296 /// Run checkers for visiting an abstract call event. 297 void CheckerManager::runCheckersForCallEvent(bool isPreVisit, 298 ExplodedNodeSet &Dst, 299 const ExplodedNodeSet &Src, 300 const CallEvent &Call, 301 ExprEngine &Eng, 302 bool WasInlined) { 303 CheckCallContext C(isPreVisit, 304 isPreVisit ? PreCallCheckers 305 : PostCallCheckers, 306 Call, Eng, WasInlined); 307 expandGraphWithCheckers(C, Dst, Src); 308 } 309 310 namespace { 311 312 struct CheckLocationContext { 313 using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>; 314 315 const CheckersTy &Checkers; 316 SVal Loc; 317 bool IsLoad; 318 const Stmt *NodeEx; /* Will become a CFGStmt */ 319 const Stmt *BoundEx; 320 ExprEngine &Eng; 321 322 CheckLocationContext(const CheckersTy &checkers, 323 SVal loc, bool isLoad, const Stmt *NodeEx, 324 const Stmt *BoundEx, 325 ExprEngine &eng) 326 : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), 327 BoundEx(BoundEx), Eng(eng) {} 328 329 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 330 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 331 332 void runChecker(CheckerManager::CheckLocationFunc checkFn, 333 NodeBuilder &Bldr, ExplodedNode *Pred) { 334 ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : 335 ProgramPoint::PreStoreKind; 336 const ProgramPoint &L = 337 ProgramPoint::getProgramPoint(NodeEx, K, 338 Pred->getLocationContext(), 339 checkFn.Checker); 340 CheckerContext C(Bldr, Eng, Pred, L); 341 checkFn(Loc, IsLoad, BoundEx, C); 342 } 343 }; 344 345 } // namespace 346 347 /// Run checkers for load/store of a location. 348 349 void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 350 const ExplodedNodeSet &Src, 351 SVal location, bool isLoad, 352 const Stmt *NodeEx, 353 const Stmt *BoundEx, 354 ExprEngine &Eng) { 355 CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, 356 BoundEx, Eng); 357 expandGraphWithCheckers(C, Dst, Src); 358 } 359 360 namespace { 361 362 struct CheckBindContext { 363 using CheckersTy = std::vector<CheckerManager::CheckBindFunc>; 364 365 const CheckersTy &Checkers; 366 SVal Loc; 367 SVal Val; 368 const Stmt *S; 369 ExprEngine &Eng; 370 const ProgramPoint &PP; 371 372 CheckBindContext(const CheckersTy &checkers, 373 SVal loc, SVal val, const Stmt *s, ExprEngine &eng, 374 const ProgramPoint &pp) 375 : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} 376 377 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 378 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 379 380 void runChecker(CheckerManager::CheckBindFunc checkFn, 381 NodeBuilder &Bldr, ExplodedNode *Pred) { 382 const ProgramPoint &L = PP.withTag(checkFn.Checker); 383 CheckerContext C(Bldr, Eng, Pred, L); 384 385 checkFn(Loc, Val, S, C); 386 } 387 }; 388 389 } // namespace 390 391 /// Run checkers for binding of a value to a location. 392 void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, 393 const ExplodedNodeSet &Src, 394 SVal location, SVal val, 395 const Stmt *S, ExprEngine &Eng, 396 const ProgramPoint &PP) { 397 CheckBindContext C(BindCheckers, location, val, S, Eng, PP); 398 expandGraphWithCheckers(C, Dst, Src); 399 } 400 401 void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 402 BugReporter &BR, 403 ExprEngine &Eng) { 404 for (const auto EndAnalysisChecker : EndAnalysisCheckers) 405 EndAnalysisChecker(G, BR, Eng); 406 } 407 408 namespace { 409 410 struct CheckBeginFunctionContext { 411 using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>; 412 413 const CheckersTy &Checkers; 414 ExprEngine &Eng; 415 const ProgramPoint &PP; 416 417 CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, 418 const ProgramPoint &PP) 419 : Checkers(Checkers), Eng(Eng), PP(PP) {} 420 421 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 422 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 423 424 void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, 425 NodeBuilder &Bldr, ExplodedNode *Pred) { 426 const ProgramPoint &L = PP.withTag(checkFn.Checker); 427 CheckerContext C(Bldr, Eng, Pred, L); 428 429 checkFn(C); 430 } 431 }; 432 433 } // namespace 434 435 void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, 436 const BlockEdge &L, 437 ExplodedNode *Pred, 438 ExprEngine &Eng) { 439 ExplodedNodeSet Src; 440 Src.insert(Pred); 441 CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); 442 expandGraphWithCheckers(C, Dst, Src); 443 } 444 445 /// Run checkers for end of path. 446 // Note, We do not chain the checker output (like in expandGraphWithCheckers) 447 // for this callback since end of path nodes are expected to be final. 448 void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, 449 ExplodedNodeSet &Dst, 450 ExplodedNode *Pred, 451 ExprEngine &Eng, 452 const ReturnStmt *RS) { 453 // We define the builder outside of the loop because if at least one checker 454 // creates a successor for Pred, we do not need to generate an 455 // autotransition for it. 456 NodeBuilder Bldr(Pred, Dst, BC); 457 for (const auto checkFn : EndFunctionCheckers) { 458 const ProgramPoint &L = 459 FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker); 460 CheckerContext C(Bldr, Eng, Pred, L); 461 checkFn(RS, C); 462 } 463 } 464 465 namespace { 466 467 struct CheckBranchConditionContext { 468 using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>; 469 470 const CheckersTy &Checkers; 471 const Stmt *Condition; 472 ExprEngine &Eng; 473 474 CheckBranchConditionContext(const CheckersTy &checkers, 475 const Stmt *Cond, ExprEngine &eng) 476 : Checkers(checkers), Condition(Cond), Eng(eng) {} 477 478 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 479 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 480 481 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, 482 NodeBuilder &Bldr, ExplodedNode *Pred) { 483 ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), 484 checkFn.Checker); 485 CheckerContext C(Bldr, Eng, Pred, L); 486 checkFn(Condition, C); 487 } 488 }; 489 490 } // namespace 491 492 /// Run checkers for branch condition. 493 void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, 494 ExplodedNodeSet &Dst, 495 ExplodedNode *Pred, 496 ExprEngine &Eng) { 497 ExplodedNodeSet Src; 498 Src.insert(Pred); 499 CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); 500 expandGraphWithCheckers(C, Dst, Src); 501 } 502 503 namespace { 504 505 struct CheckNewAllocatorContext { 506 using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>; 507 508 const CheckersTy &Checkers; 509 const CXXNewExpr *NE; 510 SVal Target; 511 bool WasInlined; 512 ExprEngine &Eng; 513 514 CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE, 515 SVal Target, bool WasInlined, ExprEngine &Eng) 516 : Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined), 517 Eng(Eng) {} 518 519 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 520 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 521 522 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn, 523 NodeBuilder &Bldr, ExplodedNode *Pred) { 524 ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext()); 525 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 526 checkFn(NE, Target, C); 527 } 528 }; 529 530 } // namespace 531 532 void CheckerManager::runCheckersForNewAllocator( 533 const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred, 534 ExprEngine &Eng, bool WasInlined) { 535 ExplodedNodeSet Src; 536 Src.insert(Pred); 537 CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng); 538 expandGraphWithCheckers(C, Dst, Src); 539 } 540 541 /// Run checkers for live symbols. 542 void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, 543 SymbolReaper &SymReaper) { 544 for (const auto LiveSymbolsChecker : LiveSymbolsCheckers) 545 LiveSymbolsChecker(state, SymReaper); 546 } 547 548 namespace { 549 550 struct CheckDeadSymbolsContext { 551 using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>; 552 553 const CheckersTy &Checkers; 554 SymbolReaper &SR; 555 const Stmt *S; 556 ExprEngine &Eng; 557 ProgramPoint::Kind ProgarmPointKind; 558 559 CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, 560 const Stmt *s, ExprEngine &eng, 561 ProgramPoint::Kind K) 562 : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {} 563 564 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 565 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 566 567 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, 568 NodeBuilder &Bldr, ExplodedNode *Pred) { 569 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, 570 Pred->getLocationContext(), checkFn.Checker); 571 CheckerContext C(Bldr, Eng, Pred, L); 572 573 // Note, do not pass the statement to the checkers without letting them 574 // differentiate if we ran remove dead bindings before or after the 575 // statement. 576 checkFn(SR, C); 577 } 578 }; 579 580 } // namespace 581 582 /// Run checkers for dead symbols. 583 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, 584 const ExplodedNodeSet &Src, 585 SymbolReaper &SymReaper, 586 const Stmt *S, 587 ExprEngine &Eng, 588 ProgramPoint::Kind K) { 589 CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); 590 expandGraphWithCheckers(C, Dst, Src); 591 } 592 593 /// Run checkers for region changes. 594 ProgramStateRef 595 CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, 596 const InvalidatedSymbols *invalidated, 597 ArrayRef<const MemRegion *> ExplicitRegions, 598 ArrayRef<const MemRegion *> Regions, 599 const LocationContext *LCtx, 600 const CallEvent *Call) { 601 for (const auto RegionChangesChecker : RegionChangesCheckers) { 602 // If any checker declares the state infeasible (or if it starts that way), 603 // bail out. 604 if (!state) 605 return nullptr; 606 state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions, 607 LCtx, Call); 608 } 609 return state; 610 } 611 612 /// Run checkers to process symbol escape event. 613 ProgramStateRef 614 CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, 615 const InvalidatedSymbols &Escaped, 616 const CallEvent *Call, 617 PointerEscapeKind Kind, 618 RegionAndSymbolInvalidationTraits *ETraits) { 619 assert((Call != nullptr || 620 (Kind != PSK_DirectEscapeOnCall && 621 Kind != PSK_IndirectEscapeOnCall)) && 622 "Call must not be NULL when escaping on call"); 623 for (const auto PointerEscapeChecker : PointerEscapeCheckers) { 624 // If any checker declares the state infeasible (or if it starts that 625 // way), bail out. 626 if (!State) 627 return nullptr; 628 State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits); 629 } 630 return State; 631 } 632 633 /// Run checkers for handling assumptions on symbolic values. 634 ProgramStateRef 635 CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, 636 SVal Cond, bool Assumption) { 637 for (const auto EvalAssumeChecker : EvalAssumeCheckers) { 638 // If any checker declares the state infeasible (or if it starts that way), 639 // bail out. 640 if (!state) 641 return nullptr; 642 state = EvalAssumeChecker(state, Cond, Assumption); 643 } 644 return state; 645 } 646 647 /// Run checkers for evaluating a call. 648 /// Only one checker will evaluate the call. 649 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, 650 const ExplodedNodeSet &Src, 651 const CallEvent &Call, 652 ExprEngine &Eng) { 653 const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); 654 for (const auto Pred : Src) { 655 bool anyEvaluated = false; 656 657 ExplodedNodeSet checkDst; 658 NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); 659 660 // Check if any of the EvalCall callbacks can evaluate the call. 661 for (const auto EvalCallChecker : EvalCallCheckers) { 662 ProgramPoint::Kind K = ProgramPoint::PostStmtKind; 663 const ProgramPoint &L = 664 ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), 665 EvalCallChecker.Checker); 666 bool evaluated = false; 667 { // CheckerContext generates transitions(populates checkDest) on 668 // destruction, so introduce the scope to make sure it gets properly 669 // populated. 670 CheckerContext C(B, Eng, Pred, L); 671 evaluated = EvalCallChecker(CE, C); 672 } 673 assert(!(evaluated && anyEvaluated) 674 && "There are more than one checkers evaluating the call"); 675 if (evaluated) { 676 anyEvaluated = true; 677 Dst.insert(checkDst); 678 #ifdef NDEBUG 679 break; // on release don't check that no other checker also evals. 680 #endif 681 } 682 } 683 684 // If none of the checkers evaluated the call, ask ExprEngine to handle it. 685 if (!anyEvaluated) { 686 NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); 687 Eng.defaultEvalCall(B, Pred, Call); 688 } 689 } 690 } 691 692 /// Run checkers for the entire Translation Unit. 693 void CheckerManager::runCheckersOnEndOfTranslationUnit( 694 const TranslationUnitDecl *TU, 695 AnalysisManager &mgr, 696 BugReporter &BR) { 697 for (const auto EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) 698 EndOfTranslationUnitChecker(TU, mgr, BR); 699 } 700 701 void CheckerManager::runCheckersForPrintState(raw_ostream &Out, 702 ProgramStateRef State, 703 const char *NL, const char *Sep) { 704 for (const auto &CheckerTag : CheckerTags) 705 CheckerTag.second->printState(Out, State, NL, Sep); 706 } 707 708 //===----------------------------------------------------------------------===// 709 // Internal registration functions for AST traversing. 710 //===----------------------------------------------------------------------===// 711 712 void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 713 HandlesDeclFunc isForDeclFn) { 714 DeclCheckerInfo info = { checkfn, isForDeclFn }; 715 DeclCheckers.push_back(info); 716 } 717 718 void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 719 BodyCheckers.push_back(checkfn); 720 } 721 722 //===----------------------------------------------------------------------===// 723 // Internal registration functions for path-sensitive checking. 724 //===----------------------------------------------------------------------===// 725 726 void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 727 HandlesStmtFunc isForStmtFn) { 728 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 729 StmtCheckers.push_back(info); 730 } 731 732 void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 733 HandlesStmtFunc isForStmtFn) { 734 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 735 StmtCheckers.push_back(info); 736 } 737 738 void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 739 PreObjCMessageCheckers.push_back(checkfn); 740 } 741 742 void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { 743 ObjCMessageNilCheckers.push_back(checkfn); 744 } 745 746 void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 747 PostObjCMessageCheckers.push_back(checkfn); 748 } 749 750 void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { 751 PreCallCheckers.push_back(checkfn); 752 } 753 void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { 754 PostCallCheckers.push_back(checkfn); 755 } 756 757 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 758 LocationCheckers.push_back(checkfn); 759 } 760 761 void CheckerManager::_registerForBind(CheckBindFunc checkfn) { 762 BindCheckers.push_back(checkfn); 763 } 764 765 void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 766 EndAnalysisCheckers.push_back(checkfn); 767 } 768 769 void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { 770 BeginFunctionCheckers.push_back(checkfn); 771 } 772 773 void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { 774 EndFunctionCheckers.push_back(checkfn); 775 } 776 777 void CheckerManager::_registerForBranchCondition( 778 CheckBranchConditionFunc checkfn) { 779 BranchConditionCheckers.push_back(checkfn); 780 } 781 782 void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) { 783 NewAllocatorCheckers.push_back(checkfn); 784 } 785 786 void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { 787 LiveSymbolsCheckers.push_back(checkfn); 788 } 789 790 void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { 791 DeadSymbolsCheckers.push_back(checkfn); 792 } 793 794 void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { 795 RegionChangesCheckers.push_back(checkfn); 796 } 797 798 void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ 799 PointerEscapeCheckers.push_back(checkfn); 800 } 801 802 void CheckerManager::_registerForConstPointerEscape( 803 CheckPointerEscapeFunc checkfn) { 804 PointerEscapeCheckers.push_back(checkfn); 805 } 806 807 void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { 808 EvalAssumeCheckers.push_back(checkfn); 809 } 810 811 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { 812 EvalCallCheckers.push_back(checkfn); 813 } 814 815 void CheckerManager::_registerForEndOfTranslationUnit( 816 CheckEndOfTranslationUnit checkfn) { 817 EndOfTranslationUnitCheckers.push_back(checkfn); 818 } 819 820 //===----------------------------------------------------------------------===// 821 // Implementation details. 822 //===----------------------------------------------------------------------===// 823 824 const CheckerManager::CachedStmtCheckers & 825 CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 826 assert(S); 827 828 unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); 829 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); 830 if (CCI != CachedStmtCheckersMap.end()) 831 return CCI->second; 832 833 // Find the checkers that should run for this Stmt and cache them. 834 CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; 835 for (const auto &Info : StmtCheckers) 836 if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) 837 Checkers.push_back(Info.CheckFn); 838 return Checkers; 839 } 840 841 CheckerManager::~CheckerManager() { 842 for (const auto CheckerDtor : CheckerDtors) 843 CheckerDtor(); 844 } 845