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