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