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 32using namespace clang; 33using namespace ento; 34 35bool 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 53void 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 63void 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 76void 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 98void 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 110template <typename CHECK_CTX> 111static 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 150namespace { 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. 184void 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 195namespace { 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. 240void 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 251const std::vector<CheckerManager::CheckObjCMessageFunc> & 252CheckerManager::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 265namespace { 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. 298void 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 311namespace { 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 350void 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 361namespace { 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. 393void 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 402void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 403 BugReporter &BR, 404 ExprEngine &Eng) { 405 for (const auto &EndAnalysisChecker : EndAnalysisCheckers) 406 EndAnalysisChecker(G, BR, Eng); 407} 408 409namespace { 410 411struct 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 436void 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. 449void 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 466namespace { 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. 494void 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 504namespace { 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 534void 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. 546void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, 547 SymbolReaper &SymReaper) { 548 for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers) 549 LiveSymbolsChecker(state, SymReaper); 550} 551 552namespace { 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. 587void 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. 598ProgramStateRef 599CheckerManager::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. 617ProgramStateRef 618CheckerManager::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. 638ProgramStateRef 639CheckerManager::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. 653void 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 bool anyEvaluated = false; 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 assert(!(evaluated && anyEvaluated) 679 && "There are more than one checkers evaluating the call"); 680 if (evaluated) { 681 anyEvaluated = true; 682 Dst.insert(checkDst); 683#ifdef NDEBUG 684 break; // on release don't check that no other checker also evals. 685#endif 686 } 687 } 688 689 // If none of the checkers evaluated the call, ask ExprEngine to handle it. 690 if (!anyEvaluated) { 691 NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); 692 Eng.defaultEvalCall(B, Pred, Call, CallOpts); 693 } 694 } 695} 696 697/// Run checkers for the entire Translation Unit. 698void CheckerManager::runCheckersOnEndOfTranslationUnit( 699 const TranslationUnitDecl *TU, 700 AnalysisManager &mgr, 701 BugReporter &BR) { 702 for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) 703 EndOfTranslationUnitChecker(TU, mgr, BR); 704} 705 706void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out, 707 ProgramStateRef State, 708 const char *NL, 709 unsigned int Space, 710 bool IsDot) const { 711 Indent(Out, Space, IsDot) << "\"checker_messages\": "; 712 713 // Create a temporary stream to see whether we have any message. 714 SmallString<1024> TempBuf; 715 llvm::raw_svector_ostream TempOut(TempBuf); 716 unsigned int InnerSpace = Space + 2; 717 718 // Create the new-line in JSON with enough space. 719 SmallString<128> NewLine; 720 llvm::raw_svector_ostream NLOut(NewLine); 721 NLOut << "\", " << NL; // Inject the ending and a new line 722 Indent(NLOut, InnerSpace, IsDot) << "\""; // then begin the next message. 723 724 ++Space; 725 bool HasMessage = false; 726 727 // Store the last CheckerTag. 728 const void *LastCT = nullptr; 729 for (const auto &CT : CheckerTags) { 730 // See whether the current checker has a message. 731 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/""); 732 733 if (TempBuf.empty()) 734 continue; 735 736 if (!HasMessage) { 737 Out << '[' << NL; 738 HasMessage = true; 739 } 740 741 LastCT = &CT; 742 TempBuf.clear(); 743 } 744 745 for (const auto &CT : CheckerTags) { 746 // See whether the current checker has a message. 747 CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/""); 748 749 if (TempBuf.empty()) 750 continue; 751 752 Indent(Out, Space, IsDot) 753 << "{ \"checker\": \"" << CT.second->getCheckerName().getName() 754 << "\", \"messages\": [" << NL; 755 Indent(Out, InnerSpace, IsDot) 756 << '\"' << TempBuf.str().trim() << '\"' << NL; 757 Indent(Out, Space, IsDot) << "]}"; 758 759 if (&CT != LastCT) 760 Out << ','; 761 Out << NL; 762 763 TempBuf.clear(); 764 } 765 766 // It is the last element of the 'program_state' so do not add a comma. 767 if (HasMessage) 768 Indent(Out, --Space, IsDot) << "]"; 769 else 770 Out << "null"; 771 772 Out << NL; 773} 774 775//===----------------------------------------------------------------------===// 776// Internal registration functions for AST traversing. 777//===----------------------------------------------------------------------===// 778 779void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 780 HandlesDeclFunc isForDeclFn) { 781 DeclCheckerInfo info = { checkfn, isForDeclFn }; 782 DeclCheckers.push_back(info); 783} 784 785void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 786 BodyCheckers.push_back(checkfn); 787} 788 789//===----------------------------------------------------------------------===// 790// Internal registration functions for path-sensitive checking. 791//===----------------------------------------------------------------------===// 792 793void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 794 HandlesStmtFunc isForStmtFn) { 795 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 796 StmtCheckers.push_back(info); 797} 798 799void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 800 HandlesStmtFunc isForStmtFn) { 801 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 802 StmtCheckers.push_back(info); 803} 804 805void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 806 PreObjCMessageCheckers.push_back(checkfn); 807} 808 809void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { 810 ObjCMessageNilCheckers.push_back(checkfn); 811} 812 813void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 814 PostObjCMessageCheckers.push_back(checkfn); 815} 816 817void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { 818 PreCallCheckers.push_back(checkfn); 819} 820void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { 821 PostCallCheckers.push_back(checkfn); 822} 823 824void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 825 LocationCheckers.push_back(checkfn); 826} 827 828void CheckerManager::_registerForBind(CheckBindFunc checkfn) { 829 BindCheckers.push_back(checkfn); 830} 831 832void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 833 EndAnalysisCheckers.push_back(checkfn); 834} 835 836void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { 837 BeginFunctionCheckers.push_back(checkfn); 838} 839 840void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { 841 EndFunctionCheckers.push_back(checkfn); 842} 843 844void CheckerManager::_registerForBranchCondition( 845 CheckBranchConditionFunc checkfn) { 846 BranchConditionCheckers.push_back(checkfn); 847} 848 849void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) { 850 NewAllocatorCheckers.push_back(checkfn); 851} 852 853void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { 854 LiveSymbolsCheckers.push_back(checkfn); 855} 856 857void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { 858 DeadSymbolsCheckers.push_back(checkfn); 859} 860 861void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { 862 RegionChangesCheckers.push_back(checkfn); 863} 864 865void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ 866 PointerEscapeCheckers.push_back(checkfn); 867} 868 869void CheckerManager::_registerForConstPointerEscape( 870 CheckPointerEscapeFunc checkfn) { 871 PointerEscapeCheckers.push_back(checkfn); 872} 873 874void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { 875 EvalAssumeCheckers.push_back(checkfn); 876} 877 878void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { 879 EvalCallCheckers.push_back(checkfn); 880} 881 882void CheckerManager::_registerForEndOfTranslationUnit( 883 CheckEndOfTranslationUnit checkfn) { 884 EndOfTranslationUnitCheckers.push_back(checkfn); 885} 886 887//===----------------------------------------------------------------------===// 888// Implementation details. 889//===----------------------------------------------------------------------===// 890 891const CheckerManager::CachedStmtCheckers & 892CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 893 assert(S); 894 895 unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); 896 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); 897 if (CCI != CachedStmtCheckersMap.end()) 898 return CCI->second; 899 900 // Find the checkers that should run for this Stmt and cache them. 901 CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; 902 for (const auto &Info : StmtCheckers) 903 if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) 904 Checkers.push_back(Info.CheckFn); 905 return Checkers; 906} 907