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 const auto IfAnyAreNonEmpty = [](const auto &... Callbacks) -> bool { 37 bool Result = false; 38 // FIXME: Use fold expressions in C++17. 39 LLVM_ATTRIBUTE_UNUSED int Unused[]{0, (Result |= !Callbacks.empty())...}; 40 return Result; 41 }; 42 return IfAnyAreNonEmpty( 43 StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers, 44 PostObjCMessageCheckers, PreCallCheckers, PostCallCheckers, 45 LocationCheckers, BindCheckers, EndAnalysisCheckers, 46 BeginFunctionCheckers, EndFunctionCheckers, BranchConditionCheckers, 47 NewAllocatorCheckers, LiveSymbolsCheckers, DeadSymbolsCheckers, 48 RegionChangesCheckers, PointerEscapeCheckers, EvalAssumeCheckers, 49 EvalCallCheckers, EndOfTranslationUnitCheckers); 50 } 51 52 void CheckerManager::finishedCheckerRegistration() { 53 #ifndef NDEBUG 54 // Make sure that for every event that has listeners, there is at least 55 // one dispatcher registered for it. 56 for (const auto &Event : Events) 57 assert(Event.second.HasDispatcher && 58 "No dispatcher registered for an event"); 59 #endif 60 } 61 62 void CheckerManager::reportInvalidCheckerOptionValue( 63 const CheckerBase *C, StringRef OptionName, 64 StringRef ExpectedValueDesc) const { 65 66 getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) 67 << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() 68 << ExpectedValueDesc; 69 } 70 71 //===----------------------------------------------------------------------===// 72 // Functions for running checkers for AST traversing.. 73 //===----------------------------------------------------------------------===// 74 75 void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 76 BugReporter &BR) { 77 assert(D); 78 79 unsigned DeclKind = D->getKind(); 80 CachedDeclCheckers *checkers = nullptr; 81 CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); 82 if (CCI != CachedDeclCheckersMap.end()) { 83 checkers = &(CCI->second); 84 } else { 85 // Find the checkers that should run for this Decl and cache them. 86 checkers = &CachedDeclCheckersMap[DeclKind]; 87 for (const auto &info : DeclCheckers) 88 if (info.IsForDeclFn(D)) 89 checkers->push_back(info.CheckFn); 90 } 91 92 assert(checkers); 93 for (const auto &checker : *checkers) 94 checker(D, mgr, BR); 95 } 96 97 void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 98 BugReporter &BR) { 99 assert(D && D->hasBody()); 100 101 for (const auto &BodyChecker : BodyCheckers) 102 BodyChecker(D, mgr, BR); 103 } 104 105 //===----------------------------------------------------------------------===// 106 // Functions for running checkers for path-sensitive checking. 107 //===----------------------------------------------------------------------===// 108 109 template <typename CHECK_CTX> 110 static void expandGraphWithCheckers(CHECK_CTX checkCtx, 111 ExplodedNodeSet &Dst, 112 const ExplodedNodeSet &Src) { 113 const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); 114 if (Src.empty()) 115 return; 116 117 typename CHECK_CTX::CheckersTy::const_iterator 118 I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); 119 if (I == E) { 120 Dst.insert(Src); 121 return; 122 } 123 124 ExplodedNodeSet Tmp1, Tmp2; 125 const ExplodedNodeSet *PrevSet = &Src; 126 127 for (; I != E; ++I) { 128 ExplodedNodeSet *CurrSet = nullptr; 129 if (I+1 == E) 130 CurrSet = &Dst; 131 else { 132 CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; 133 CurrSet->clear(); 134 } 135 136 NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); 137 for (const auto &NI : *PrevSet) 138 checkCtx.runChecker(*I, B, NI); 139 140 // If all the produced transitions are sinks, stop. 141 if (CurrSet->empty()) 142 return; 143 144 // Update which NodeSet is the current one. 145 PrevSet = CurrSet; 146 } 147 } 148 149 namespace { 150 151 struct CheckStmtContext { 152 using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>; 153 154 bool IsPreVisit; 155 const CheckersTy &Checkers; 156 const Stmt *S; 157 ExprEngine &Eng; 158 bool WasInlined; 159 160 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 161 const Stmt *s, ExprEngine &eng, bool wasInlined = false) 162 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), 163 WasInlined(wasInlined) {} 164 165 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 166 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 167 168 void runChecker(CheckerManager::CheckStmtFunc checkFn, 169 NodeBuilder &Bldr, ExplodedNode *Pred) { 170 // FIXME: Remove respondsToCallback from CheckerContext; 171 ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : 172 ProgramPoint::PostStmtKind; 173 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 174 Pred->getLocationContext(), checkFn.Checker); 175 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 176 checkFn(S, C); 177 } 178 }; 179 180 } // namespace 181 182 /// Run checkers for visiting Stmts. 183 void CheckerManager::runCheckersForStmt(bool isPreVisit, 184 ExplodedNodeSet &Dst, 185 const ExplodedNodeSet &Src, 186 const Stmt *S, 187 ExprEngine &Eng, 188 bool WasInlined) { 189 CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), 190 S, Eng, WasInlined); 191 expandGraphWithCheckers(C, Dst, Src); 192 } 193 194 namespace { 195 196 struct CheckObjCMessageContext { 197 using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>; 198 199 ObjCMessageVisitKind Kind; 200 bool WasInlined; 201 const CheckersTy &Checkers; 202 const ObjCMethodCall &Msg; 203 ExprEngine &Eng; 204 205 CheckObjCMessageContext(ObjCMessageVisitKind visitKind, 206 const CheckersTy &checkers, 207 const ObjCMethodCall &msg, ExprEngine &eng, 208 bool wasInlined) 209 : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg), 210 Eng(eng) {} 211 212 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 213 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 214 215 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 216 NodeBuilder &Bldr, ExplodedNode *Pred) { 217 bool IsPreVisit; 218 219 switch (Kind) { 220 case ObjCMessageVisitKind::Pre: 221 IsPreVisit = true; 222 break; 223 case ObjCMessageVisitKind::MessageNil: 224 case ObjCMessageVisitKind::Post: 225 IsPreVisit = false; 226 break; 227 } 228 229 const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); 230 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 231 232 checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); 233 } 234 }; 235 236 } // namespace 237 238 /// Run checkers for visiting obj-c messages. 239 void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, 240 ExplodedNodeSet &Dst, 241 const ExplodedNodeSet &Src, 242 const ObjCMethodCall &msg, 243 ExprEngine &Eng, 244 bool WasInlined) { 245 const auto &checkers = getObjCMessageCheckers(visitKind); 246 CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined); 247 expandGraphWithCheckers(C, Dst, Src); 248 } 249 250 const std::vector<CheckerManager::CheckObjCMessageFunc> & 251 CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) const { 252 switch (Kind) { 253 case ObjCMessageVisitKind::Pre: 254 return PreObjCMessageCheckers; 255 break; 256 case ObjCMessageVisitKind::Post: 257 return PostObjCMessageCheckers; 258 case ObjCMessageVisitKind::MessageNil: 259 return ObjCMessageNilCheckers; 260 } 261 llvm_unreachable("Unknown Kind"); 262 } 263 264 namespace { 265 266 // FIXME: This has all the same signatures as CheckObjCMessageContext. 267 // Is there a way we can merge the two? 268 struct CheckCallContext { 269 using CheckersTy = std::vector<CheckerManager::CheckCallFunc>; 270 271 bool IsPreVisit, WasInlined; 272 const CheckersTy &Checkers; 273 const CallEvent &Call; 274 ExprEngine &Eng; 275 276 CheckCallContext(bool isPreVisit, const CheckersTy &checkers, 277 const CallEvent &call, ExprEngine &eng, 278 bool wasInlined) 279 : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), 280 Call(call), Eng(eng) {} 281 282 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 283 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 284 285 void runChecker(CheckerManager::CheckCallFunc checkFn, 286 NodeBuilder &Bldr, ExplodedNode *Pred) { 287 const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); 288 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 289 290 checkFn(*Call.cloneWithState(Pred->getState()), C); 291 } 292 }; 293 294 } // namespace 295 296 /// Run checkers for visiting an abstract call event. 297 void CheckerManager::runCheckersForCallEvent(bool isPreVisit, 298 ExplodedNodeSet &Dst, 299 const ExplodedNodeSet &Src, 300 const CallEvent &Call, 301 ExprEngine &Eng, 302 bool WasInlined) { 303 CheckCallContext C(isPreVisit, 304 isPreVisit ? PreCallCheckers 305 : PostCallCheckers, 306 Call, Eng, WasInlined); 307 expandGraphWithCheckers(C, Dst, Src); 308 } 309 310 namespace { 311 312 struct CheckLocationContext { 313 using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>; 314 315 const CheckersTy &Checkers; 316 SVal Loc; 317 bool IsLoad; 318 const Stmt *NodeEx; /* Will become a CFGStmt */ 319 const Stmt *BoundEx; 320 ExprEngine &Eng; 321 322 CheckLocationContext(const CheckersTy &checkers, 323 SVal loc, bool isLoad, const Stmt *NodeEx, 324 const Stmt *BoundEx, 325 ExprEngine &eng) 326 : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), 327 BoundEx(BoundEx), Eng(eng) {} 328 329 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 330 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 331 332 void runChecker(CheckerManager::CheckLocationFunc checkFn, 333 NodeBuilder &Bldr, ExplodedNode *Pred) { 334 ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : 335 ProgramPoint::PreStoreKind; 336 const ProgramPoint &L = 337 ProgramPoint::getProgramPoint(NodeEx, K, 338 Pred->getLocationContext(), 339 checkFn.Checker); 340 CheckerContext C(Bldr, Eng, Pred, L); 341 checkFn(Loc, IsLoad, BoundEx, C); 342 } 343 }; 344 345 } // namespace 346 347 /// Run checkers for load/store of a location. 348 349 void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 350 const ExplodedNodeSet &Src, 351 SVal location, bool isLoad, 352 const Stmt *NodeEx, 353 const Stmt *BoundEx, 354 ExprEngine &Eng) { 355 CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, 356 BoundEx, Eng); 357 expandGraphWithCheckers(C, Dst, Src); 358 } 359 360 namespace { 361 362 struct CheckBindContext { 363 using CheckersTy = std::vector<CheckerManager::CheckBindFunc>; 364 365 const CheckersTy &Checkers; 366 SVal Loc; 367 SVal Val; 368 const Stmt *S; 369 ExprEngine &Eng; 370 const ProgramPoint &PP; 371 372 CheckBindContext(const CheckersTy &checkers, 373 SVal loc, SVal val, const Stmt *s, ExprEngine &eng, 374 const ProgramPoint &pp) 375 : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} 376 377 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 378 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 379 380 void runChecker(CheckerManager::CheckBindFunc checkFn, 381 NodeBuilder &Bldr, ExplodedNode *Pred) { 382 const ProgramPoint &L = PP.withTag(checkFn.Checker); 383 CheckerContext C(Bldr, Eng, Pred, L); 384 385 checkFn(Loc, Val, S, C); 386 } 387 }; 388 389 } // namespace 390 391 /// Run checkers for binding of a value to a location. 392 void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, 393 const ExplodedNodeSet &Src, 394 SVal location, SVal val, 395 const Stmt *S, ExprEngine &Eng, 396 const ProgramPoint &PP) { 397 CheckBindContext C(BindCheckers, location, val, S, Eng, PP); 398 expandGraphWithCheckers(C, Dst, Src); 399 } 400 401 void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 402 BugReporter &BR, 403 ExprEngine &Eng) { 404 for (const auto &EndAnalysisChecker : EndAnalysisCheckers) 405 EndAnalysisChecker(G, BR, Eng); 406 } 407 408 namespace { 409 410 struct CheckBeginFunctionContext { 411 using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>; 412 413 const CheckersTy &Checkers; 414 ExprEngine &Eng; 415 const ProgramPoint &PP; 416 417 CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, 418 const ProgramPoint &PP) 419 : Checkers(Checkers), Eng(Eng), PP(PP) {} 420 421 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 422 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 423 424 void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, 425 NodeBuilder &Bldr, ExplodedNode *Pred) { 426 const ProgramPoint &L = PP.withTag(checkFn.Checker); 427 CheckerContext C(Bldr, Eng, Pred, L); 428 429 checkFn(C); 430 } 431 }; 432 433 } // namespace 434 435 void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, 436 const BlockEdge &L, 437 ExplodedNode *Pred, 438 ExprEngine &Eng) { 439 ExplodedNodeSet Src; 440 Src.insert(Pred); 441 CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); 442 expandGraphWithCheckers(C, Dst, Src); 443 } 444 445 /// Run checkers for end of path. 446 // Note, We do not chain the checker output (like in expandGraphWithCheckers) 447 // for this callback since end of path nodes are expected to be final. 448 void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, 449 ExplodedNodeSet &Dst, 450 ExplodedNode *Pred, 451 ExprEngine &Eng, 452 const ReturnStmt *RS) { 453 // We define the builder outside of the loop because if at least one checker 454 // creates a successor for Pred, we do not need to generate an 455 // autotransition for it. 456 NodeBuilder Bldr(Pred, Dst, BC); 457 for (const auto &checkFn : EndFunctionCheckers) { 458 const ProgramPoint &L = 459 FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker); 460 CheckerContext C(Bldr, Eng, Pred, L); 461 checkFn(RS, C); 462 } 463 } 464 465 namespace { 466 467 struct CheckBranchConditionContext { 468 using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>; 469 470 const CheckersTy &Checkers; 471 const Stmt *Condition; 472 ExprEngine &Eng; 473 474 CheckBranchConditionContext(const CheckersTy &checkers, 475 const Stmt *Cond, ExprEngine &eng) 476 : Checkers(checkers), Condition(Cond), Eng(eng) {} 477 478 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 479 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 480 481 void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, 482 NodeBuilder &Bldr, ExplodedNode *Pred) { 483 ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), 484 checkFn.Checker); 485 CheckerContext C(Bldr, Eng, Pred, L); 486 checkFn(Condition, C); 487 } 488 }; 489 490 } // namespace 491 492 /// Run checkers for branch condition. 493 void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, 494 ExplodedNodeSet &Dst, 495 ExplodedNode *Pred, 496 ExprEngine &Eng) { 497 ExplodedNodeSet Src; 498 Src.insert(Pred); 499 CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); 500 expandGraphWithCheckers(C, Dst, Src); 501 } 502 503 namespace { 504 505 struct CheckNewAllocatorContext { 506 using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>; 507 508 const CheckersTy &Checkers; 509 const CXXAllocatorCall &Call; 510 bool WasInlined; 511 ExprEngine &Eng; 512 513 CheckNewAllocatorContext(const CheckersTy &Checkers, 514 const CXXAllocatorCall &Call, bool WasInlined, 515 ExprEngine &Eng) 516 : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {} 517 518 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 519 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 520 521 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn, 522 NodeBuilder &Bldr, ExplodedNode *Pred) { 523 ProgramPoint L = 524 PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext()); 525 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 526 checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())), 527 C); 528 } 529 }; 530 531 } // namespace 532 533 void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call, 534 ExplodedNodeSet &Dst, 535 ExplodedNode *Pred, 536 ExprEngine &Eng, 537 bool WasInlined) { 538 ExplodedNodeSet Src; 539 Src.insert(Pred); 540 CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng); 541 expandGraphWithCheckers(C, Dst, Src); 542 } 543 544 /// Run checkers for live symbols. 545 void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, 546 SymbolReaper &SymReaper) { 547 for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers) 548 LiveSymbolsChecker(state, SymReaper); 549 } 550 551 namespace { 552 553 struct CheckDeadSymbolsContext { 554 using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>; 555 556 const CheckersTy &Checkers; 557 SymbolReaper &SR; 558 const Stmt *S; 559 ExprEngine &Eng; 560 ProgramPoint::Kind ProgarmPointKind; 561 562 CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, 563 const Stmt *s, ExprEngine &eng, 564 ProgramPoint::Kind K) 565 : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {} 566 567 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 568 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 569 570 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, 571 NodeBuilder &Bldr, ExplodedNode *Pred) { 572 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, 573 Pred->getLocationContext(), checkFn.Checker); 574 CheckerContext C(Bldr, Eng, Pred, L); 575 576 // Note, do not pass the statement to the checkers without letting them 577 // differentiate if we ran remove dead bindings before or after the 578 // statement. 579 checkFn(SR, C); 580 } 581 }; 582 583 } // namespace 584 585 /// Run checkers for dead symbols. 586 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, 587 const ExplodedNodeSet &Src, 588 SymbolReaper &SymReaper, 589 const Stmt *S, 590 ExprEngine &Eng, 591 ProgramPoint::Kind K) { 592 CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); 593 expandGraphWithCheckers(C, Dst, Src); 594 } 595 596 /// Run checkers for region changes. 597 ProgramStateRef 598 CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, 599 const InvalidatedSymbols *invalidated, 600 ArrayRef<const MemRegion *> ExplicitRegions, 601 ArrayRef<const MemRegion *> Regions, 602 const LocationContext *LCtx, 603 const CallEvent *Call) { 604 for (const auto &RegionChangesChecker : RegionChangesCheckers) { 605 // If any checker declares the state infeasible (or if it starts that way), 606 // bail out. 607 if (!state) 608 return nullptr; 609 state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions, 610 LCtx, Call); 611 } 612 return state; 613 } 614 615 /// Run checkers to process symbol escape event. 616 ProgramStateRef 617 CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, 618 const InvalidatedSymbols &Escaped, 619 const CallEvent *Call, 620 PointerEscapeKind Kind, 621 RegionAndSymbolInvalidationTraits *ETraits) { 622 assert((Call != nullptr || 623 (Kind != PSK_DirectEscapeOnCall && 624 Kind != PSK_IndirectEscapeOnCall)) && 625 "Call must not be NULL when escaping on call"); 626 for (const auto &PointerEscapeChecker : PointerEscapeCheckers) { 627 // If any checker declares the state infeasible (or if it starts that 628 // way), bail out. 629 if (!State) 630 return nullptr; 631 State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits); 632 } 633 return State; 634 } 635 636 /// Run checkers for handling assumptions on symbolic values. 637 ProgramStateRef 638 CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, 639 SVal Cond, bool Assumption) { 640 for (const auto &EvalAssumeChecker : EvalAssumeCheckers) { 641 // If any checker declares the state infeasible (or if it starts that way), 642 // bail out. 643 if (!state) 644 return nullptr; 645 state = EvalAssumeChecker(state, Cond, Assumption); 646 } 647 return state; 648 } 649 650 /// Run checkers for evaluating a call. 651 /// Only one checker will evaluate the call. 652 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, 653 const ExplodedNodeSet &Src, 654 const CallEvent &Call, 655 ExprEngine &Eng, 656 const EvalCallOptions &CallOpts) { 657 for (auto *const Pred : Src) { 658 bool anyEvaluated = false; 659 660 ExplodedNodeSet checkDst; 661 NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); 662 663 // Check if any of the EvalCall callbacks can evaluate the call. 664 for (const auto &EvalCallChecker : EvalCallCheckers) { 665 // TODO: Support the situation when the call doesn't correspond 666 // to any Expr. 667 ProgramPoint L = ProgramPoint::getProgramPoint( 668 Call.getOriginExpr(), ProgramPoint::PostStmtKind, 669 Pred->getLocationContext(), 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, CallOpts); 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