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