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 <vector> 32 33 using namespace clang; 34 using namespace ento; 35 36 bool CheckerManager::hasPathSensitiveCheckers() const { 37 const auto IfAnyAreNonEmpty = [](const auto &... Callbacks) -> bool { 38 bool Result = false; 39 // FIXME: Use fold expressions in C++17. 40 LLVM_ATTRIBUTE_UNUSED int Unused[]{0, (Result |= !Callbacks.empty())...}; 41 return Result; 42 }; 43 return IfAnyAreNonEmpty( 44 StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers, 45 PostObjCMessageCheckers, PreCallCheckers, PostCallCheckers, 46 LocationCheckers, BindCheckers, EndAnalysisCheckers, 47 BeginFunctionCheckers, EndFunctionCheckers, BranchConditionCheckers, 48 NewAllocatorCheckers, LiveSymbolsCheckers, DeadSymbolsCheckers, 49 RegionChangesCheckers, PointerEscapeCheckers, EvalAssumeCheckers, 50 EvalCallCheckers, EndOfTranslationUnitCheckers); 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 getDiagnostics().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 const 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) const { 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 CXXAllocatorCall &Call; 511 bool WasInlined; 512 ExprEngine &Eng; 513 514 CheckNewAllocatorContext(const CheckersTy &Checkers, 515 const CXXAllocatorCall &Call, bool WasInlined, 516 ExprEngine &Eng) 517 : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {} 518 519 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 520 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 521 522 void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn, 523 NodeBuilder &Bldr, ExplodedNode *Pred) { 524 ProgramPoint L = 525 PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext()); 526 CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 527 checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())), 528 C); 529 } 530 }; 531 532 } // namespace 533 534 void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call, 535 ExplodedNodeSet &Dst, 536 ExplodedNode *Pred, 537 ExprEngine &Eng, 538 bool WasInlined) { 539 ExplodedNodeSet Src; 540 Src.insert(Pred); 541 CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng); 542 expandGraphWithCheckers(C, Dst, Src); 543 } 544 545 /// Run checkers for live symbols. 546 void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, 547 SymbolReaper &SymReaper) { 548 for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers) 549 LiveSymbolsChecker(state, SymReaper); 550 } 551 552 namespace { 553 554 struct CheckDeadSymbolsContext { 555 using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>; 556 557 const CheckersTy &Checkers; 558 SymbolReaper &SR; 559 const Stmt *S; 560 ExprEngine &Eng; 561 ProgramPoint::Kind ProgarmPointKind; 562 563 CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, 564 const Stmt *s, ExprEngine &eng, 565 ProgramPoint::Kind K) 566 : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {} 567 568 CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 569 CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 570 571 void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, 572 NodeBuilder &Bldr, ExplodedNode *Pred) { 573 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, 574 Pred->getLocationContext(), checkFn.Checker); 575 CheckerContext C(Bldr, Eng, Pred, L); 576 577 // Note, do not pass the statement to the checkers without letting them 578 // differentiate if we ran remove dead bindings before or after the 579 // statement. 580 checkFn(SR, C); 581 } 582 }; 583 584 } // namespace 585 586 /// Run checkers for dead symbols. 587 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, 588 const ExplodedNodeSet &Src, 589 SymbolReaper &SymReaper, 590 const Stmt *S, 591 ExprEngine &Eng, 592 ProgramPoint::Kind K) { 593 CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); 594 expandGraphWithCheckers(C, Dst, Src); 595 } 596 597 /// Run checkers for region changes. 598 ProgramStateRef 599 CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, 600 const InvalidatedSymbols *invalidated, 601 ArrayRef<const MemRegion *> ExplicitRegions, 602 ArrayRef<const MemRegion *> Regions, 603 const LocationContext *LCtx, 604 const CallEvent *Call) { 605 for (const auto &RegionChangesChecker : RegionChangesCheckers) { 606 // If any checker declares the state infeasible (or if it starts that way), 607 // bail out. 608 if (!state) 609 return nullptr; 610 state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions, 611 LCtx, Call); 612 } 613 return state; 614 } 615 616 /// Run checkers to process symbol escape event. 617 ProgramStateRef 618 CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, 619 const InvalidatedSymbols &Escaped, 620 const CallEvent *Call, 621 PointerEscapeKind Kind, 622 RegionAndSymbolInvalidationTraits *ETraits) { 623 assert((Call != nullptr || 624 (Kind != PSK_DirectEscapeOnCall && 625 Kind != PSK_IndirectEscapeOnCall)) && 626 "Call must not be NULL when escaping on call"); 627 for (const auto &PointerEscapeChecker : PointerEscapeCheckers) { 628 // If any checker declares the state infeasible (or if it starts that 629 // way), bail out. 630 if (!State) 631 return nullptr; 632 State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits); 633 } 634 return State; 635 } 636 637 /// Run checkers for handling assumptions on symbolic values. 638 ProgramStateRef 639 CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, 640 SVal Cond, bool Assumption) { 641 for (const auto &EvalAssumeChecker : EvalAssumeCheckers) { 642 // If any checker declares the state infeasible (or if it starts that way), 643 // bail out. 644 if (!state) 645 return nullptr; 646 state = EvalAssumeChecker(state, Cond, Assumption); 647 } 648 return state; 649 } 650 651 /// Run checkers for evaluating a call. 652 /// Only one checker will evaluate the call. 653 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, 654 const ExplodedNodeSet &Src, 655 const CallEvent &Call, 656 ExprEngine &Eng, 657 const EvalCallOptions &CallOpts) { 658 for (auto *const Pred : Src) { 659 Optional<CheckerNameRef> evaluatorChecker; 660 661 ExplodedNodeSet checkDst; 662 NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); 663 664 // Check if any of the EvalCall callbacks can evaluate the call. 665 for (const auto &EvalCallChecker : EvalCallCheckers) { 666 // TODO: Support the situation when the call doesn't correspond 667 // to any Expr. 668 ProgramPoint L = ProgramPoint::getProgramPoint( 669 Call.getOriginExpr(), ProgramPoint::PostStmtKind, 670 Pred->getLocationContext(), EvalCallChecker.Checker); 671 bool evaluated = false; 672 { // CheckerContext generates transitions(populates checkDest) on 673 // destruction, so introduce the scope to make sure it gets properly 674 // populated. 675 CheckerContext C(B, Eng, Pred, L); 676 evaluated = EvalCallChecker(Call, C); 677 } 678 #ifndef NDEBUG 679 if (evaluated && evaluatorChecker) { 680 const auto toString = [](const CallEvent &Call) -> std::string { 681 std::string Buf; 682 llvm::raw_string_ostream OS(Buf); 683 Call.dump(OS); 684 OS.flush(); 685 return Buf; 686 }; 687 std::string AssertionMessage = llvm::formatv( 688 "The '{0}' call has been already evaluated by the {1} checker, " 689 "while the {2} checker also tried to evaluate the same call. At " 690 "most one checker supposed to evaluate a call.", 691 toString(Call), evaluatorChecker->getName(), 692 EvalCallChecker.Checker->getCheckerName()); 693 llvm_unreachable(AssertionMessage.c_str()); 694 } 695 #endif 696 if (evaluated) { 697 evaluatorChecker = EvalCallChecker.Checker->getCheckerName(); 698 Dst.insert(checkDst); 699 #ifdef NDEBUG 700 break; // on release don't check that no other checker also evals. 701 #endif 702 } 703 } 704 705 // If none of the checkers evaluated the call, ask ExprEngine to handle it. 706 if (!evaluatorChecker) { 707 NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); 708 Eng.defaultEvalCall(B, Pred, Call, CallOpts); 709 } 710 } 711 } 712 713 /// Run checkers for the entire Translation Unit. 714 void CheckerManager::runCheckersOnEndOfTranslationUnit( 715 const TranslationUnitDecl *TU, 716 AnalysisManager &mgr, 717 BugReporter &BR) { 718 for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) 719 EndOfTranslationUnitChecker(TU, mgr, BR); 720 } 721 722 void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out, 723 ProgramStateRef State, 724 const char *NL, 725 unsigned int Space, 726 bool IsDot) const { 727 Indent(Out, Space, IsDot) << "\"checker_messages\": "; 728 729 // Create a temporary stream to see whether we have any message. 730 SmallString<1024> TempBuf; 731 llvm::raw_svector_ostream TempOut(TempBuf); 732 unsigned int InnerSpace = Space + 2; 733 734 // Create the new-line in JSON with enough space. 735 SmallString<128> NewLine; 736 llvm::raw_svector_ostream NLOut(NewLine); 737 NLOut << "\", " << NL; // Inject the ending and a new line 738 Indent(NLOut, InnerSpace, IsDot) << "\""; // then begin the next message. 739 740 ++Space; 741 bool HasMessage = false; 742 743 // Store the last CheckerTag. 744 const void *LastCT = nullptr; 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 if (!HasMessage) { 753 Out << '[' << NL; 754 HasMessage = true; 755 } 756 757 LastCT = &CT; 758 TempBuf.clear(); 759 } 760 761 for (const auto &CT : CheckerTags) { 762 // See whether the current checker has a message. 763 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/""); 764 765 if (TempBuf.empty()) 766 continue; 767 768 Indent(Out, Space, IsDot) 769 << "{ \"checker\": \"" << CT.second->getCheckerName().getName() 770 << "\", \"messages\": [" << NL; 771 Indent(Out, InnerSpace, IsDot) 772 << '\"' << TempBuf.str().trim() << '\"' << NL; 773 Indent(Out, Space, IsDot) << "]}"; 774 775 if (&CT != LastCT) 776 Out << ','; 777 Out << NL; 778 779 TempBuf.clear(); 780 } 781 782 // It is the last element of the 'program_state' so do not add a comma. 783 if (HasMessage) 784 Indent(Out, --Space, IsDot) << "]"; 785 else 786 Out << "null"; 787 788 Out << NL; 789 } 790 791 //===----------------------------------------------------------------------===// 792 // Internal registration functions for AST traversing. 793 //===----------------------------------------------------------------------===// 794 795 void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 796 HandlesDeclFunc isForDeclFn) { 797 DeclCheckerInfo info = { checkfn, isForDeclFn }; 798 DeclCheckers.push_back(info); 799 } 800 801 void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 802 BodyCheckers.push_back(checkfn); 803 } 804 805 //===----------------------------------------------------------------------===// 806 // Internal registration functions for path-sensitive checking. 807 //===----------------------------------------------------------------------===// 808 809 void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 810 HandlesStmtFunc isForStmtFn) { 811 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 812 StmtCheckers.push_back(info); 813 } 814 815 void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 816 HandlesStmtFunc isForStmtFn) { 817 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 818 StmtCheckers.push_back(info); 819 } 820 821 void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 822 PreObjCMessageCheckers.push_back(checkfn); 823 } 824 825 void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { 826 ObjCMessageNilCheckers.push_back(checkfn); 827 } 828 829 void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 830 PostObjCMessageCheckers.push_back(checkfn); 831 } 832 833 void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { 834 PreCallCheckers.push_back(checkfn); 835 } 836 void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { 837 PostCallCheckers.push_back(checkfn); 838 } 839 840 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 841 LocationCheckers.push_back(checkfn); 842 } 843 844 void CheckerManager::_registerForBind(CheckBindFunc checkfn) { 845 BindCheckers.push_back(checkfn); 846 } 847 848 void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 849 EndAnalysisCheckers.push_back(checkfn); 850 } 851 852 void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { 853 BeginFunctionCheckers.push_back(checkfn); 854 } 855 856 void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { 857 EndFunctionCheckers.push_back(checkfn); 858 } 859 860 void CheckerManager::_registerForBranchCondition( 861 CheckBranchConditionFunc checkfn) { 862 BranchConditionCheckers.push_back(checkfn); 863 } 864 865 void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) { 866 NewAllocatorCheckers.push_back(checkfn); 867 } 868 869 void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { 870 LiveSymbolsCheckers.push_back(checkfn); 871 } 872 873 void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { 874 DeadSymbolsCheckers.push_back(checkfn); 875 } 876 877 void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { 878 RegionChangesCheckers.push_back(checkfn); 879 } 880 881 void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ 882 PointerEscapeCheckers.push_back(checkfn); 883 } 884 885 void CheckerManager::_registerForConstPointerEscape( 886 CheckPointerEscapeFunc checkfn) { 887 PointerEscapeCheckers.push_back(checkfn); 888 } 889 890 void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { 891 EvalAssumeCheckers.push_back(checkfn); 892 } 893 894 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { 895 EvalCallCheckers.push_back(checkfn); 896 } 897 898 void CheckerManager::_registerForEndOfTranslationUnit( 899 CheckEndOfTranslationUnit checkfn) { 900 EndOfTranslationUnitCheckers.push_back(checkfn); 901 } 902 903 //===----------------------------------------------------------------------===// 904 // Implementation details. 905 //===----------------------------------------------------------------------===// 906 907 const CheckerManager::CachedStmtCheckers & 908 CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 909 assert(S); 910 911 unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); 912 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); 913 if (CCI != CachedStmtCheckersMap.end()) 914 return CCI->second; 915 916 // Find the checkers that should run for this Stmt and cache them. 917 CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; 918 for (const auto &Info : StmtCheckers) 919 if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) 920 Checkers.push_back(Info.CheckFn); 921 return Checkers; 922 } 923