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