brintos

brintos / llvm-project-archived public Read only

0
0
Text · 36.7 KiB · 8ee4832 Raw
997 lines · cpp
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-exception6//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/ErrorHandling.h"28#include "llvm/Support/FormatVariadic.h"29#include "llvm/Support/TimeProfiler.h"30#include <cassert>31#include <optional>32#include <vector>33 34using namespace clang;35using namespace ento;36 37bool CheckerManager::hasPathSensitiveCheckers() const {38  const auto IfAnyAreNonEmpty = [](const auto &... Callbacks) -> bool {39    return (!Callbacks.empty() || ...);40  };41  return IfAnyAreNonEmpty(42      StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers,43      PostObjCMessageCheckers, PreCallCheckers, PostCallCheckers,44      LocationCheckers, BindCheckers, BlockEntranceCheckers,45      EndAnalysisCheckers, BeginFunctionCheckers, EndFunctionCheckers,46      BranchConditionCheckers, NewAllocatorCheckers, LiveSymbolsCheckers,47      DeadSymbolsCheckers, RegionChangesCheckers, PointerEscapeCheckers,48      EvalAssumeCheckers, EvalCallCheckers, EndOfTranslationUnitCheckers);49}50 51void CheckerManager::reportInvalidCheckerOptionValue(52    const CheckerFrontend *Checker, StringRef OptionName,53    StringRef ExpectedValueDesc) const {54 55  getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input)56      << (llvm::Twine(Checker->getName()) + ":" + OptionName).str()57      << ExpectedValueDesc;58}59 60//===----------------------------------------------------------------------===//61// Functions for running checkers for AST traversing..62//===----------------------------------------------------------------------===//63 64void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,65                                          BugReporter &BR) {66  assert(D);67 68  unsigned DeclKind = D->getKind();69  auto [CCI, Inserted] = CachedDeclCheckersMap.try_emplace(DeclKind);70  CachedDeclCheckers *checkers = &(CCI->second);71  if (Inserted) {72    // Find the checkers that should run for this Decl and cache them.73    for (const auto &info : DeclCheckers)74      if (info.IsForDeclFn(D))75        checkers->push_back(info.CheckFn);76  }77 78  assert(checkers);79  for (const auto &checker : *checkers)80    checker(D, mgr, BR);81}82 83void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,84                                          BugReporter &BR) {85  assert(D && D->hasBody());86 87  for (const auto &BodyChecker : BodyCheckers)88    BodyChecker(D, mgr, BR);89}90 91//===----------------------------------------------------------------------===//92// Functions for running checkers for path-sensitive checking.93//===----------------------------------------------------------------------===//94 95template <typename CHECK_CTX>96static void expandGraphWithCheckers(CHECK_CTX checkCtx,97                                    ExplodedNodeSet &Dst,98                                    const ExplodedNodeSet &Src) {99  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();100  if (Src.empty())101    return;102 103  typename CHECK_CTX::CheckersTy::const_iterator104      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();105  if (I == E) {106    Dst.insert(Src);107    return;108  }109 110  ExplodedNodeSet Tmp1, Tmp2;111  const ExplodedNodeSet *PrevSet = &Src;112 113  for (; I != E; ++I) {114    ExplodedNodeSet *CurrSet = nullptr;115    if (I+1 == E)116      CurrSet = &Dst;117    else {118      CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;119      CurrSet->clear();120    }121 122    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);123    for (const auto &NI : *PrevSet)124      checkCtx.runChecker(*I, B, NI);125 126    // If all the produced transitions are sinks, stop.127    if (CurrSet->empty())128      return;129 130    // Update which NodeSet is the current one.131    PrevSet = CurrSet;132  }133}134 135namespace {136 137std::string checkerScopeName(StringRef Name, const CheckerBackend *Checker) {138  if (!llvm::timeTraceProfilerEnabled())139    return "";140  StringRef CheckerTag = Checker ? Checker->getDebugTag() : "<unknown>";141  return (Name + ":" + CheckerTag).str();142}143 144  struct CheckStmtContext {145    using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>;146 147    bool IsPreVisit;148    const CheckersTy &Checkers;149    const Stmt *S;150    ExprEngine &Eng;151    bool WasInlined;152 153    CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,154                     const Stmt *s, ExprEngine &eng, bool wasInlined = false)155        : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),156          WasInlined(wasInlined) {}157 158    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }159    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }160 161    void runChecker(CheckerManager::CheckStmtFunc checkFn,162                    NodeBuilder &Bldr, ExplodedNode *Pred) {163      llvm::TimeTraceScope TimeScope(checkerScopeName("Stmt", checkFn.Checker));164      // FIXME: Remove respondsToCallback from CheckerContext;165      ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :166                                           ProgramPoint::PostStmtKind;167      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,168                                Pred->getLocationContext(), checkFn.Checker);169      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);170      checkFn(S, C);171    }172  };173 174} // namespace175 176/// Run checkers for visiting Stmts.177void CheckerManager::runCheckersForStmt(bool isPreVisit,178                                        ExplodedNodeSet &Dst,179                                        const ExplodedNodeSet &Src,180                                        const Stmt *S,181                                        ExprEngine &Eng,182                                        bool WasInlined) {183  CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit),184                     S, Eng, WasInlined);185  llvm::TimeTraceScope TimeScope(186      isPreVisit ? "CheckerManager::runCheckersForStmt (Pre)"187                 : "CheckerManager::runCheckersForStmt (Post)");188  expandGraphWithCheckers(C, Dst, Src);189}190 191namespace {192 193  struct CheckObjCMessageContext {194    using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>;195 196    ObjCMessageVisitKind Kind;197    bool WasInlined;198    const CheckersTy &Checkers;199    const ObjCMethodCall &Msg;200    ExprEngine &Eng;201 202    CheckObjCMessageContext(ObjCMessageVisitKind visitKind,203                            const CheckersTy &checkers,204                            const ObjCMethodCall &msg, ExprEngine &eng,205                            bool wasInlined)206        : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg),207          Eng(eng) {}208 209    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }210    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }211 212    void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,213                    NodeBuilder &Bldr, ExplodedNode *Pred) {214      llvm::TimeTraceScope TimeScope(215          checkerScopeName("ObjCMsg", checkFn.Checker));216      bool IsPreVisit;217 218      switch (Kind) {219        case ObjCMessageVisitKind::Pre:220          IsPreVisit = true;221          break;222        case ObjCMessageVisitKind::MessageNil:223        case ObjCMessageVisitKind::Post:224          IsPreVisit = false;225          break;226      }227 228      const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);229      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);230 231      checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);232    }233  };234 235} // namespace236 237/// Run checkers for visiting obj-c messages.238void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,239                                               ExplodedNodeSet &Dst,240                                               const ExplodedNodeSet &Src,241                                               const ObjCMethodCall &msg,242                                               ExprEngine &Eng,243                                               bool WasInlined) {244  const auto &checkers = getObjCMessageCheckers(visitKind);245  CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);246  llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForObjCMessage");247  expandGraphWithCheckers(C, Dst, Src);248}249 250const std::vector<CheckerManager::CheckObjCMessageFunc> &251CheckerManager::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 264namespace {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      llvm::TimeTraceScope TimeScope(checkerScopeName("Call", checkFn.Checker));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} // namespace296 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 ? PreCallCheckers306                                : PostCallCheckers,307                     Call, Eng, WasInlined);308  llvm::TimeTraceScope TimeScope(309      isPreVisit ? "CheckerManager::runCheckersForCallEvent (Pre)"310                 : "CheckerManager::runCheckersForCallEvent (Post)");311  expandGraphWithCheckers(C, Dst, Src);312}313 314namespace {315 316  struct CheckLocationContext {317    using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>;318 319    const CheckersTy &Checkers;320    SVal Loc;321    bool IsLoad;322    const Stmt *NodeEx; /* Will become a CFGStmt */323    const Stmt *BoundEx;324    ExprEngine &Eng;325 326    CheckLocationContext(const CheckersTy &checkers,327                         SVal loc, bool isLoad, const Stmt *NodeEx,328                         const Stmt *BoundEx,329                         ExprEngine &eng)330        : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx),331          BoundEx(BoundEx), Eng(eng) {}332 333    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }334    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }335 336    void runChecker(CheckerManager::CheckLocationFunc checkFn,337                    NodeBuilder &Bldr, ExplodedNode *Pred) {338      llvm::TimeTraceScope TimeScope(checkerScopeName("Loc", checkFn.Checker));339      ProgramPoint::Kind K =  IsLoad ? ProgramPoint::PreLoadKind :340                                       ProgramPoint::PreStoreKind;341      const ProgramPoint &L =342        ProgramPoint::getProgramPoint(NodeEx, K,343                                      Pred->getLocationContext(),344                                      checkFn.Checker);345      CheckerContext C(Bldr, Eng, Pred, L);346      checkFn(Loc, IsLoad, BoundEx, C);347    }348  };349 350} // namespace351 352/// Run checkers for load/store of a location.353 354void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,355                                            const ExplodedNodeSet &Src,356                                            SVal location, bool isLoad,357                                            const Stmt *NodeEx,358                                            const Stmt *BoundEx,359                                            ExprEngine &Eng) {360  CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx,361                         BoundEx, Eng);362  llvm::TimeTraceScope TimeScope(363      isLoad ? "CheckerManager::runCheckersForLocation (Load)"364             : "CheckerManager::runCheckersForLocation (Store)");365  expandGraphWithCheckers(C, Dst, Src);366}367 368namespace {369 370  struct CheckBindContext {371    using CheckersTy = std::vector<CheckerManager::CheckBindFunc>;372 373    const CheckersTy &Checkers;374    SVal Loc;375    SVal Val;376    const Stmt *S;377    ExprEngine &Eng;378    const ProgramPoint &PP;379    bool AtDeclInit;380 381    CheckBindContext(const CheckersTy &checkers, SVal loc, SVal val,382                     const Stmt *s, bool AtDeclInit, ExprEngine &eng,383                     const ProgramPoint &pp)384        : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp),385          AtDeclInit(AtDeclInit) {}386 387    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }388    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }389 390    void runChecker(CheckerManager::CheckBindFunc checkFn,391                    NodeBuilder &Bldr, ExplodedNode *Pred) {392      llvm::TimeTraceScope TimeScope(checkerScopeName("Bind", checkFn.Checker));393      const ProgramPoint &L = PP.withTag(checkFn.Checker);394      CheckerContext C(Bldr, Eng, Pred, L);395 396      checkFn(Loc, Val, S, AtDeclInit, C);397    }398  };399 400  llvm::TimeTraceMetadata getTimeTraceBindMetadata(SVal Val) {401    assert(llvm::timeTraceProfilerEnabled());402    std::string Name;403    llvm::raw_string_ostream OS(Name);404    Val.dumpToStream(OS);405    return llvm::TimeTraceMetadata{OS.str(), ""};406  }407 408} // namespace409 410/// Run checkers for binding of a value to a location.411void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,412                                        const ExplodedNodeSet &Src,413                                        SVal location, SVal val, const Stmt *S,414                                        bool AtDeclInit, ExprEngine &Eng,415                                        const ProgramPoint &PP) {416  CheckBindContext C(BindCheckers, location, val, S, AtDeclInit, Eng, PP);417  llvm::TimeTraceScope TimeScope{418      "CheckerManager::runCheckersForBind",419      [&val]() { return getTimeTraceBindMetadata(val); }};420  expandGraphWithCheckers(C, Dst, Src);421}422 423namespace {424struct CheckBlockEntranceContext {425  using CheckBlockEntranceFunc = CheckerManager::CheckBlockEntranceFunc;426  using CheckersTy = std::vector<CheckBlockEntranceFunc>;427 428  const CheckersTy &Checkers;429  const BlockEntrance &Entrance;430  ExprEngine &Eng;431 432  CheckBlockEntranceContext(const CheckersTy &Checkers,433                            const BlockEntrance &Entrance, ExprEngine &Eng)434      : Checkers(Checkers), Entrance(Entrance), Eng(Eng) {}435 436  auto checkers_begin() const { return Checkers.begin(); }437  auto checkers_end() const { return Checkers.end(); }438 439  void runChecker(CheckBlockEntranceFunc CheckFn, NodeBuilder &Bldr,440                  ExplodedNode *Pred) {441    llvm::TimeTraceScope TimeScope(442        checkerScopeName("BlockEntrance", CheckFn.Checker));443    CheckerContext C(Bldr, Eng, Pred, Entrance.withTag(CheckFn.Checker));444    CheckFn(Entrance, C);445  }446};447 448} // namespace449 450void CheckerManager::runCheckersForBlockEntrance(ExplodedNodeSet &Dst,451                                                 const ExplodedNodeSet &Src,452                                                 const BlockEntrance &Entrance,453                                                 ExprEngine &Eng) const {454  CheckBlockEntranceContext C(BlockEntranceCheckers, Entrance, Eng);455  llvm::TimeTraceScope TimeScope{"CheckerManager::runCheckersForBlockEntrance"};456  expandGraphWithCheckers(C, Dst, Src);457}458 459void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,460                                               BugReporter &BR,461                                               ExprEngine &Eng) {462  for (const auto &EndAnalysisChecker : EndAnalysisCheckers)463    EndAnalysisChecker(G, BR, Eng);464}465 466namespace {467 468struct CheckBeginFunctionContext {469  using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>;470 471  const CheckersTy &Checkers;472  ExprEngine &Eng;473  const ProgramPoint &PP;474 475  CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng,476                            const ProgramPoint &PP)477      : Checkers(Checkers), Eng(Eng), PP(PP) {}478 479  CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }480  CheckersTy::const_iterator checkers_end() { return Checkers.end(); }481 482  void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn,483                  NodeBuilder &Bldr, ExplodedNode *Pred) {484    llvm::TimeTraceScope TimeScope(checkerScopeName("Begin", checkFn.Checker));485    const ProgramPoint &L = PP.withTag(checkFn.Checker);486    CheckerContext C(Bldr, Eng, Pred, L);487 488    checkFn(C);489  }490};491 492} // namespace493 494void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst,495                                                 const BlockEdge &L,496                                                 ExplodedNode *Pred,497                                                 ExprEngine &Eng) {498  ExplodedNodeSet Src;499  Src.insert(Pred);500  CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L);501  llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForBeginFunction");502  expandGraphWithCheckers(C, Dst, Src);503}504 505/// Run checkers for end of path.506// Note, We do not chain the checker output (like in expandGraphWithCheckers)507// for this callback since end of path nodes are expected to be final.508void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,509                                               ExplodedNodeSet &Dst,510                                               ExplodedNode *Pred,511                                               ExprEngine &Eng,512                                               const ReturnStmt *RS) {513  // We define the builder outside of the loop because if at least one checker514  // creates a successor for Pred, we do not need to generate an515  // autotransition for it.516  NodeBuilder Bldr(Pred, Dst, BC);517  for (const auto &checkFn : EndFunctionCheckers) {518    const ProgramPoint &L =519        FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);520    CheckerContext C(Bldr, Eng, Pred, L);521    llvm::TimeTraceScope TimeScope(checkerScopeName("End", checkFn.Checker));522    checkFn(RS, C);523  }524}525 526namespace {527 528  struct CheckBranchConditionContext {529    using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>;530 531    const CheckersTy &Checkers;532    const Stmt *Condition;533    ExprEngine &Eng;534 535    CheckBranchConditionContext(const CheckersTy &checkers,536                                const Stmt *Cond, ExprEngine &eng)537        : Checkers(checkers), Condition(Cond), Eng(eng) {}538 539    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }540    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }541 542    void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,543                    NodeBuilder &Bldr, ExplodedNode *Pred) {544      llvm::TimeTraceScope TimeScope(545          checkerScopeName("BranchCond", checkFn.Checker));546      ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),547                                     checkFn.Checker);548      CheckerContext C(Bldr, Eng, Pred, L);549      checkFn(Condition, C);550    }551  };552 553} // namespace554 555/// Run checkers for branch condition.556void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition,557                                                   ExplodedNodeSet &Dst,558                                                   ExplodedNode *Pred,559                                                   ExprEngine &Eng) {560  ExplodedNodeSet Src;561  Src.insert(Pred);562  CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);563  llvm::TimeTraceScope TimeScope(564      "CheckerManager::runCheckersForBranchCondition");565  expandGraphWithCheckers(C, Dst, Src);566}567 568namespace {569 570  struct CheckNewAllocatorContext {571    using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;572 573    const CheckersTy &Checkers;574    const CXXAllocatorCall &Call;575    bool WasInlined;576    ExprEngine &Eng;577 578    CheckNewAllocatorContext(const CheckersTy &Checkers,579                             const CXXAllocatorCall &Call, bool WasInlined,580                             ExprEngine &Eng)581        : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}582 583    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }584    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }585 586    void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,587                    NodeBuilder &Bldr, ExplodedNode *Pred) {588      llvm::TimeTraceScope TimeScope(589          checkerScopeName("Allocator", checkFn.Checker));590      ProgramPoint L = PostAllocatorCall(591          Call.getOriginExpr(), Pred->getLocationContext(), checkFn.Checker);592      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);593      checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),594              C);595    }596  };597 598} // namespace599 600void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call,601                                                ExplodedNodeSet &Dst,602                                                ExplodedNode *Pred,603                                                ExprEngine &Eng,604                                                bool WasInlined) {605  ExplodedNodeSet Src;606  Src.insert(Pred);607  CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);608  llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForNewAllocator");609  expandGraphWithCheckers(C, Dst, Src);610}611 612/// Run checkers for live symbols.613void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,614                                               SymbolReaper &SymReaper) {615  for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers)616    LiveSymbolsChecker(state, SymReaper);617}618 619namespace {620 621  struct CheckDeadSymbolsContext {622    using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>;623 624    const CheckersTy &Checkers;625    SymbolReaper &SR;626    const Stmt *S;627    ExprEngine &Eng;628    ProgramPoint::Kind ProgarmPointKind;629 630    CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,631                            const Stmt *s, ExprEngine &eng,632                            ProgramPoint::Kind K)633        : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {}634 635    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }636    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }637 638    void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,639                    NodeBuilder &Bldr, ExplodedNode *Pred) {640      llvm::TimeTraceScope TimeScope(641          checkerScopeName("DeadSymbols", checkFn.Checker));642      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,643                                Pred->getLocationContext(), checkFn.Checker);644      CheckerContext C(Bldr, Eng, Pred, L);645 646      // Note, do not pass the statement to the checkers without letting them647      // differentiate if we ran remove dead bindings before or after the648      // statement.649      checkFn(SR, C);650    }651  };652 653} // namespace654 655/// Run checkers for dead symbols.656void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,657                                               const ExplodedNodeSet &Src,658                                               SymbolReaper &SymReaper,659                                               const Stmt *S,660                                               ExprEngine &Eng,661                                               ProgramPoint::Kind K) {662  CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K);663  llvm::TimeTraceScope TimeScope("CheckerManager::runCheckersForDeadSymbols");664  expandGraphWithCheckers(C, Dst, Src);665}666 667/// Run checkers for region changes.668ProgramStateRef669CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,670                                            const InvalidatedSymbols *invalidated,671                                            ArrayRef<const MemRegion *> ExplicitRegions,672                                            ArrayRef<const MemRegion *> Regions,673                                            const LocationContext *LCtx,674                                            const CallEvent *Call) {675  for (const auto &RegionChangesChecker : RegionChangesCheckers) {676    // If any checker declares the state infeasible (or if it starts that way),677    // bail out.678    if (!state)679      return nullptr;680    state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions,681                                 LCtx, Call);682  }683  return state;684}685 686/// Run checkers to process symbol escape event.687ProgramStateRef688CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,689                                   const InvalidatedSymbols &Escaped,690                                   const CallEvent *Call,691                                   PointerEscapeKind Kind,692                                   RegionAndSymbolInvalidationTraits *ETraits) {693  assert((Call != nullptr ||694          (Kind != PSK_DirectEscapeOnCall &&695           Kind != PSK_IndirectEscapeOnCall)) &&696         "Call must not be NULL when escaping on call");697  for (const auto &PointerEscapeChecker : PointerEscapeCheckers) {698    // If any checker declares the state infeasible (or if it starts that699    //  way), bail out.700    if (!State)701      return nullptr;702    State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits);703  }704  return State;705}706 707/// Run checkers for handling assumptions on symbolic values.708ProgramStateRef709CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,710                                         SVal Cond, bool Assumption) {711  for (const auto &EvalAssumeChecker : EvalAssumeCheckers) {712    // If any checker declares the state infeasible (or if it starts that way),713    // bail out.714    if (!state)715      return nullptr;716    state = EvalAssumeChecker(state, Cond, Assumption);717  }718  return state;719}720 721/// Run checkers for evaluating a call.722/// Only one checker will evaluate the call.723void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,724                                            const ExplodedNodeSet &Src,725                                            const CallEvent &Call,726                                            ExprEngine &Eng,727                                            const EvalCallOptions &CallOpts) {728  for (auto *const Pred : Src) {729    std::optional<StringRef> evaluatorChecker;730 731    ExplodedNodeSet checkDst;732    NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());733 734    ProgramStateRef State = Pred->getState();735    CallEventRef<> UpdatedCall = Call.cloneWithState(State);736 737    // Check if any of the EvalCall callbacks can evaluate the call.738    for (const auto &EvalCallChecker : EvalCallCheckers) {739      // TODO: Support the situation when the call doesn't correspond740      // to any Expr.741      ProgramPoint L = ProgramPoint::getProgramPoint(742          UpdatedCall->getOriginExpr(), ProgramPoint::PostStmtKind,743          Pred->getLocationContext(), EvalCallChecker.Checker);744      bool evaluated = false;745      { // CheckerContext generates transitions (populates checkDest) on746        // destruction, so introduce the scope to make sure it gets properly747        // populated.748        CheckerContext C(B, Eng, Pred, L);749        evaluated = EvalCallChecker(*UpdatedCall, C);750      }751#ifndef NDEBUG752      if (evaluated && evaluatorChecker) {753        const auto toString = [](const CallEvent &Call) -> std::string {754          std::string Buf;755          llvm::raw_string_ostream OS(Buf);756          Call.dump(OS);757          return Buf;758        };759        std::string AssertionMessage = llvm::formatv(760            "The '{0}' call has been already evaluated by the {1} checker, "761            "while the {2} checker also tried to evaluate the same call. At "762            "most one checker supposed to evaluate a call.",763            toString(Call), evaluatorChecker,764            EvalCallChecker.Checker->getDebugTag());765        llvm_unreachable(AssertionMessage.c_str());766      }767#endif768      if (evaluated) {769        evaluatorChecker = EvalCallChecker.Checker->getDebugTag();770        Dst.insert(checkDst);771#ifdef NDEBUG772        break; // on release don't check that no other checker also evals.773#endif774      }775    }776 777    // If none of the checkers evaluated the call, ask ExprEngine to handle it.778    if (!evaluatorChecker) {779      NodeBuilder B(Pred, Dst, Eng.getBuilderContext());780      Eng.defaultEvalCall(B, Pred, *UpdatedCall, CallOpts);781    }782  }783}784 785/// Run checkers for the entire Translation Unit.786void CheckerManager::runCheckersOnEndOfTranslationUnit(787                                                  const TranslationUnitDecl *TU,788                                                  AnalysisManager &mgr,789                                                  BugReporter &BR) {790  for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)791    EndOfTranslationUnitChecker(TU, mgr, BR);792}793 794void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out,795                                                  ProgramStateRef State,796                                                  const char *NL,797                                                  unsigned int Space,798                                                  bool IsDot) const {799  Indent(Out, Space, IsDot) << "\"checker_messages\": ";800 801  // Create a temporary stream to see whether we have any message.802  SmallString<1024> TempBuf;803  llvm::raw_svector_ostream TempOut(TempBuf);804  unsigned int InnerSpace = Space + 2;805 806  // Create the new-line in JSON with enough space.807  SmallString<128> NewLine;808  llvm::raw_svector_ostream NLOut(NewLine);809  NLOut << "\", " << NL;                     // Inject the ending and a new line810  Indent(NLOut, InnerSpace, IsDot) << "\"";  // then begin the next message.811 812  ++Space;813  bool HasMessage = false;814 815  // Store the last CheckerTag.816  const void *LastCT = nullptr;817  for (const auto &CT : CheckerTags) {818    // See whether the current checker has a message.819    CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");820 821    if (TempBuf.empty())822      continue;823 824    if (!HasMessage) {825      Out << '[' << NL;826      HasMessage = true;827    }828 829    LastCT = &CT;830    TempBuf.clear();831  }832 833  for (const auto &CT : CheckerTags) {834    // See whether the current checker has a message.835    CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");836 837    if (TempBuf.empty())838      continue;839 840    Indent(Out, Space, IsDot) << "{ \"checker\": \"" << CT.second->getDebugTag()841                              << "\", \"messages\": [" << NL;842    Indent(Out, InnerSpace, IsDot)843        << '\"' << TempBuf.str().trim() << '\"' << NL;844    Indent(Out, Space, IsDot) << "]}";845 846    if (&CT != LastCT)847      Out << ',';848    Out << NL;849 850    TempBuf.clear();851  }852 853  // It is the last element of the 'program_state' so do not add a comma.854  if (HasMessage)855    Indent(Out, --Space, IsDot) << "]";856  else857    Out << "null";858 859  Out << NL;860}861 862//===----------------------------------------------------------------------===//863// Internal registration functions for AST traversing.864//===----------------------------------------------------------------------===//865 866void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,867                                      HandlesDeclFunc isForDeclFn) {868  DeclCheckerInfo info = { checkfn, isForDeclFn };869  DeclCheckers.push_back(info);870}871 872void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {873  BodyCheckers.push_back(checkfn);874}875 876//===----------------------------------------------------------------------===//877// Internal registration functions for path-sensitive checking.878//===----------------------------------------------------------------------===//879 880void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,881                                         HandlesStmtFunc isForStmtFn) {882  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };883  StmtCheckers.push_back(info);884}885 886void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,887                                          HandlesStmtFunc isForStmtFn) {888  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };889  StmtCheckers.push_back(info);890}891 892void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {893  PreObjCMessageCheckers.push_back(checkfn);894}895 896void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) {897  ObjCMessageNilCheckers.push_back(checkfn);898}899 900void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {901  PostObjCMessageCheckers.push_back(checkfn);902}903 904void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) {905  PreCallCheckers.push_back(checkfn);906}907void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) {908  PostCallCheckers.push_back(checkfn);909}910 911void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {912  LocationCheckers.push_back(checkfn);913}914 915void CheckerManager::_registerForBind(CheckBindFunc checkfn) {916  BindCheckers.push_back(checkfn);917}918 919void CheckerManager::_registerForBlockEntrance(CheckBlockEntranceFunc checkfn) {920  BlockEntranceCheckers.push_back(checkfn);921}922 923void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {924  EndAnalysisCheckers.push_back(checkfn);925}926 927void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) {928  BeginFunctionCheckers.push_back(checkfn);929}930 931void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) {932  EndFunctionCheckers.push_back(checkfn);933}934 935void CheckerManager::_registerForBranchCondition(936                                             CheckBranchConditionFunc checkfn) {937  BranchConditionCheckers.push_back(checkfn);938}939 940void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) {941  NewAllocatorCheckers.push_back(checkfn);942}943 944void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {945  LiveSymbolsCheckers.push_back(checkfn);946}947 948void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {949  DeadSymbolsCheckers.push_back(checkfn);950}951 952void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) {953  RegionChangesCheckers.push_back(checkfn);954}955 956void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){957  PointerEscapeCheckers.push_back(checkfn);958}959 960void CheckerManager::_registerForConstPointerEscape(961                                          CheckPointerEscapeFunc checkfn) {962  PointerEscapeCheckers.push_back(checkfn);963}964 965void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {966  EvalAssumeCheckers.push_back(checkfn);967}968 969void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {970  EvalCallCheckers.push_back(checkfn);971}972 973void CheckerManager::_registerForEndOfTranslationUnit(974                                            CheckEndOfTranslationUnit checkfn) {975  EndOfTranslationUnitCheckers.push_back(checkfn);976}977 978//===----------------------------------------------------------------------===//979// Implementation details.980//===----------------------------------------------------------------------===//981 982const CheckerManager::CachedStmtCheckers &983CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {984  assert(S);985 986  unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);987  auto [CCI, Inserted] = CachedStmtCheckersMap.try_emplace(Key);988  CachedStmtCheckers &Checkers = CCI->second;989  if (Inserted) {990    // Find the checkers that should run for this Stmt and cache them.991    for (const auto &Info : StmtCheckers)992      if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S))993        Checkers.push_back(Info.CheckFn);994  }995  return Checkers;996}997