31#include "llvm/Support/ErrorHandling.h" 
   32#include "llvm/Support/FormatVariadic.h" 
   33#include "llvm/Support/TimeProfiler.h" 
   43#define DEBUG_TYPE "CoreEngine" 
   49                         "The # of times we reached the max number of steps.");
 
   50STAT_COUNTER(NumPathsExplored, 
"The # of paths explored by the analyzer.");
 
   71  llvm_unreachable(
"Unknown AnalyzerOptions::ExplorationStrategyKind");
 
 
   78      BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
 
 
   81  WList->setBlockCounter(
C);
 
   83    CTUWList->setBlockCounter(
C);
 
   90    assert(!G.getRoot() && 
"empty graph must not have a root node");
 
   95    assert(Entry->
empty() && 
"Entry block must be empty.");
 
   97    assert(Entry->
succ_size() == 1 && 
"Entry block must have 1 successor.");
 
  100    FunctionSummaries->markVisitedBasicBlock(Entry->
getBlockID(),
 
  112    setBlockCounter(BCounterFactory.GetEmptyCounter());
 
  115      InitState = ExprEng.getInitialState(L);
 
  118    ExplodedNode *Node = G.getNode(StartLoc, InitState, 
false, &IsNew);
 
  120    G.designateAsRoot(Node);
 
  124    ExprEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc);
 
  130  bool UnlimitedSteps = MaxSteps == 0;
 
  134  const unsigned PreReservationCap = 4000000;
 
  136    G.reserve(std::min(MaxSteps, PreReservationCap));
 
  138  auto ProcessWList = [
this, UnlimitedSteps](
unsigned MaxSteps) {
 
  139    unsigned Steps = MaxSteps;
 
  140    while (WList->hasWork()) {
 
  141      if (!UnlimitedSteps) {
 
  143          NumReachedMaxSteps++;
 
  161    return MaxSteps - Steps;
 
  163  const unsigned STUSteps = ProcessWList(MaxSteps);
 
  166    NumSTUSteps += STUSteps;
 
  167    const unsigned MinCTUSteps =
 
  168        this->ExprEng.getAnalysisManager().options.CTUMaxNodesMin;
 
  170        this->ExprEng.getAnalysisManager().options.CTUMaxNodesPercentage;
 
  171    unsigned MaxCTUSteps = std::max(STUSteps * Pct / 100, MinCTUSteps);
 
  173    WList = std::move(CTUWList);
 
  174    const unsigned CTUSteps = ProcessWList(MaxCTUSteps);
 
  175    NumCTUSteps += CTUSteps;
 
  178  ExprEng.processEndWorklist();
 
  179  return WList->hasWork();
 
 
  183  if (llvm::timeTraceProfilerEnabled()) {
 
  184    return llvm::formatv(
"dispatchWorkItem {0}",
 
 
  194  assert(llvm::timeTraceProfilerEnabled());
 
  195  std::string Detail = 
"";
 
  197    if (
const Stmt *S = SP->getStmt())
 
  198      Detail = S->getStmtClassName();
 
  200  auto SLoc = 
Loc.getSourceLocation();
 
  202    return llvm::TimeTraceMetadata{std::move(Detail), 
""};
 
  207  auto Line = 
SM.getPresumedLineNumber(*SLoc);
 
  208  auto Fname = 
SM.getFilename(*SLoc);
 
  209  return llvm::TimeTraceMetadata{std::move(Detail), Fname.str(),
 
  210                                 static_cast<int>(
Line)};
 
 
  230      assert(
false && 
"BlockExit location never occur in forward analysis.");
 
  238      ExprEng.processCallExit(Pred);
 
  243             "Assume epsilon has exactly one predecessor by construction");
 
 
  278          return "Virtual base initialization skipped because " 
  279                 "it has already been handled by the most derived class";
 
  285    Pred = Bldr.generateNode(P, Pred->
getState(), Pred);
 
  293           "EXIT block cannot contain Stmts.");
 
  299      if (std::optional<CFGStmt> LastStmt = LastElement.
getAs<
CFGStmt>()) {
 
  300        RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
 
  301      } 
else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
 
  302                     LastElement.
getAs<CFGAutomaticObjDtor>()) {
 
  303        RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
 
  307    ExplodedNodeSet CheckerNodes;
 
  309    ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, Pred, CheckerNodes);
 
  312    for (ExplodedNode *P : CheckerNodes) {
 
  313      ExprEng.processEndOfFunction(BuilderCtx, P, RS);
 
  322  ExplodedNodeSet DstNodes;
 
  323  NodeBuilderWithSinks 
NodeBuilder(Pred, DstNodes, BuilderCtx, BE);
 
  324  ExprEng.processCFGBlockEntrance(L, 
NodeBuilder, Pred);
 
  331  ExplodedNodeSet CheckerNodes;
 
  332  for (
auto *N : DstNodes) {
 
  333    ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, N, CheckerNodes);
 
  340void CoreEngine::HandleBlockEntrance(
const BlockEntrance &L,
 
  345  BlockCounter Counter = WList->getBlockCounter();
 
  346  Counter = BCounterFactory.IncrementCount(Counter, LC->
getStackFrame(),
 
  348  setBlockCounter(Counter);
 
  353    ExprEng.processCFGElement(*E, Pred, 0, &Ctx);
 
  355    HandleBlockExit(L.
getBlock(), Pred);
 
  358void CoreEngine::HandleBlockExit(
const CFGBlock * B, 
ExplodedNode *Pred) {
 
  360    switch (Term->getStmtClass()) {
 
  362        llvm_unreachable(
"Analysis for this terminator not implemented.");
 
  364      case Stmt::CXXBindTemporaryExprClass:
 
  365        HandleCleanupTemporaryBranch(
 
  370      case Stmt::DeclStmtClass:
 
  374      case Stmt::BinaryOperatorClass: 
 
  378      case Stmt::BinaryConditionalOperatorClass:
 
  379      case Stmt::ConditionalOperatorClass:
 
  387      case Stmt::ChooseExprClass:
 
  391      case Stmt::CXXTryStmtClass:
 
  395             et = B->
succ_end(); it != et; ++it) {
 
  396          if (
const CFGBlock *succ = *it) {
 
  403      case Stmt::DoStmtClass:
 
  404        HandleBranch(
cast<DoStmt>(Term)->getCond(), Term, B, Pred);
 
  407      case Stmt::CXXForRangeStmtClass:
 
  411      case Stmt::ForStmtClass:
 
  415      case Stmt::SEHLeaveStmtClass:
 
  416      case Stmt::ContinueStmtClass:
 
  417      case Stmt::BreakStmtClass:
 
  418      case Stmt::GotoStmtClass:
 
  421      case Stmt::IfStmtClass:
 
  422        HandleBranch(
cast<IfStmt>(Term)->getCond(), Term, B, Pred);
 
  425      case Stmt::IndirectGotoStmtClass: {
 
  433        ExprEng.processIndirectGoto(builder);
 
  437      case Stmt::ObjCForCollectionStmtClass:
 
  448        HandleBranch(Term, Term, B, Pred);
 
  451      case Stmt::SwitchStmtClass: {
 
  455        ExprEng.processSwitch(builder);
 
  459      case Stmt::WhileStmtClass:
 
  463      case Stmt::GCCAsmStmtClass:
 
  464        assert(
cast<GCCAsmStmt>(Term)->isAsmGoto() && 
"Encountered GCCAsmStmt without labels");
 
  471    HandleVirtualBaseBranch(B, Pred);
 
  476         "Blocks with no terminator should have at most 1 successor.");
 
  482void CoreEngine::HandleCallEnter(
const CallEnter &CE, 
ExplodedNode *Pred) {
 
  484  ExprEng.processCallEnter(BuilderCtx, CE, Pred);
 
  487void CoreEngine::HandleBranch(
const Stmt *
Cond, 
const Stmt *Term,
 
  494                        getCompletedIterationCount(B, Pred));
 
  499void CoreEngine::HandleCleanupTemporaryBranch(
const CXXBindTemporaryExpr *BTE,
 
  505  ExprEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->
succ_begin()),
 
  511void CoreEngine::HandleStaticInit(
const DeclStmt *DS, 
const CFGBlock *B,
 
  516  ExprEng.processStaticInitializer(DS, Ctx, Pred, Dst,
 
  522void CoreEngine::HandlePostStmt(
const CFGBlock *B, 
unsigned StmtIdx,
 
  527  if (StmtIdx == B->
size())
 
  528    HandleBlockExit(B, Pred);
 
  531    ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
 
  535void CoreEngine::HandleVirtualBaseBranch(
const CFGBlock *B,
 
  538  if (
const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
 
  540    switch (CallerCtor->getConstructionKind()) {
 
  544      HandleBlockEdge(Loc, Pred);
 
  554  BlockEdge Loc(B, *(B->
succ_begin() + 1), LCtx);
 
  555  HandleBlockEdge(Loc, Pred);
 
  560void CoreEngine::generateNode(
const ProgramPoint &
Loc,
 
  565  ExplodedNode *Node = G.getNode(Loc, State, 
false, &IsNew);
 
  570  if (IsNew) WList->enqueue(Node);
 
  582    WList->enqueue(N, 
Block, Idx);
 
  590    WList->enqueue(N, 
Block, Idx+1);
 
  595    WList->enqueue(N, 
Block, Idx);
 
  600    WList->enqueue(N, 
Block, Idx+1);
 
  611    WList->enqueue(N, 
Block, Idx+1);
 
  620    WList->enqueue(Succ, 
Block, Idx+1);
 
 
  634  return isNew ? Node : 
nullptr;
 
  637std::optional<unsigned>
 
  638CoreEngine::getCompletedIterationCount(
const CFGBlock *B,
 
  642  unsigned BlockCount =
 
  647    assert(BlockCount >= 1 &&
 
  648           "Block count of currently analyzed block must be >= 1");
 
  649    return BlockCount - 1;
 
  662  for (
const auto I : 
Set)
 
 
  668  for (
const auto I : 
Set)
 
 
  673  for (
auto *I : 
Set) {
 
  675    if (I->getLocationContext()->getParent()) {
 
  676      I = generateCallExitBeginNode(I, RS);
 
 
  687void NodeBuilder::anchor() {}
 
  708void NodeBuilderWithSinks::anchor() {}
 
  713      EnclosingBldr->addNodes(I);
 
 
  716void BranchNodeBuilder::anchor() {}
 
  721  const CFGBlock *Dst = Branch ? DstT : DstF;
 
 
  746    Eng.WList->enqueue(Succ);
 
 
  762  Eng.WList->enqueue(Succ);
 
 
  770  assert(Src->succ_rbegin() != Src->succ_rend());
 
  780      Eng.G.getNode(
BlockEdge(Src, DefaultBlock, Pred->getLocationContext()),
 
  788    Eng.WList->enqueue(Succ);
 
 
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static std::unique_ptr< WorkList > generateWorkList(AnalyzerOptions &Opts)
ALWAYS_ENABLED_STATISTIC(NumReachedMaxSteps, "The # of times we reached the max number of steps.")
static std::string timeTraceScopeName(const ProgramPoint &Loc)
static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)
static Decl::Kind getKind(const Decl *D)
#define STAT_COUNTER(VARNAME, DESC)
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
SourceManager & getSourceManager()
ASTContext & getASTContext() const
Stores options for the analyzer from the command line.
ExplorationStrategyKind getExplorationStrategy() const
const CFGBlock * getSrc() const
const CFGBlock * getDst() const
std::optional< CFGElement > getFirstElement() const
const CFGBlock * getBlock() const
Represents a single basic block in a source-level CFG.
succ_reverse_iterator succ_rbegin()
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
unsigned getBlockID() const
AdjacentBlocks::const_iterator const_succ_iterator
unsigned succ_size() const
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
const Stmt * getStmt() const
bool isVirtualBaseBranch() const
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents a point when we begin processing an inlined call.
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
Represents a point when we start the call exit sequence (for inlined call).
Represents a point when we finish the call exit sequence (for inlined call).
This is a meta program point, which should be skipped by all the diagnostic reasoning etc.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const StackFrameContext * getStackFrame() const
Represents a point when we exit a loop.
Represents a program point just after an implicit call event.
static StringRef getProgramPointKindName(Kind K)
ProgramPoint withTag(const ProgramPointTag *tag) const
Create a new ProgramPoint object that is the same as the original except for using the specified tag ...
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
const LocationContext * getLocationContext() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
const Stmt * getCallSite() const
Stmt - This represents one statement.
An abstract data type used to count the number of times a given block has been visited along a path a...
unsigned getNumVisited(const StackFrameContext *CallSite, unsigned BlockID) const
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
friend class SwitchNodeBuilder
CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts)
Construct a CoreEngine object to analyze the provided CFG.
DataTag::Factory & getDataTags()
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
void dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc, const WorkListUnit &WU)
Dispatch the work list item based on the given location information.
friend class IndirectGotoNodeBuilder
friend class NodeBuilderContext
bool ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS)
enqueue the nodes corresponding to the end of function onto the end of path / work list.
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
ExplodedNode * getNode(const ProgramPoint &L, ProgramStateRef State, bool IsSink=false, bool *IsNew=nullptr)
Retrieve the node associated with a (Location, State) pair, where the 'Location' is a ProgramPoint in...
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
bool hasSinglePred() const
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
const CFGBlock * getBlock() const
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
This is the simplest builder which generates nodes in the ExplodedGraph.
const NodeBuilderContext & C
ExplodedNodeSet & Frontier
The frontier set - a set of nodes which need to be propagated after the builder dies.
ExplodedNode * generateNodeImpl(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
While alive, includes the current analysis stack in a crash trace.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
~StmtNodeBuilder() override
const CFGBlock * getBlock() const
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, bool isSink=false)
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
ExplodedNode * getNode() const
Returns the node associated with the worklist unit.
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityLocationQueue()
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityQueue()
static std::unique_ptr< WorkList > makeBFSBlockDFSContents()
static std::unique_ptr< WorkList > makeBFS()
static std::unique_ptr< WorkList > makeDFS()
static std::unique_ptr< WorkList > makeUnexploredFirst()
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
U cast(CodeGen::Address addr)
@ UnexploredFirstLocationQueue