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