Static Value-Flow Analysis
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Private Attributes | Friends | List of all members
SVF::AbstractInterpretation Class Reference

#include <AbstractInterpretation.h>

Inheritance diagram for SVF::AbstractInterpretation:
SVF::SemiSparseAbstractInterpretation SVF::FullSparseAbstractInterpretation

Classes

struct  AllocationSizeBounds
 

Public Types

enum  AESparsity { Dense , SemiSparse , Sparse }
 
enum  HandleRecur { TOP , WIDEN_ONLY , WIDEN_NARROW }
 
enum  AEFunEntryMode { MAIN , NO_MAIN }
 

Public Member Functions

virtual void runOnModule ()
 
virtual ~AbstractInterpretation ()
 Destructor.
 
void analyse ()
 Program entry.
 
void analyzeFromAllProgEntries ()
 Analyze all entry points (functions without callers)
 
FIFOWorkList< const FunObjVar * > collectProgEntryFuns ()
 Get all entry point functions (functions without callers)
 
void addDetector (std::unique_ptr< AEDetector > detector)
 
const SVFVar * getSVFVar (NodeID varId) const
 Retrieve SVFVar given its ID; asserts if no such variable exists.
 
virtual const AbstractValue & getAbsValue (const ValVar *var, const ICFGNode *node)
 
virtual const AbstractValue & getAbsValue (const ObjVar *var, const ICFGNode *node)
 
virtual const AbstractValue & getAbsValue (const SVFVar *var, const ICFGNode *node)
 
virtual bool hasAbsValue (const ValVar *var, const ICFGNode *node) const
 Side-effect-free existence check.
 
virtual bool hasAbsValue (const ObjVar *var, const ICFGNode *node) const
 
virtual bool hasAbsValue (const SVFVar *var, const ICFGNode *node) const
 
virtual void updateAbsValue (const ValVar *var, const AbstractValue &val, const ICFGNode *node)
 
virtual void updateAbsValue (const ObjVar *var, const AbstractValue &val, const ICFGNode *node)
 
virtual void updateAbsValue (const SVFVar *var, const AbstractValue &val, const ICFGNode *node)
 
AbstractState & getAbsState (const ICFGNode *node)
 
virtual void updateAbsState (const ICFGNode *node, const AbstractState &state)
 
virtual void joinStates (AbstractState &dst, const AbstractState &src)
 
bool hasAbsState (const ICFGNode *node)
 
void getAbsState (const Set< const ValVar * > &vars, AbstractState &result, const ICFGNode *node)
 
void getAbsState (const Set< const ObjVar * > &vars, AbstractState &result, const ICFGNode *node)
 
void getAbsState (const Set< const SVFVar * > &vars, AbstractState &result, const ICFGNode *node)
 
IntervalValue getGepElementIndex (const GepStmt *gep)
 
IntervalValue getGepByteOffset (const GepStmt *gep)
 
AddressValue getGepObjAddrs (const ValVar *pointer, IntervalValue offset)
 
virtual AbstractValue loadValue (const ValVar *pointer, const ICFGNode *node)
 Read memory through the pointer's address targets.
 
virtual void storeValue (const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
 
const SVFType * getPointeeElement (const ObjVar *var, const ICFGNode *node)
 
AllocationSizeBounds getAllocaInstByteSize (const AddrStmt *addr)
 
Map< const ICFGNode *, AbstractState > & getTrace ()
 
AbstractState & operator[] (const ICFGNode *node)
 

Static Public Member Functions

static AbstractInterpretation & getAEInstance ()
 

Protected Member Functions

 AbstractInterpretation ()
 
bool isStrongUpdate (const AddressValue &targets, const AbstractState &state) const
 
virtual AbstractState getFullCycleHeadState (const ICFGCycleWTO *cycle)
 
virtual bool widenCycleState (const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
 
virtual bool narrowCycleState (const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
 
virtual bool mergeStatesFromPredecessors (const ICFGNode *node)
 
bool isBranchEdgeFeasible (const IntraCFGEdge *edge, AbstractState &as)
 
bool applyBranchRefinement (const IntraCFGEdge *edge, AbstractState &as)
 
bool shouldApplyNarrowing (const FunObjVar *fun)
 Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.
 

Protected Attributes

SVFIR * svfir {nullptr}
 Data and helpers reachable from SparseAbstractInterpretation.
 
AEWTO * preAnalysis {nullptr}
 
Map< const ICFGNode *, AbstractState > abstractTrace
 per-node trace; owned here
 

Private Member Functions

virtual void handleGlobalNode ()
 
virtual void handleCallSite (const ICFGNode *node)
 Handle a call site node: dispatch to ext-call, direct-call, or indirect-call handling.
 
virtual void handleLoopOrRecursion (const ICFGCycleWTO *cycle, const CallICFGNode *caller)
 Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration.
 
void handleFunction (const ICFGNode *funEntry, const CallICFGNode *caller)
 Handle a function body via worklist-driven WTO traversal starting from funEntry.
 
bool handleICFGNode (const ICFGNode *node)
 Handle an ICFG node: execute statements; return true if state changed.
 
virtual void handleSVFStatement (const SVFStmt *stmt)
 Dispatch an SVF statement (Addr/Binary/Cmp/Load/Store/Copy/Gep/Select/Phi/Call/Ret) to its handler.
 
bool isCmpBranchEdgeFeasible (const IntraCFGEdge *edge, AbstractState &as)
 Returns true if the cmp-conditional branch is feasible.
 
bool isSwitchBranchEdgeFeasible (const IntraCFGEdge *edge, const IntervalValue &input) const
 Check whether any input value can take this switch edge; do not refine it.
 
bool isSwitchDefaultEdge (const IntraCFGEdge *edge) const
 
void updateStateOnAddr (const AddrStmt *addr)
 
void updateStateOnBinary (const BinaryOPStmt *binary)
 
IntervalValue evaluatePointerCmp (u32_t predicate, const AddressValue &lhs, const AddressValue &rhs) const
 
IntervalValue evaluateIntervalCmp (u32_t predicate, const IntervalValue &lhs, const IntervalValue &rhs) const
 
void updateStateOnCmp (const CmpStmt *cmp)
 
void updateStateOnLoad (const LoadStmt *load)
 
void updateStateOnStore (const StoreStmt *store)
 
void updateStateOnCopy (const CopyStmt *copy)
 
void updateStateOnCall (const CallPE *callPE)
 
void updateStateOnRet (const RetPE *retPE)
 
void updateStateOnGep (const GepStmt *gep)
 
void updateStateOnSelect (const SelectStmt *select)
 
void updateStateOnPhi (const PhiStmt *phi)
 
AbsExtAPI * getUtils ()
 
virtual bool isExtCall (const CallICFGNode *callNode)
 
virtual void handleExtCall (const CallICFGNode *callNode)
 
virtual bool isRecursiveFun (const FunObjVar *fun)
 Check if a function is recursive (part of a call graph SCC)
 
virtual void skipRecursionWithTop (const CallICFGNode *callNode)
 
virtual bool isRecursiveCallSite (const CallICFGNode *callNode, const FunObjVar *)
 Check if caller and callee are in the same CallGraph SCC (i.e. a recursive callsite)
 
virtual void handleFunCall (const CallICFGNode *callNode)
 
bool skipRecursiveCall (const CallICFGNode *callNode)
 Skip recursive callsites (within SCC); entry calls from outside SCC are not skipped.
 
const FunObjVar * getCallee (const CallICFGNode *callNode)
 Get callee function: directly for direct calls, via pointer analysis for indirect calls.
 

Private Attributes

AEAPI * api {nullptr}
 Execution State, used to store the Interval Value of every SVF variable.
 
ICFG * icfg
 
CallGraph * callGraph
 
AEStat * stat
 
Map< std::string, std::function< void(const CallICFGNode *)> > func_map
 
Set< const ICFGNode * > allAnalyzedNodes
 
std::string moduleName
 
std::vector< std::unique_ptr< AEDetector > > detectors
 
AbsExtAPI * utils
 

Friends

class AEStat
 
class AEAPI
 
class BufOverflowDetector
 
class NullptrDerefDetector
 

Detailed Description

AbstractInterpretation is same as Abstract Execution.

Owns the per-node abstract trace and exposes the read/write API directly (no separate state-manager indirection). Sparse modes are implemented as subclasses that override the virtual hooks below (cycle helpers, ValVar accessors, joinStates, def/use queries).

Definition at line 60 of file AbstractInterpretation.h.

Member Enumeration Documentation

◆ AEFunEntryMode

Enumerator
MAIN 
NO_MAIN 

Definition at line 97 of file AbstractInterpretation.h.

◆ AESparsity

Enumerator
Dense 
SemiSparse 
Sparse 

Definition at line 83 of file AbstractInterpretation.h.

◆ HandleRecur

Enumerator
TOP 
WIDEN_ONLY 
WIDEN_NARROW 

Definition at line 90 of file AbstractInterpretation.h.

Constructor & Destructor Documentation

◆ ~AbstractInterpretation()

AbstractInterpretation::~AbstractInterpretation ( )
virtual

Destructor.

Definition at line 112 of file AbstractInterpretation.cpp.

◆ AbstractInterpretation()

AbstractInterpretation::AbstractInterpretation ( )
protected

Factory-only construction. External callers must use getAEInstance(); SparseAbstractInterpretation reaches this via its own ctor.

Definition at line 61 of file AbstractInterpretation.cpp.

62{
63 stat = new AEStat(this);
64 // Run Andersen's pointer analysis and build WTO
66 icfg = svfir->getICFG();
71}
CallGraph * getCallGraph() const
Definition AEWTO.h:60
void initWTO()
Build WTO for each function using call graph SCC.
Definition AEWTO.cpp:51
SVFIR * svfir
Data and helpers reachable from SparseAbstractInterpretation.
void updateCallGraph(CallGraph *callgraph)
update ICFG for indirect calls
Definition ICFG.cpp:428
ICFG * getICFG() const
Definition SVFIR.h:232
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:121

Member Function Documentation

◆ addDetector()

void SVF::AbstractInterpretation::addDetector ( std::unique_ptr< AEDetector >  detector)
inline

Definition at line 124 of file AbstractInterpretation.h.

125 {
126 detectors.push_back(std::move(detector));
127 }
std::vector< std::unique_ptr< AEDetector > > detectors
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ analyse()

void AbstractInterpretation::analyse ( )

Program entry.

Program entry - entry policy is selected by -ae-fun-entry.

Definition at line 200 of file AbstractInterpretation.cpp.

201{
203}
void analyzeFromAllProgEntries()
Analyze all entry points (functions without callers)

◆ analyzeFromAllProgEntries()

void AbstractInterpretation::analyzeFromAllProgEntries ( )

Analyze all entry points (functions without callers)

Analyze the entry functions selected by collectProgEntryFuns(). Abstract state is shared across entry points so that functions analyzed from earlier entries are not re-analyzed from scratch.

Definition at line 208 of file AbstractInterpretation.cpp.

209{
210 // Collect all entry point functions
212
213 if (entryFunctions.empty())
214 {
215 assert(false && "No entry functions found for analysis");
216 return;
217 }
218 // handle Global ICFGNode of SVFModule
221 while (!entryFunctions.empty())
222 {
223 const FunObjVar* entryFun = entryFunctions.pop();
226 handleFunction(funEntry, nullptr);
227 }
228}
void handleFunction(const ICFGNode *funEntry, const CallICFGNode *caller)
Handle a function body via worklist-driven WTO traversal starting from funEntry.
AbstractState & getAbsState(const ICFGNode *node)
FIFOWorkList< const FunObjVar * > collectProgEntryFuns()
Get all entry point functions (functions without callers)
virtual void updateAbsState(const ICFGNode *node, const AbstractState &state)
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:243
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244

◆ applyBranchRefinement()

bool AbstractInterpretation::applyBranchRefinement ( const IntraCFGEdge *  edge,
AbstractState &  as 
)
protected

Derive cmp/switch constraints and apply them to this temporary input. Narrow only carried interval Obj values reached through one known pointer target, without changing the backing load's trace. Return false when a carried value contradicts the selected branch.

Definition at line 566 of file AbstractInterpretation.cpp.

568{
569 bool feasible = true;
570 std::vector<std::pair<const LoadStmt*, IntervalValue>> constraints;
571 // Step 1: collect Load ObjVars related to CmpStmt
572 // e.g. cmp = (*p>0), we need to get var p, constant number 0, and predicate > (greater than)
573 const SVFVar* cond = edge->getCondition();
574 const ICFGNode* pred = edge->getSrcNode();
575 s64_t succ = edge->getSuccessorCondValue();
576
577 assert(!cond->getInEdges().empty() &&
578 "branch condition has no defining edge?");
579 const SVFStmt* condDef = *cond->getInEdges().begin();
580
581 if (const CmpStmt* cmpStmt = SVFUtil::dyn_cast<CmpStmt>(condDef))
582 {
583 s32_t predicate = cmpStmt->getPredicate();
584
585 if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
586 cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
587 {
588 // p == NULL / p != NULL: no interval obj to refine.
589 }
590 else
591 {
592 AbstractValue opVal[2] = {getAbsValue(cmpStmt->getOpVar(0), pred),
593 getAbsValue(cmpStmt->getOpVar(1), pred)
594 };
595
596 const bool hasIntervalCmp =
597 opVal[0].isInterval() && opVal[1].isInterval();
598 if (!hasIntervalCmp && (opVal[0].isAddr() || opVal[1].isAddr()))
599 {
600 // Pointer-valued cmp: branch feasibility only.
601 }
602 else
603 {
604 for (int i = 0; i < 2; i++)
605 {
606 const int other = 1 - i;
607 const LoadStmt* load =
608 findBackingLoad(cmpStmt->getOpVar(i));
609
610 if (opVal[i].getInterval().is_numeral())
611 {
612 // Example: in x < 5, operand 5 is not refined.
613 }
614 else if (!opVal[other].getInterval().is_numeral())
615 {
616 // Example: x < y, neither side has a fixed bound.
617 }
618 else if (!load)
619 {
620 // Example: cmp uses a computed temporary, not load p.
621 }
622 else
623 {
625 predicate, succ, i == 0, opVal[i].getInterval(),
626 opVal[other].getInterval());
627
628 if (narrowed.isTop())
629 {
630 // != and unsupported predicates reach here.
631 }
632 else
633 {
634 constraints.emplace_back(load, narrowed);
635 }
636 }
637 }
638 }
639 }
640 }
641 else
642 {
643 if (!isSwitchBranchEdgeFeasible(edge, getAbsValue(cond, pred).getInterval()))
644 return false;
645 else if (isSwitchDefaultEdge(edge))
646 return true;
647 else
648 {
649 const auto* branch = SVFUtil::cast<BranchStmt>(pred->getSVFStmts().back());
650 u32_t caseCount = 0;
651 s64_t caseValue = 0;
652 for (u32_t i = 1; i < branch->getNumSuccessors(); ++i)
653 {
654 if (branch->getSuccessor(i) == edge->getDstNode())
655 {
656 ++caseCount;
657 caseValue = branch->getSuccessorCondValue(i);
658 }
659 }
660
661 // case 10: A(); -> entering A requires x == 10.
662 // case 10: case 20: A(); -> do not select just one value.
663 // Reuse the Obj refinement below; do not modify the defining state.
664 if (caseCount == 1)
665 {
666 if (const LoadStmt* load = findBackingLoad(cond))
667 constraints.emplace_back(load, IntervalValue(caseValue));
668 }
669 }
670 }
671
672 // Step 2: refine Obj below.
673 // Example: x > 5 supplies [6,+inf]; narrowing [0,10] yields [6,10].
674 // Only this temporary input changes, never the backing load's trace.
675 for (const auto& [load, narrowed] : constraints)
676 {
677 const ICFGNode* loadICFG = load->getICFGNode();
678 const AbstractValue& pointer = getAbsValue(load->getRHSVar(), loadICFG);
679 if (!pointer.isAddr() || pointer.getAddrs().size() != 1)
680 {
681 // A condition on *p cannot refine every possible target of p.
682 }
683 else
684 {
685 const u32_t addr = *pointer.getAddrs().begin();
686 const NodeID objId = as.getIDFromAddr(addr);
688 {
689 // No backing memory cell to refine.
690 }
691 else if (!as.inAddrToValTable(objId))
692 {
693 // Refine only an interval Obj already carried by this state.
694 }
695 else
696 {
697 IntervalValue& value = as.load(addr).getInterval();
698 value.meet_with(narrowed);
699 feasible &= !value.isBottom();
700 }
701 }
702 }
703 return feasible;
704}
static const LoadStmt * findBackingLoad(const SVFVar *var)
static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ, bool isLHS, const IntervalValue &self, const IntervalValue &other)
unsigned u32_t
Definition CommandLine.h:18
virtual const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node)
bool isSwitchBranchEdgeFeasible(const IntraCFGEdge *edge, const IntervalValue &input) const
Check whether any input value can take this switch edge; do not refine it.
bool isSwitchDefaultEdge(const IntraCFGEdge *edge) const
static bool isNullOrBlackHoleAddr(u32_t addr)
Whether addr has no concrete backing memory object.
bool isInterval() const
AddressValue & getAddrs()
bool isAddr() const
u32_t size() const
AddrSet::const_iterator begin() const
const GEdgeSetTy & getInEdges() const
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
bool isBottom() const
const ValVar * getRHSVar() const
ICFGNode * getICFGNode() const
u32_t NodeID
Definition GeneralType.h:76
signed s32_t
Definition GeneralType.h:68
signed long long s64_t
Definition GeneralType.h:70

◆ collectProgEntryFuns()

FIFOWorkList< const FunObjVar * > AbstractInterpretation::collectProgEntryFuns ( )

Get all entry point functions (functions without callers)

Collect entry point functions for analysis. In main mode, entry is main/svf.main. In no-main mode, entries are SCCs with no external caller in the Andersen-resolved CallGraph.

Definition at line 122 of file AbstractInterpretation.cpp.

123{
127 auto* callGraphSCC = preAnalysis->getCallGraphSCC();
128
129 for (auto it = callGraph->begin(); it != callGraph->end(); ++it)
130 {
131 const CallGraphNode* cgNode = it->second;
132 const FunObjVar* fun = cgNode->getFunction();
133
134 // Skip declarations
135 if (fun->isDeclaration())
136 continue;
137
138 if (mainEntry)
139 {
141 {
142 entryFunctions.push(fun);
143 break;
144 }
145 }
146 else
147 {
148 NodeID repNodeId = callGraphSCC->repNode(cgNode->getId());
149 if (visitedEntrySCCs.count(repNodeId))
150 continue;
151
152 const NodeBS& cgSCCNodes = callGraphSCC->subNodes(repNodeId);
153 bool hasExternalCaller = false;
154 for (NodeID nodeId : cgSCCNodes)
155 {
157 for (auto inEdge : sccNode->getInEdges())
158 {
159 if (!cgSCCNodes.test(inEdge->getSrcID()))
160 {
161 hasExternalCaller = true;
162 break;
163 }
164 }
166 break;
167 }
168
170 continue;
171
173 const FunObjVar* entryFun = fun;
174 for (NodeID nodeId : cgSCCNodes)
175 {
176 const FunObjVar* sccFun = callGraph->getGNode(nodeId)->getFunction();
178 {
180 break;
181 }
182 }
184 }
185 }
186
187 if (mainEntry && entryFunctions.empty())
188 {
190 "AE -ae-fun-entry=main requires a program entry function, but main/svf.main was not found.\n");
191 assert(false && "No program entry function found for -ae-fun-entry=main");
192 abort();
193 }
194
195 return entryFunctions;
196}
CallGraphSCC * getCallGraphSCC() const
Definition AEWTO.h:64
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
bool isDeclaration() const
iterator begin()
Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
static const OptionMap< u32_t > AEFunEntry
Definition Options.h:238
NodeID getId() const
Get ID.
Definition SVFValue.h:158
bool isProgEntryFunction(const FunObjVar *)
Program entry function e.g. main.
Definition SVFUtil.cpp:531
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:98
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:64

◆ evaluateIntervalCmp()

IntervalValue AbstractInterpretation::evaluateIntervalCmp ( u32_t  predicate,
const IntervalValue &  lhs,
const IntervalValue &  rhs 
) const
private

Definition at line 1191 of file AbstractInterpretation.cpp.

1193{
1195 switch (predicate)
1196 {
1197 case CmpStmt::ICMP_EQ:
1198 case CmpStmt::FCMP_OEQ:
1199 case CmpStmt::FCMP_UEQ:
1200 result = (lhs == rhs);
1201 break;
1202 case CmpStmt::ICMP_NE:
1203 case CmpStmt::FCMP_ONE:
1204 case CmpStmt::FCMP_UNE:
1205 result = (lhs != rhs);
1206 break;
1207 case CmpStmt::ICMP_UGT:
1208 case CmpStmt::ICMP_SGT:
1209 case CmpStmt::FCMP_OGT:
1210 case CmpStmt::FCMP_UGT:
1211 result = (lhs > rhs);
1212 break;
1213 case CmpStmt::ICMP_UGE:
1214 case CmpStmt::ICMP_SGE:
1215 case CmpStmt::FCMP_OGE:
1216 case CmpStmt::FCMP_UGE:
1217 result = (lhs >= rhs);
1218 break;
1219 case CmpStmt::ICMP_ULT:
1220 case CmpStmt::ICMP_SLT:
1221 case CmpStmt::FCMP_OLT:
1222 case CmpStmt::FCMP_ULT:
1223 result = (lhs < rhs);
1224 break;
1225 case CmpStmt::ICMP_ULE:
1226 case CmpStmt::ICMP_SLE:
1227 case CmpStmt::FCMP_OLE:
1228 case CmpStmt::FCMP_ULE:
1229 result = (lhs <= rhs);
1230 break;
1232 result = IntervalValue(0, 0);
1233 break;
1234 case CmpStmt::FCMP_TRUE:
1235 result = IntervalValue(1, 1);
1236 break;
1237 case CmpStmt::FCMP_ORD:
1238 case CmpStmt::FCMP_UNO:
1239 // Keep both outcomes because the interval domain does not track NaN.
1240 result = IntervalValue(0, 1);
1241 break;
1242 default:
1243 assert(false && "undefined compare: ");
1244 }
1245 return result;
1246}
@ ICMP_SGT
signed greater than
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ ICMP_UGE
unsigned greater or equal
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ ICMP_ULE
unsigned less or equal
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ ICMP_NE
not equal
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_ULT
unsigned less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ ICMP_SLT
signed less than
@ ICMP_UGT
unsigned greater than
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_SLE
signed less or equal
static IntervalValue top()
Create the IntervalValue [-inf, +inf].

◆ evaluatePointerCmp()

IntervalValue AbstractInterpretation::evaluatePointerCmp ( u32_t  predicate,
const AddressValue &  lhs,
const AddressValue &  rhs 
) const
private

Evaluate a pointer-typed ICMP over abstract points-to alternatives. Object IDs identify targets but their numeric order does not model runtime address order, so only equality and inequality can produce a definite result.

Definition at line 1145 of file AbstractInterpretation.cpp.

1147{
1149 predicate <= CmpStmt::LAST_ICMP_PREDICATE &&
1150 "pointer comparison must use an ICMP predicate");
1151
1152 const bool lhsTargetKnown =
1153 !lhs.isBottom() && !lhs.contains(BlackHoleObjAddr);
1154 const bool rhsTargetKnown =
1155 !rhs.isBottom() && !rhs.contains(BlackHoleObjAddr);
1157 const bool targetsMayBeEqual = lhs.hasIntersect(rhs);
1158 const bool targetsMustBeEqual =
1159 targetsMayBeEqual && lhs.size() == 1 && rhs.size() == 1;
1160
1162 if (hasUnknownTarget)
1163 {
1164 // Case 1: an unknown target may equal or differ from the other target.
1166 }
1167 else if (!targetsMayBeEqual)
1168 {
1169 // Case 2: known disjoint target sets are definitely unequal.
1171 }
1172 else if (targetsMustBeEqual)
1173 {
1174 // Case 3: intersecting single-target sets contain the same target.
1176 }
1177 else
1178 {
1179 // Case 4: intersecting sets with multiple choices may be equal.
1181 }
1182
1184 if (predicate == CmpStmt::ICMP_EQ)
1185 result = equality;
1186 else if (predicate == CmpStmt::ICMP_NE)
1188 return result;
1189}
#define BlackHoleObjAddr

◆ getAbsState() [1/4]

AbstractState & AbstractInterpretation::getAbsState ( const ICFGNode *  node)

Definition at line 44 of file AbstractStateManager.cpp.

45{
46 if (abstractTrace.count(node) == 0)
47 {
48 assert(false && "No preAbsTrace for this node");
49 abort();
50 }
51 return abstractTrace[node];
52}
Map< const ICFGNode *, AbstractState > abstractTrace
per-node trace; owned here

◆ getAbsState() [2/4]

void AbstractInterpretation::getAbsState ( const Set< const ObjVar * > &  vars,
AbstractState &  result,
const ICFGNode *  node 
)

Definition at line 171 of file AbstractStateManager.cpp.

172{
174 for (const ObjVar* var : vars)
175 {
177 result.store(addr, as.load(addr));
178 }
179}
static u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.

◆ getAbsState() [3/4]

void AbstractInterpretation::getAbsState ( const Set< const SVFVar * > &  vars,
AbstractState &  result,
const ICFGNode *  node 
)

Definition at line 181 of file AbstractStateManager.cpp.

182{
184 for (const SVFVar* var : vars)
185 {
186 if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
187 {
188 u32_t id = valVar->getId();
189 result[id] = as[id];
190 }
191 else if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
192 {
194 result.store(addr, as.load(addr));
195 }
196 }
197}

◆ getAbsState() [4/4]

void AbstractInterpretation::getAbsState ( const Set< const ValVar * > &  vars,
AbstractState &  result,
const ICFGNode *  node 
)

Definition at line 161 of file AbstractStateManager.cpp.

162{
164 for (const ValVar* var : vars)
165 {
166 u32_t id = var->getId();
167 result[id] = as[id];
168 }
169}

◆ getAbsValue() [1/3]

const AbstractValue & AbstractInterpretation::getAbsValue ( const ObjVar *  var,
const ICFGNode *  node 
)
virtual

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 93 of file AbstractStateManager.cpp.

94{
97 return as.load(addr);
98}

◆ getAbsValue() [2/3]

const AbstractValue & AbstractInterpretation::getAbsValue ( const SVFVar *  var,
const ICFGNode *  node 
)
virtual

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 100 of file AbstractStateManager.cpp.

101{
102 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
103 return getAbsValue(objVar, node);
104 if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
105 return getAbsValue(valVar, node);
106 assert(false && "Unknown SVFVar kind");
107 abort();
108}

◆ getAbsValue() [3/3]

const AbstractValue & AbstractInterpretation::getAbsValue ( const ValVar *  var,
const ICFGNode *  node 
)
virtual

Read a top-level variable's abstract value. Dense base does a direct trace lookup; sparse subclasses override with their own resolution chain (def-site walk, call-result fallback, etc.). All three overloads are virtual so full-sparse can route ObjVar reads through the SVFG.

Dense base: direct trace lookup, with a type-directed top value for genuinely missing entries (e.g. function parameters never written before first read). Sparse subclasses override with a def-site resolution chain.

The "in map" check is a raw map.count — NOT inVarToValTable / inVarToAddrsTable, which gate on isInterval / isAddr. SVF canonically represents uninit and null-pointer shapes as (interval=bottom ∧ addrs=∅); those predicates would falsely report such an entry as "not present", and the top fallback below would then clobber the very signal NullptrDerefDetector::isUninit keys off.

Reimplemented in SVF::SemiSparseAbstractInterpretation, and SVF::SemiSparseAbstractInterpretation.

Definition at line 79 of file AbstractStateManager.cpp.

80{
81 u32_t id = var->getId();
83 if (!as.getVarToVal().count(id))
84 {
85 if (var->getType()->isPointerTy())
87 else
88 as[id] = IntervalValue::top();
89 }
90 return as[id];
91}

◆ getAEInstance()

AbstractInterpretation & AbstractInterpretation::getAEInstance ( )
static

Factory: returns the singleton instance. The concrete class is chosen once, on first call, from Options::AESparsity(): SemiSparseAbstractInterpretation for SemiSparse, FullSparseAbstractInterpretation for Sparse, otherwise the dense base. Must be called only after the option parser has run.

Factory: first call allocates the concrete subclass based on Options::AESparsity(); all subsequent calls return the same instance. Must only be called after the option parser has populated AESparsity.

Definition at line 76 of file AbstractInterpretation.cpp.

77{
78 // Leak the singleton on purpose. AbstractInterpretation owns a
79 // Map<std::string, std::function<void(const CallICFGNode*)>> func_map
80 // whose lambda closures back-reference state owned by other globals
81 // (preAnalysis's WTO, the call graph, ...). Letting the static
82 // unique_ptr's atexit-time destructor run hits a static-destruction-
83 // order issue: the func_map hashtable's destructor calls into
84 // std::function destroyers whose closures touch already-destroyed
85 // state, and ~_Hashtable() segfaults during normal program shutdown.
86 //
87 // Reliably reproducible from any downstream tool that drives a full
88 // AE analysis to completion and then exits normally:
89 // - SSA's ass3 binary (Software-Security-Analysis/Assignment-3)
90 // - pysvf via Python interpreter shutdown
91 //
92 // A process-lifetime singleton has no observable lifecycle past
93 // program exit, so leaking is benign and avoids the use-after-destroy.
95 {
96 switch (Options::AESparsity())
97 {
103 default:
104 return new AbstractInterpretation();
105 }
106 }();
107 return *instance;
108}
static const OptionMap< u32_t > AESparsity
Definition Options.h:237

◆ getAllocaInstByteSize()

AbstractInterpretation::AllocationSizeBounds AbstractInterpretation::getAllocaInstByteSize ( const AddrStmt *  addr)

Definition at line 430 of file AbstractStateManager.cpp.

431{
432 const ICFGNode* node = addr->getICFGNode();
433 if (const ObjVar* objvar = SVFUtil::dyn_cast<ObjVar>(addr->getRHSVar()))
434 {
436 {
437 const u32_t size = svfir->getBaseObject(objvar->getId())->getByteSizeOfObj();
438 return {size, size};
439 }
440 else
441 {
442 const std::vector<SVFVar*>& sizes = addr->getArrSize();
443 u32_t elementSize = 1;
445 u64_t lower = sizes.empty() ? 0 : elementSize;
446 for (const SVFVar* value : sizes)
447 {
448 const AbstractValue& sizeVal = getAbsValue(value, node);
449 IntervalValue itv = sizeVal.getInterval();
450 if (itv.isBottom())
452 const s64_t lb = std::max<s64_t>(0, itv.lb().getIntNumeral());
454 ? Options::MaxFieldLimit() : lower * lb;
455 upper = upper * itv.ub().getIntNumeral() > Options::MaxFieldLimit()
456 ? Options::MaxFieldLimit() : upper * itv.ub().getIntNumeral();
457 }
458 return {static_cast<u32_t>(std::min(lower, upper)), static_cast<u32_t>(upper)};
459 }
460 }
461 assert(false && "Addr rhs value is not ObjVar");
462 abort();
463}
bool isConstantByteSize() const
Check if byte size is a const value.
u32_t getByteSizeOfObj() const
Get the byte size of this object.
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:34
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:499
unsigned long long u64_t
Definition GeneralType.h:69

◆ getCallee()

const FunObjVar * AbstractInterpretation::getCallee ( const CallICFGNode *  callNode)
private

Get callee function: directly for direct calls, via pointer analysis for indirect calls.

Definition at line 842 of file AbstractInterpretation.cpp.

843{
844 // Direct call: get callee directly from call node
845 if (const FunObjVar* callee = callNode->getCalledFunction())
846 return callee;
847
848 // Indirect call: resolve callee through pointer analysis
850 auto it = callsiteMaps.find(callNode);
851 if (it == callsiteMaps.end())
852 return nullptr;
853
854 NodeID call_id = it->second;
855 if (!hasAbsState(callNode))
856 return nullptr;
857
859 if (!Addrs.isAddr() || Addrs.getAddrs().empty())
860 return nullptr;
861
862 NodeID addr = *Addrs.getAddrs().begin();
863 const SVFVar* func_var = getSVFVar(getAbsState(callNode).getIDFromAddr(addr));
864 return SVFUtil::dyn_cast<FunObjVar>(func_var);
865}
bool hasAbsState(const ICFGNode *node)
const SVFVar * getSVFVar(NodeID varId) const
Retrieve SVFVar given its ID; asserts if no such variable exists.
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition SVFIR.h:454
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:136

◆ getFullCycleHeadState()

AbstractState AbstractInterpretation::getFullCycleHeadState ( const ICFGCycleWTO *  cycle)
protectedvirtual

Build a full cycle-head AbstractState. Dense default: trace[cycle_head] as-is. Semi-sparse subclass: also pull cycle ValVars from def-sites.

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 162 of file AELoopRecursion.cpp.

163{
164 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
168 return snap;
169}

◆ getGepByteOffset()

IntervalValue AbstractInterpretation::getGepByteOffset ( const GepStmt *  gep)

Definition at line 256 of file AbstractStateManager.cpp.

257{
258 const ICFGNode* node = gep->getICFGNode();
259 if (gep->isConstantOffset())
260 return IntervalValue((s64_t)gep->accumulateConstantByteOffset());
261
262 IntervalValue res(0);
263 for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
264 {
265 const ValVar* idxOperandVar = gep->getOffsetVarAndGepTypePairVec()[i].first;
266 const SVFType* idxOperandType = gep->getOffsetVarAndGepTypePairVec()[i].second;
267
268 if (SVFUtil::isa<SVFArrayType>(idxOperandType) || SVFUtil::isa<SVFPointerType>(idxOperandType))
269 {
271 if (const SVFArrayType* arrOperandType = SVFUtil::dyn_cast<SVFArrayType>(idxOperandType))
272 elemByteSize = arrOperandType->getTypeOfElement()->getByteSize();
273 else if (SVFUtil::isa<SVFPointerType>(idxOperandType))
274 elemByteSize = gep->getAccessPath().gepSrcPointeeType()->getByteSize();
275 else
276 assert(false && "idxOperandType must be ArrType or PtrType");
277
278 if (const ConstIntValVar* op = SVFUtil::dyn_cast<ConstIntValVar>(idxOperandVar))
279 {
280 s64_t lb = (double)Options::MaxFieldLimit() / elemByteSize >= op->getSExtValue()
281 ? op->getSExtValue() * elemByteSize
283 res = res + IntervalValue(lb, lb);
284 }
285 else
286 {
288 if (idxVal.isBottom())
289 res = res + IntervalValue(0, 0);
290 else
291 {
292 s64_t ub = (idxVal.ub().getIntNumeral() < 0) ? 0
293 : (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.ub().getIntNumeral()
294 ? elemByteSize * idxVal.ub().getIntNumeral()
295 : Options::MaxFieldLimit();
296 s64_t lb = (idxVal.lb().getIntNumeral() < 0) ? 0
297 : (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.lb().getIntNumeral()
298 ? elemByteSize * idxVal.lb().getIntNumeral()
299 : Options::MaxFieldLimit();
300 res = res + IntervalValue(lb, ub);
301 }
302 }
303 }
304 else if (const SVFStructType* structOperandType = SVFUtil::dyn_cast<SVFStructType>(idxOperandType))
305 {
306 res = res + IntervalValue(gep->getAccessPath().getStructFieldOffset(idxOperandVar, structOperandType));
307 }
308 else
309 {
310 assert(false && "gep type pair only support arr/ptr/struct");
311 }
312 }
313 return res;
314}
IntervalValue & getInterval()
Carries around command line options.
Definition Options.h:16
u32_t getByteSize() const
Definition SVFType.h:287

◆ getGepElementIndex()

IntervalValue AbstractInterpretation::getGepElementIndex ( const GepStmt *  gep)

Definition at line 199 of file AbstractStateManager.cpp.

200{
201 const ICFGNode* node = gep->getICFGNode();
202 if (gep->isConstantOffset())
203 return IntervalValue((s64_t)gep->accumulateConstantOffset());
204
205 IntervalValue res(0);
206 for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
207 {
208 const ValVar* var = gep->getOffsetVarAndGepTypePairVec()[i].first;
209 const SVFType* type = gep->getOffsetVarAndGepTypePairVec()[i].second;
210
212 if (const ConstIntValVar* constInt = SVFUtil::dyn_cast<ConstIntValVar>(var))
213 idxLb = idxUb = constInt->getSExtValue();
214 else
215 {
217 if (idxItv.isBottom())
218 idxLb = idxUb = 0;
219 else
220 {
222 idxUb = idxItv.ub().getIntNumeral();
223 }
224 }
225
226 if (SVFUtil::isa<SVFPointerType>(type))
227 {
228 u32_t elemNum = gep->getAccessPath().getElementNum(gep->getAccessPath().gepSrcPointeeType());
229 idxLb = (double)Options::MaxFieldLimit() / elemNum < idxLb ? Options::MaxFieldLimit() : idxLb * elemNum;
230 idxUb = (double)Options::MaxFieldLimit() / elemNum < idxUb ? Options::MaxFieldLimit() : idxUb * elemNum;
231 }
232 else
233 {
235 {
236 const std::vector<u32_t>& so = PAG::getPAG()->getTypeInfo(type)->getFlattenedElemIdxVec();
237 if (so.empty() || idxUb >= (APOffset)so.size() || idxLb < 0)
238 idxLb = idxUb = 0;
239 else
240 {
243 }
244 }
245 else
246 idxLb = idxUb = 0;
247 }
248 res = res + IntervalValue(idxLb, idxUb);
249 }
250 res.meet_with(IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit()));
251 if (res.isBottom())
252 res = IntervalValue(0);
253 return res;
254}
newitem type
Definition cJSON.cpp:2739
s64_t getIntNumeral() const
u32_t getFlattenedElemIdx(const SVFType *T, u32_t origId)
Flattened element idx of an array or struct by considering stride.
Definition IRGraph.cpp:148
const StInfo * getTypeInfo(const SVFType *T) const
Get struct info.
Definition IRGraph.cpp:259
const BoundedInt & lb() const
Return the lower bound.
static Option< bool > ModelArrays
Definition Options.h:179
std::vector< u32_t > & getFlattenedElemIdxVec()
Definition SVFType.h:123
s64_t APOffset
Definition GeneralType.h:80

◆ getGepObjAddrs()

AddressValue AbstractInterpretation::getGepObjAddrs ( const ValVar *  pointer,
IntervalValue  offset 
)

Definition at line 316 of file AbstractStateManager.cpp.

317{
318 const ICFGNode* node = pointer->getICFGNode();
321 APOffset lb = offset.lb().getIntNumeral() < Options::MaxFieldLimit() ? offset.lb().getIntNumeral()
323 APOffset ub = offset.ub().getIntNumeral() < Options::MaxFieldLimit() ? offset.ub().getIntNumeral()
325 for (APOffset i = lb; i <= ub; i++)
326 {
327 const AbstractValue& addrs = getAbsValue(pointer, node);
328 for (const auto& addr : addrs.getAddrs())
329 {
330 // Null and black-hole addresses have no backing object.
332 continue;
333 s64_t baseObj = as.getIDFromAddr(addr);
334 assert(SVFUtil::isa<ObjVar>(svfir->getSVFVar(baseObj)) && "Fail to get the base object address!");
338 }
339 }
340 return gepAddrs;
341}
buffer offset
Definition cJSON.cpp:1113
const GepObjVar * getGepObjVar(NodeID id) const
Definition SVFIR.h:170
const ICFGNode * getICFGNode() const

◆ getPointeeElement()

const SVFType * AbstractInterpretation::getPointeeElement ( const ObjVar *  var,
const ICFGNode *  node 
)

Definition at line 414 of file AbstractStateManager.cpp.

415{
416 const AbstractValue& ptrVal = getAbsValue(var, node);
417 if (!ptrVal.isAddr())
418 return nullptr;
419 for (auto addr : ptrVal.getAddrs())
420 {
422 if (objId == 0)
423 continue;
424 return svfir->getBaseObject(objId)->getType();
425 }
426 return nullptr;
427}
u32_t getIDFromAddr(u32_t addr) const
Return the internal index if addr is an address otherwise return the value of idx.
const SVFType * getType() const
Get obj type.

◆ getSVFVar()

const SVFVar * SVF::AbstractInterpretation::getSVFVar ( NodeID  varId) const
inline

Retrieve SVFVar given its ID; asserts if no such variable exists.

Definition at line 130 of file AbstractInterpretation.h.

131 {
132 return svfir->getSVFVar(varId);
133 }

◆ getTrace()

Map< const ICFGNode *, AbstractState > & SVF::AbstractInterpretation::getTrace ( )
inline

Definition at line 201 of file AbstractInterpretation.h.

202 {
203 return abstractTrace;
204 }

◆ getUtils()

AbsExtAPI * SVF::AbstractInterpretation::getUtils ( )
inlineprivate

Definition at line 336 of file AbstractInterpretation.h.

337 {
338 return utils;
339 }

◆ handleCallSite()

void AbstractInterpretation::handleCallSite ( const ICFGNode *  node)
privatevirtual

Handle a call site node: dispatch to ext-call, direct-call, or indirect-call handling.

Definition at line 809 of file AbstractInterpretation.cpp.

810{
811 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
812 {
813 if (isExtCall(callNode))
814 {
816 }
817 else
818 {
819 // Handle both direct and indirect calls uniformly
821 }
822 }
823 else
824 assert (false && "it is not call node");
825}
virtual void handleFunCall(const CallICFGNode *callNode)
virtual bool isExtCall(const CallICFGNode *callNode)
virtual void handleExtCall(const CallICFGNode *callNode)

◆ handleExtCall()

void AbstractInterpretation::handleExtCall ( const CallICFGNode *  callNode)
privatevirtual

Definition at line 832 of file AbstractInterpretation.cpp.

833{
835 for (auto& detector : detectors)
836 {
837 detector->handleStubFunctions(callNode);
838 }
839}
void handleExtAPI(const CallICFGNode *call)
Handles an external API call.

◆ handleFunCall()

void AbstractInterpretation::handleFunCall ( const CallICFGNode *  callNode)
privatevirtual

Handle direct or indirect call: get callee(s), process function body, set return state.

For direct calls, the callee is known statically. For indirect calls, the previous implementation resolved callees from the abstract state's address domain, which only picked the first address and missed other targets. Since the abstract state's address domain is not an over-approximation for function pointers (it may be uninitialized or incomplete), we now use Andersen's pointer analysis results from the pre-computed call graph, which soundly resolves all possible indirect call targets.

Definition at line 876 of file AbstractInterpretation.cpp.

877{
879 return;
880
881 // Direct call: callee is known
882 if (const FunObjVar* callee = callNode->getCalledFunction())
883 {
886 const RetICFGNode* retNode = callNode->getRetICFGNode();
888 return;
889 }
890
891 // Indirect call: use Andersen's call graph to get all resolved callees.
892 const RetICFGNode* retNode = callNode->getRetICFGNode();
894 {
896 for (const FunObjVar* callee : callees)
897 {
898 if (callee->isDeclaration())
899 continue;
902 }
903 }
904 // Resume return node from caller's state (context-insensitive)
906}
bool skipRecursiveCall(const CallICFGNode *callNode)
Skip recursive callsites (within SCC); entry calls from outside SCC are not skipped.
bool hasIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:335
const FunctionSet & getIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:339

◆ handleFunction()

void AbstractInterpretation::handleFunction ( const ICFGNode *  funEntry,
const CallICFGNode *  caller 
)
private

Handle a function body via worklist-driven WTO traversal starting from funEntry.

Handle a function using worklist algorithm guided by WTO order. All top-level WTO components are pushed into the worklist upfront, so the traversal order is exactly the WTO order — each node is visited once, and cycles are handled as whole components.

Definition at line 782 of file AbstractInterpretation.cpp.

783{
784 auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
785 assert(it != preAnalysis->getFuncToWTO().end() && "Missing WTO for function");
786
787 // Push all top-level WTO components into the worklist in WTO order
788 FIFOWorkList<const ICFGWTOComp*> worklist(it->second->getWTOComponents());
789
790 while (!worklist.empty())
791 {
792 const ICFGWTOComp* comp = worklist.pop();
793
794 if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
795 {
796 const ICFGNode* node = singleton->getICFGNode();
798 handleICFGNode(node);
799 }
800 else if (const ICFGCycleWTO* cycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
801 {
802 if (mergeStatesFromPredecessors(cycle->head()->getICFGNode()))
804 }
805 }
806}
const Map< const FunObjVar *, const ICFGWTO * > & getFuncToWTO() const
Accessors for WTO data.
Definition AEWTO.h:72
bool handleICFGNode(const ICFGNode *node)
Handle an ICFG node: execute statements; return true if state changed.
virtual bool mergeStatesFromPredecessors(const ICFGNode *node)
virtual void handleLoopOrRecursion(const ICFGCycleWTO *cycle, const CallICFGNode *caller)
Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration.
WTONode< ICFG > ICFGSingletonWTO
Definition ICFGWTO.h:48
WTOComponent< ICFG > ICFGWTOComp
Definition ICFGWTO.h:47

◆ handleGlobalNode()

void AbstractInterpretation::handleGlobalNode ( )
privatevirtual

Initialize abstract state for the global ICFG node and process global statements

handle global node Initializes the abstract state for the global ICFG node and processes all global statements. This includes setting up the null pointer and black hole pointer (blkPtr). BlkPtr is initialized to point to the BlackHole object, representing an unknown memory location that cannot be statically resolved.

Definition at line 235 of file AbstractInterpretation.cpp.

236{
237 const ICFGNode* node = icfg->getGlobalICFGNode();
238 // Global init is one of the few legitimate direct-mutation sites:
239 // updateAbsState filters out ValVars in semi-sparse mode, but NullPtr/
240 // BlkPtr have no SVFVar so we cannot route them through updateAbsValue.
241 // Use the manager's operator[] (auto-creates the entry if absent).
242 AbstractState& init = abstractTrace[node];
243 init = AbstractState();
244 // NullPtr has no backing SVFVar. Model it directly as the singleton null
245 // address; BlkPtr is initialized directly below for the same reason.
247
248 // Global Node, we just need to handle addr, load, store, copy and gep
249 for (const SVFStmt *stmt: node->getSVFStmts())
250 {
251 handleSVFStatement(stmt);
252 }
253
254 // BlkPtr is the canonical unknown value. Keep its address-domain meaning
255 // for pointer uses, and also give it numeric top so external-input stores
256 // can flow through ordinary store/load state as [-inf, +inf].
258 blkPtrValue.getAddrs().insert(BlackHoleObjAddr);
260}
#define NullMemAddr
virtual void handleSVFStatement(const SVFStmt *stmt)
Dispatch an SVF statement (Addr/Binary/Cmp/Load/Store/Copy/Gep/Select/Phi/Call/Ret) to its handler.
NodeID getBlkPtr() const
Definition IRGraph.h:259

◆ handleICFGNode()

bool AbstractInterpretation::handleICFGNode ( const ICFGNode *  node)
private

Handle an ICFG node: execute statements; return true if state changed.

Handle an ICFG node: execute statements on the current abstract state. The node's pre-state must already be in getAbsState(node) (set by mergeStatesFromPredecessors, or by handleGlobalNode for the global node). Returns true if the abstract state has changed, false if fixpoint reached or unreachable.

Definition at line 723 of file AbstractInterpretation.cpp.

724{
725 // Check reachability: pre-state must have been propagated by predecessors
726 bool isFunEntry = SVFUtil::isa<FunEntryICFGNode>(node);
727 if (!hasAbsState(node))
728 {
729 if (isFunEntry)
730 {
731 // Entry point with no callers: inherit from global node
735 else
737 }
738 else
739 {
740 return false; // unreachable node
741 }
742 }
743
744 // Store the previous state for fixpoint detection
746
747 stat->getBlockTrace()++;
749
750 // Handle SVF statements
751 for (const SVFStmt *stmt: node->getSVFStmts())
752 {
753 handleSVFStatement(stmt);
754 }
755
756 // Handle call sites
757 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
758 {
760 }
761
762 // Run detectors
763 for (auto& detector: detectors)
764 detector->detect(node);
766
767 // Track this node as analyzed (for coverage statistics across all entry points)
768 allAnalyzedNodes.insert(node);
769
770 if (getAbsState(node) == prevState)
771 return false;
772
773 return true;
774}
u32_t & getBlockTrace()
Definition AEStat.h:70
u32_t & getICFGNodeTrace()
Definition AEStat.h:78
void countStateSize()
Definition AEStat.cpp:31
virtual void handleCallSite(const ICFGNode *node)
Handle a call site node: dispatch to ext-call, direct-call, or indirect-call handling.
Set< const ICFGNode * > allAnalyzedNodes

◆ handleLoopOrRecursion()

void AbstractInterpretation::handleLoopOrRecursion ( const ICFGCycleWTO *  cycle,
const CallICFGNode *  caller 
)
privatevirtual

Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration.

Definition at line 235 of file AELoopRecursion.cpp.

236{
237 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
238
239 // TOP mode for recursive function cycles: set all stores and return value to TOP
240 if (Options::HandleRecur() == TOP && isRecursiveFun(cycle_head->getFun()))
241 {
242 if (caller)
244 return;
245 }
246
247 // Iterate until fixpoint with widening/narrowing on the cycle head.
248 bool increasing = true;
250 for (u32_t cur_iter = 0;; cur_iter++)
251 {
252 if (cur_iter >= widen_delay)
253 {
254 // getFullCycleHeadState handles dense (returns trace[cycle_head])
255 // and semi-sparse (collects ValVars from def-sites) uniformly.
257
261
262 if (increasing)
263 {
264 if (widenCycleState(prev, cur, cycle))
265 {
266 increasing = false;
267 continue;
268 }
269 }
270 else
271 {
272 if (narrowCycleState(prev, cur, cycle))
273 break;
274 }
275 }
276 else
277 {
278 // Before widen_delay: process cycle head with gated pattern
281 }
282
283 // Process cycle body components (each with gated merge+handle)
284 for (const ICFGWTOComp* comp : cycle->getWTOComponents())
285 {
286 if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
287 {
288 const ICFGNode* node = singleton->getICFGNode();
290 handleICFGNode(node);
291 }
292 else if (const ICFGCycleWTO* subCycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
293 {
294 if (mergeStatesFromPredecessors(subCycle->head()->getICFGNode()))
296 }
297 }
298 }
299}
newitem prev
Definition cJSON.cpp:2285
virtual bool narrowCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
virtual AbstractState getFullCycleHeadState(const ICFGCycleWTO *cycle)
virtual void skipRecursionWithTop(const CallICFGNode *callNode)
virtual bool widenCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
virtual bool isRecursiveFun(const FunObjVar *fun)
Check if a function is recursive (part of a call graph SCC)
static const OptionMap< u32_t > HandleRecur
recursion handling mode, Default: TOP
Definition Options.h:241
static const Option< u32_t > WidenDelay
Definition Options.h:239

◆ handleSVFStatement()

void AbstractInterpretation::handleSVFStatement ( const SVFStmt *  stmt)
privatevirtual

Dispatch an SVF statement (Addr/Binary/Cmp/Load/Store/Copy/Gep/Select/Phi/Call/Ret) to its handler.

Definition at line 911 of file AbstractInterpretation.cpp.

912{
913 if (const AddrStmt *addr = SVFUtil::dyn_cast<AddrStmt>(stmt))
914 {
916 }
917 else if (const BinaryOPStmt *binary = SVFUtil::dyn_cast<BinaryOPStmt>(stmt))
918 {
920 }
921 else if (const CmpStmt *cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
922 {
924 }
925 else if (SVFUtil::isa<UnaryOPStmt>(stmt))
926 {
927 }
928 else if (SVFUtil::isa<BranchStmt>(stmt))
929 {
930 // branch stmt is handled in hasBranchES
931 }
932 else if (const LoadStmt *load = SVFUtil::dyn_cast<LoadStmt>(stmt))
933 {
934 updateStateOnLoad(load);
935 }
936 else if (const StoreStmt *store = SVFUtil::dyn_cast<StoreStmt>(stmt))
937 {
938 updateStateOnStore(store);
939 }
940 else if (const CopyStmt *copy = SVFUtil::dyn_cast<CopyStmt>(stmt))
941 {
943 }
944 else if (const GepStmt *gep = SVFUtil::dyn_cast<GepStmt>(stmt))
945 {
947 }
948 else if (const SelectStmt *select = SVFUtil::dyn_cast<SelectStmt>(stmt))
949 {
951 }
952 else if (const PhiStmt *phi = SVFUtil::dyn_cast<PhiStmt>(stmt))
953 {
955 }
956 else if (const CallPE *callPE = SVFUtil::dyn_cast<CallPE>(stmt))
957 {
958 // To handle Call Edge
959 updateStateOnCall(callPE);
960 }
961 else if (const RetPE *retPE = SVFUtil::dyn_cast<RetPE>(stmt))
962 {
963 updateStateOnRet(retPE);
964 }
965 else
966 assert(false && "implement this part");
967 // NullPtr should not be changed by any statement. If the entry is missing
968 // (not yet auto-inserted) we treat that as "unchanged" — only check the
969 // entry if it actually exists.
970 {
971 const auto& vmap = getAbsState(stmt->getICFGNode()).getVarToVal();
972 auto it = vmap.find(IRGraph::NullPtr);
973 (void)it; // Suppress warning of unused variable under release build
974 assert(it == vmap.end() ||
975 (it->second.isAddr() &&
976 it->second.getAddrs().equals(AddressValue(NullMemAddr))));
977 }
978}
copy
Definition cJSON.cpp:414
void updateStateOnCall(const CallPE *callPE)
void updateStateOnStore(const StoreStmt *store)
void updateStateOnGep(const GepStmt *gep)
void updateStateOnPhi(const PhiStmt *phi)
void updateStateOnSelect(const SelectStmt *select)
void updateStateOnAddr(const AddrStmt *addr)
void updateStateOnRet(const RetPE *retPE)
void updateStateOnCopy(const CopyStmt *copy)
void updateStateOnLoad(const LoadStmt *load)
void updateStateOnBinary(const BinaryOPStmt *binary)
void updateStateOnCmp(const CmpStmt *cmp)
const VarToAbsValMap & getVarToVal() const
get var2val map

◆ hasAbsState()

bool AbstractInterpretation::hasAbsState ( const ICFGNode *  node)

Definition at line 64 of file AbstractStateManager.cpp.

65{
66 return abstractTrace.count(node) != 0;
67}

◆ hasAbsValue() [1/3]

bool AbstractInterpretation::hasAbsValue ( const ObjVar *  var,
const ICFGNode *  node 
) const
virtual

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 122 of file AbstractStateManager.cpp.

123{
124 auto it = abstractTrace.find(node);
125 if (it == abstractTrace.end())
126 return false;
127 return it->second.getLocToVal().count(var->getId()) != 0;
128}

◆ hasAbsValue() [2/3]

bool AbstractInterpretation::hasAbsValue ( const SVFVar *  var,
const ICFGNode *  node 
) const
virtual

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 130 of file AbstractStateManager.cpp.

131{
132 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
133 return hasAbsValue(objVar, node);
134 if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
135 return hasAbsValue(valVar, node);
136 return false;
137}
virtual bool hasAbsValue(const ValVar *var, const ICFGNode *node) const
Side-effect-free existence check.

◆ hasAbsValue() [3/3]

bool AbstractInterpretation::hasAbsValue ( const ValVar *  var,
const ICFGNode *  node 
) const
virtual

Side-effect-free existence check.

Dense base: direct existence check at node. Mirrors the simplified getAbsValue lookup — uses raw map.contains rather than inVar*Table predicates, which would falsely report neutral (interval=bottom ∧ addrs=∅) entries as "not present".

Reimplemented in SVF::SemiSparseAbstractInterpretation, and SVF::SemiSparseAbstractInterpretation.

Definition at line 114 of file AbstractStateManager.cpp.

115{
116 auto it = abstractTrace.find(node);
117 if (it == abstractTrace.end())
118 return false;
119 return it->second.getVarToVal().count(var->getId()) != 0;
120}

◆ isBranchEdgeFeasible()

bool AbstractInterpretation::isBranchEdgeFeasible ( const IntraCFGEdge *  edge,
AbstractState &  as 
)
protected

Returns true if the branch edge is reachable under the current state. Pure query: does not update abstract states.

Definition at line 706 of file AbstractInterpretation.cpp.

708{
709 const SVFVar* cmpVar = edge->getCondition();
710 assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
711 if (SVFUtil::isa<CmpStmt>(*cmpVar->getInEdges().begin()))
714 getAbsValue(cmpVar, edge->getSrcNode()).getInterval());
715}
bool isCmpBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the cmp-conditional branch is feasible.

◆ isCmpBranchEdgeFeasible()

bool AbstractInterpretation::isCmpBranchEdgeFeasible ( const IntraCFGEdge *  edge,
AbstractState &  as 
)
private

Returns true if the cmp-conditional branch is feasible.

Definition at line 494 of file AbstractInterpretation.cpp.

496{
497 const ICFGNode* pred = edge->getSrcNode();
498 s64_t succ = edge->getSuccessorCondValue();
499 const CmpStmt* cmpStmt = SVFUtil::cast<CmpStmt>(
500 *edge->getCondition()->getInEdges().begin());
501 const AbstractValue& cmpValue = getAbsValue(cmpStmt->getRes(), pred);
502 assert(cmpValue.isInterval() &&
503 "CmpStmt result must be represented by a Boolean interval");
504
505 // Feasibility check: cmp result must be compatible with branch successor
506 IntervalValue resVal = cmpValue.getInterval();
508 return !resVal.isBottom();
509}

◆ isExtCall()

bool AbstractInterpretation::isExtCall ( const CallICFGNode *  callNode)
privatevirtual

Definition at line 827 of file AbstractInterpretation.cpp.

828{
829 return SVFUtil::isExtCall(callNode->getCalledFunction());
830}
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:526

◆ isRecursiveCallSite()

bool AbstractInterpretation::isRecursiveCallSite ( const CallICFGNode *  callNode,
const FunObjVar *  callee 
)
privatevirtual

Check if caller and callee are in the same CallGraph SCC (i.e. a recursive callsite)

Definition at line 104 of file AELoopRecursion.cpp.

106{
107 const FunObjVar* caller = callNode->getCaller();
109}
AndersenWaveDiff * getPointerAnalysis() const
Accessors for Andersen's results.
Definition AEWTO.h:56
bool inSameCallGraphSCC(const FunObjVar *fun1, const FunObjVar *fun2)
Return TRUE if this edge is inside a PTACallGraph SCC, i.e., src node and dst node are in the same SC...

◆ isRecursiveFun()

bool AbstractInterpretation::isRecursiveFun ( const FunObjVar *  fun)
privatevirtual

Check if a function is recursive (part of a call graph SCC)

Definition at line 47 of file AELoopRecursion.cpp.

48{
50}
bool isInRecursion(const FunObjVar *fun) const

◆ isStrongUpdate()

bool AbstractInterpretation::isStrongUpdate ( const AddressValue &  targets,
const AbstractState &  state 
) const
protected

One abstract address need not denote one concrete cell. Heap allocation sites and recursive locals summarize multiple instances and need weak updates, just like multi-target pointers and merged fields. A separate array element can be strongly updated if elements are modeled separately and its address is unique.

state is needed because getIDFromAddr checks its freed-address set, not just the address bits. An address recorded as freed resolves to the BlackHole Obj and must not receive a strong update.

int x=1, y=3; p=cond ? &x : &y; *p=2; // x:[1,2], y:[2,3] a=foo(); b=foo(); // foo returns malloc: a/b may name one heap summary

Definition at line 359 of file AbstractStateManager.cpp.

362{
363 if (targets.size() != 1)
364 return false;
365
366 const NodeID obj = state.getIDFromAddr(*targets.begin());
368 return false;
369
370 const BaseObjVar* base = svfir->getBaseObject(obj);
371 const auto* pta = preAnalysis->getPointerAnalysis();
372
373 if (pta->isHeapMemObj(obj) ||
374 base->isFieldInsensitive() ||
375 pta->isLocalVarInRecursiveFun(obj))
376 return false;
377
378 // Array bases are summaries; individual GEP objects may be
379 // strongly updated only when their offsets are precise.
380 if (pta->isArrayMemObj(obj) && !svfir->isGepObjVar(obj))
381 return false;
382
383 // Reject objects whose fields may be merged by the field limit.
384 const auto* typeInfo = base->getType()->getTypeInfo();
385 return typeInfo->getNumOfFlattenElements() <=
387}
u32_t getMaxFieldOffsetLimit() const
Get max field offset limit.
bool isFieldInsensitive() const
Return true if its field limit is 0.
static bool isNullOrBlkObj(NodeID id)
Check a decoded NodeID, not an AE virtual memory address.
Definition IRGraph.h:169
bool isGepObjVar(NodeID id) const
Definition SVFIR.h:188
StInfo * getTypeInfo()
Definition SVFType.h:273
u32_t getNumOfFlattenElements() const
Return number of elements after flattening (including array elements)
Definition SVFType.h:164

◆ isSwitchBranchEdgeFeasible()

bool AbstractInterpretation::isSwitchBranchEdgeFeasible ( const IntraCFGEdge *  edge,
const IntervalValue &  input 
) const
private

Check whether any input value can take this switch edge; do not refine it.

Definition at line 522 of file AbstractInterpretation.cpp.

524{
525 if (input.isBottom())
526 return false;
527 else if (edge->getCondition()->getType()->getByteSize() > sizeof(s64_t))
528 return true;
529
530 const auto* branch = SVFUtil::cast<BranchStmt>(
531 edge->getSrcNode()->getSVFStmts().back());
533 for (u32_t i = 1; i < branch->getNumSuccessors(); ++i)
534 {
535 const s64_t caseValue = branch->getSuccessorCondValue(i);
536 if (input.lb().leq(caseValue) && input.ub().geq(caseValue))
537 {
538 // case 1: (input: [0,2])
539 // {block for case 1 }
540 // so input can satisfy this case
541 if (branch->getSuccessor(i) == edge->getDstNode())
542 return true;
543 ++matchedCases;
544 }
545 }
546
547 // after last for loop, we test all non-default edge. If we reach here
548 // 1)non-default edge, infeasible 2)default edge, it depends.
550 return false;
551 else if (input.is_infinite())
552 // default edge here
553 // if input reach infinity, conservatively think it can go default edge
554 return true;
555 else
556 {
557 // default edge here
558 // if we still have possible value to miss all non-default cases, it can
559 // go default now.
560 const u64_t span = static_cast<u64_t>(input.ub().getIntNumeral()) -
561 static_cast<u64_t>(input.lb().getIntNumeral());
562 return span >= matchedCases;
563 }
564}

◆ isSwitchDefaultEdge()

bool AbstractInterpretation::isSwitchDefaultEdge ( const IntraCFGEdge *  edge) const
private

True when the edge enters the switch's default destination. LLVM provides this destination even without a source-level default. Explicit cases may share it; this checks the destination only.

Definition at line 511 of file AbstractInterpretation.cpp.

512{
513 // LLVM successor 0 is the default destination, not ICFGNode ID 0.
514 // switch(x) { case 1: work(); break; } after(); -> default goes to after().
515 // Explicit cases may enter the same block; this checks the destination only.
516 enum : u32_t { DefaultSuccessor = 0 };
517 const SVFStmt* terminator = edge->getSrcNode()->getSVFStmts().back();
518 const auto* branch = SVFUtil::cast<BranchStmt>(terminator);
519 return branch->getSuccessor(DefaultSuccessor) == edge->getDstNode();
520}
NodeType * getSrcNode() const

◆ joinStates()

void AbstractInterpretation::joinStates ( AbstractState &  dst,
const AbstractState &  src 
)
virtual

Join src into dst with sparsity-aware semantics. Dense merges everything; semi-sparse skips ValVars.

Reimplemented in SVF::SemiSparseAbstractInterpretation, and SVF::FullSparseAbstractInterpretation.

Definition at line 59 of file AbstractStateManager.cpp.

60{
61 dst.joinWith(src);
62}
void joinWith(const AbstractState &other)
domain join with other, important! other widen this.

◆ loadValue()

AbstractValue AbstractInterpretation::loadValue ( const ValVar *  pointer,
const ICFGNode *  node 
)
virtual

Read memory through the pointer's address targets.

Definition at line 343 of file AbstractStateManager.cpp.

344{
345 const AbstractValue& ptrVal = getAbsValue(pointer, node);
347 AbstractValue res;
348 for (auto addr : ptrVal.getAddrs())
349 {
350 // Null and black-hole addresses have no backing object.
352 continue;
353 res.join_with(
354 getAbsValue(svfir->getSVFVar(as.getIDFromAddr(addr)), node));
355 }
356 return res;
357}
void join_with(const AbstractValue &other)

◆ mergeStatesFromPredecessors()

bool AbstractInterpretation::mergeStatesFromPredecessors ( const ICFGNode *  node)
protectedvirtual

Pull-based state merge: read abstractTrace[pred] for each predecessor, apply branch refinement for conditional IntraCFGEdges, and join into abstractTrace[node]. Returns true if at least one predecessor had state. FullSparse additionally assembles inputs from direct SVFG predecessors.

Pull-based state merge: for each predecessor that has an abstract state, copy its state, apply branch refinement for conditional IntraCFGEdges, and join all feasible states into getAbsState(node). Dense/semi-sparse use their state JOIN; full-sparse merges only freed addresses here and collects Obj values separately through SVFG inputs. Returns true if at least one predecessor contributed state.

Reimplemented in SVF::FullSparseAbstractInterpretation.

Definition at line 268 of file AbstractInterpretation.cpp.

269{
270 // Collect all feasible predecessor states, then merge at the end.
272 bool hasFeasiblePred = false;
273
274 for (auto& edge : node->getInEdges())
275 {
276 const ICFGNode* pred = edge->getSrcNode();
277 if (!hasAbsState(pred))
278 continue;
279
281 bool feasible = false;
282 if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
283 {
284 if (intraCfgEdge->getCondition())
285 {
287 if (feasible)
289 }
290 else
291 {
292 feasible = true;
293 }
294 }
295 else if (SVFUtil::isa<CallCFGEdge>(edge))
296 {
297 feasible = true;
298 }
299 else if (SVFUtil::isa<RetCFGEdge>(edge))
300 {
301 switch (Options::HandleRecur())
302 {
303 case TOP:
304 feasible = true;
305 break;
306 case WIDEN_ONLY:
307 case WIDEN_NARROW:
308 {
309 const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
310 const CallICFGNode* callSite = returnSite->getCallICFGNode();
312 break;
313 }
314 }
315 }
316
317 if (feasible)
318 {
320 {
321 // getAEInstance() selects this class for Sparse mode.
322 static_cast<FullSparseAbstractInterpretation*>(this)->mergeFreedAddrs(merged, predState);
323 }
324 else
326 hasFeasiblePred = true;
327 }
328 }
329
330 if (!hasFeasiblePred)
331 return false;
332
333 updateAbsState(node, merged);
334
335 return true;
336}
bool isBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
virtual void joinStates(AbstractState &dst, const AbstractState &src)
bool applyBranchRefinement(const IntraCFGEdge *edge, AbstractState &as)

◆ narrowCycleState()

bool AbstractInterpretation::narrowCycleState ( const AbstractState &  prev,
const AbstractState &  cur,
const ICFGCycleWTO *  cycle 
)
protectedvirtual

Narrow prev with cur; write the narrowed state back. Returns true when narrowing is disabled or the narrowed state equals prev. Semi-sparse subclass scatters the narrowed ValVars on non-fixpoint.

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 183 of file AELoopRecursion.cpp.

185{
186 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
187 if (!shouldApplyNarrowing(cycle_head->getFun()))
188 return true;
191 if (next == prev)
192 return true; // fixpoint
194 return false;
195}
item next
Definition cJSON.cpp:2224
bool shouldApplyNarrowing(const FunObjVar *fun)
Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.
AbstractState narrowing(const AbstractState &other)
domain narrow with other, and return the narrowed domain

◆ operator[]()

AbstractState & SVF::AbstractInterpretation::operator[] ( const ICFGNode *  node)
inline

Definition at line 205 of file AbstractInterpretation.h.

206 {
207 return abstractTrace[node];
208 }

◆ runOnModule()

void AbstractInterpretation::runOnModule ( )
virtual

collect checkpoint

Definition at line 44 of file AbstractInterpretation.cpp.

45{
46 stat->startClk();
47 utils = new AbsExtAPI(this);
50
51 analyse();
53 stat->endClk();
55 if (Options::PStat())
57 for (auto& detector: detectors)
58 detector->reportBug();
59}
void finializeStat()
Definition AEStat.cpp:44
void performStat() override
Definition AEStat.cpp:120
Handles external API calls and manages abstract states.
Definition AbsExtAPI.h:49
void collectCheckPoint()
void checkPointAllSet()
static const Option< bool > PStat
Definition Options.h:116
virtual void endClk()
Definition SVFStat.h:66
virtual void startClk()
Definition SVFStat.h:61

◆ shouldApplyNarrowing()

bool AbstractInterpretation::shouldApplyNarrowing ( const FunObjVar *  fun)
protected

Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.

Definition at line 130 of file AELoopRecursion.cpp.

131{
132 // Non-recursive functions (regular loops): always apply narrowing
133 if (!isRecursiveFun(fun))
134 return true;
135
136 // Recursive functions: WIDEN_NARROW applies narrowing, WIDEN_ONLY does not
137 // TOP mode exits early in handleLoopOrRecursion, so should not reach here
138 switch (Options::HandleRecur())
139 {
140 case TOP:
141 assert(false && "TOP mode should not reach narrowing phase for recursive functions");
142 return false;
143 case WIDEN_ONLY:
144 return false; // Skip narrowing for recursive functions
145 case WIDEN_NARROW:
146 return true; // Apply narrowing for recursive functions
147 default:
148 assert(false && "Unknown recursion handling mode");
149 return false;
150 }
151}

◆ skipRecursionWithTop()

void AbstractInterpretation::skipRecursionWithTop ( const CallICFGNode *  callNode)
privatevirtual

TOP mode for recursive calls: skip the function body entirely and conservatively set all reachable stores and the return value to TOP.

Definition at line 54 of file AELoopRecursion.cpp.

55{
56 const RetICFGNode *retNode = callNode->getRetICFGNode();
57
58 // 1. Set return value to TOP
59 if (retNode->getSVFStmts().size() > 0)
60 {
61 if (const RetPE *retPE = SVFUtil::dyn_cast<RetPE>(*retNode->getSVFStmts().begin()))
62 {
63 if (!retPE->getLHSVar()->isPointer() &&
64 !retPE->getLHSVar()->isConstDataOrAggDataButNotNullPtr())
65 updateAbsValue(retPE->getLHSVar(), IntervalValue::top(), callNode);
66 }
67 }
68
69 // 2. Set all stores in callee's reachable BBs to TOP
70 if (retNode->getOutEdges().size() > 1)
71 {
73 return;
74 }
75 for (const SVFBasicBlock* bb : callNode->getCalledFunction()->getReachableBBs())
76 {
77 for (const ICFGNode* node : bb->getICFGNodeList())
78 {
79 for (const SVFStmt* stmt : node->getSVFStmts())
80 {
81 if (const StoreStmt* store = SVFUtil::dyn_cast<StoreStmt>(stmt))
82 {
83 const SVFVar* rhsVar = store->getRHSVar();
84 if (!rhsVar->isPointer() && !rhsVar->isConstDataOrAggDataButNotNullPtr())
85 {
86 const AbstractValue& addrs = getAbsValue(store->getLHSVar(), callNode);
87 if (addrs.isAddr())
88 {
90 for (const auto& addr : addrs.getAddrs())
91 as.store(addr, IntervalValue::top());
92 }
93 }
94 }
95 }
96 }
97 }
98
99 // 3. Copy callNode's state to retNode
101}
virtual void updateAbsValue(const ValVar *var, const AbstractValue &val, const ICFGNode *node)

◆ skipRecursiveCall()

bool AbstractInterpretation::skipRecursiveCall ( const CallICFGNode *  callNode)
private

Skip recursive callsites (within SCC); entry calls from outside SCC are not skipped.

Definition at line 112 of file AELoopRecursion.cpp.

113{
115 if (!callee)
116 return false;
117
118 // Non-recursive function: never skip, always inline
120 return false;
121
122 // For recursive functions, skip only recursive callsites (within same SCC).
123 // Entry calls (from outside SCC) are not skipped - they are inlined so that
124 // handleLoopOrRecursion() can analyze the function body.
125 // This applies uniformly to all modes (TOP/WIDEN_ONLY/WIDEN_NARROW).
127}
const FunObjVar * getCallee(const CallICFGNode *callNode)
Get callee function: directly for direct calls, via pointer analysis for indirect calls.
virtual bool isRecursiveCallSite(const CallICFGNode *callNode, const FunObjVar *)
Check if caller and callee are in the same CallGraph SCC (i.e. a recursive callsite)

◆ storeValue()

void AbstractInterpretation::storeValue ( const ValVar *  pointer,
const AbstractValue &  val,
const ICFGNode *  node 
)
virtual

Shared by all sparsity modes: a strong update replaces one concrete cell; a weak update JOINs the old and new values at every possible target.

Definition at line 389 of file AbstractStateManager.cpp.

390{
391 const AbstractValue& ptrVal = getAbsValue(pointer, node);
393 const bool strongUpdate = isStrongUpdate(ptrVal.getAddrs(), as);
394 for (auto addr : ptrVal.getAddrs())
395 {
396 // Null and black-hole addresses have no backing object.
398 continue;
399 const ObjVar* target =
400 SVFUtil::cast<ObjVar>(svfir->getSVFVar(as.getIDFromAddr(addr)));
401 if (strongUpdate)
402 {
403 updateAbsValue(target, val, node);
404 }
405 else
406 {
407 AbstractValue joined = getAbsValue(target, node);
408 joined.join_with(val);
409 updateAbsValue(target, joined, node);
410 }
411 }
412}
bool isStrongUpdate(const AddressValue &targets, const AbstractState &state) const

◆ updateAbsState()

void AbstractInterpretation::updateAbsState ( const ICFGNode *  node,
const AbstractState &  state 
)
virtual

Replace the state at node. Sparse subclasses replace only the ObjVar map (ValVars live at def-sites).

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 54 of file AbstractStateManager.cpp.

55{
56 abstractTrace[node] = state;
57}

◆ updateAbsValue() [1/3]

void AbstractInterpretation::updateAbsValue ( const ObjVar *  var,
const AbstractValue &  val,
const ICFGNode *  node 
)
virtual

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 144 of file AbstractStateManager.cpp.

145{
148 as.store(addr, val);
149}

◆ updateAbsValue() [2/3]

void AbstractInterpretation::updateAbsValue ( const SVFVar *  var,
const AbstractValue &  val,
const ICFGNode *  node 
)
virtual

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 151 of file AbstractStateManager.cpp.

152{
153 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
154 updateAbsValue(objVar, val, node);
155 else if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
156 updateAbsValue(valVar, val, node);
157 else
158 assert(false && "Unknown SVFVar kind");
159}

◆ updateAbsValue() [3/3]

void AbstractInterpretation::updateAbsValue ( const ValVar *  var,
const AbstractValue &  val,
const ICFGNode *  node 
)
virtual

Write a variable's abstract value. Sparse subclasses re-route ValVar writes to the def-site.

Reimplemented in SVF::SemiSparseAbstractInterpretation, and SVF::SemiSparseAbstractInterpretation.

Definition at line 139 of file AbstractStateManager.cpp.

140{
141 abstractTrace[node][var->getId()] = val;
142}

◆ updateStateOnAddr()

void AbstractInterpretation::updateStateOnAddr ( const AddrStmt *  addr)
private

Definition at line 1067 of file AbstractInterpretation.cpp.

1068{
1069 const ICFGNode* node = addr->getICFGNode();
1070 // initObjVar mutates _varToAbsVal/_addrToAbsVal directly, so we need
1071 // mutable access; route via the manager.
1072 AbstractState& as = getAbsState(node);
1073 as.initObjVar(SVFUtil::cast<ObjVar>(addr->getRHSVar()));
1074 // AddrStmt: lhs(ValVar) = &rhs(ObjVar).
1075 // as[rhsId] stores the ObjVar's virtual address in _varToVal,
1076 // NOT the object contents. So we must use as[] directly for ObjVar.
1077 u32_t rhsId = addr->getRHSVarID();
1078 if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy)
1079 as[rhsId].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType()));
1080 // LHS is a ValVar (pointer), write through the API
1081 updateAbsValue(addr->getLHSVar(), as[rhsId], node);
1082}
IntervalValue getRangeLimitFromType(const SVFType *type)
Gets the range limit from a type.

◆ updateStateOnBinary()

void AbstractInterpretation::updateStateOnBinary ( const BinaryOPStmt *  binary)
private

Definition at line 1085 of file AbstractInterpretation.cpp.

1086{
1087 const ICFGNode* node = binary->getICFGNode();
1088 // Treat bottom (uninitialized) operands as top for soundness
1089 const AbstractValue& op0Val = getAbsValue(binary->getOpVar(0), node);
1090 const AbstractValue& op1Val = getAbsValue(binary->getOpVar(1), node);
1091 IntervalValue lhs = op0Val.getInterval().isBottom() ? IntervalValue::top() : op0Val.getInterval();
1092 IntervalValue rhs = op1Val.getInterval().isBottom() ? IntervalValue::top() : op1Val.getInterval();
1094 switch (binary->getOpcode())
1095 {
1096 case BinaryOPStmt::Add:
1097 case BinaryOPStmt::FAdd:
1098 resVal = (lhs + rhs);
1099 break;
1100 case BinaryOPStmt::Sub:
1101 case BinaryOPStmt::FSub:
1102 resVal = (lhs - rhs);
1103 break;
1104 case BinaryOPStmt::Mul:
1105 case BinaryOPStmt::FMul:
1106 resVal = (lhs * rhs);
1107 break;
1108 case BinaryOPStmt::SDiv:
1109 case BinaryOPStmt::FDiv:
1110 case BinaryOPStmt::UDiv:
1111 resVal = (lhs / rhs);
1112 break;
1113 case BinaryOPStmt::SRem:
1114 case BinaryOPStmt::FRem:
1115 case BinaryOPStmt::URem:
1116 resVal = (lhs % rhs);
1117 break;
1118 case BinaryOPStmt::Xor:
1119 resVal = (lhs ^ rhs);
1120 break;
1121 case BinaryOPStmt::And:
1122 resVal = (lhs & rhs);
1123 break;
1124 case BinaryOPStmt::Or:
1125 resVal = (lhs | rhs);
1126 break;
1127 case BinaryOPStmt::AShr:
1128 resVal = (lhs >> rhs);
1129 break;
1130 case BinaryOPStmt::Shl:
1131 resVal = (lhs << rhs);
1132 break;
1133 case BinaryOPStmt::LShr:
1134 resVal = (lhs >> rhs);
1135 break;
1136 default:
1137 assert(false && "undefined binary: ");
1138 }
1139 updateAbsValue(binary->getRes(), resVal, node);
1140}

◆ updateStateOnCall()

void AbstractInterpretation::updateStateOnCall ( const CallPE *  callPE)
private

Handle CallPE: phi-like merging of actual parameters from all call sites into the formal parameter at FunEntryICFGNode (e.g., formal = join(actual1@cs1, actual2@cs2, ...))

Definition at line 1042 of file AbstractInterpretation.cpp.

1043{
1044 const ICFGNode* node = callPE->getICFGNode();
1045 const SVFVar* res = callPE->getRes();
1047 for (u32_t i = 0; i < callPE->getOpVarNum(); i++)
1048 {
1049 const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
1051 {
1052 const AbstractValue& opVal = getAbsValue(callPE->getOpVar(i), opICFGNode);
1053 rhs.join_with(opVal);
1054 }
1055 }
1056 updateAbsValue(res, rhs, node);
1057}
const CallICFGNode * getOpCallICFGNode(u32_t op_idx) const
Return the CallICFGNode of the i-th operand.
const ValVar * getRes() const
Result SVFVar.
const ValVar * getOpVar(u32_t pos) const
Operand SVFVars.
u32_t getOpVarNum() const

◆ updateStateOnCmp()

void AbstractInterpretation::updateStateOnCmp ( const CmpStmt *  cmp)
private

Definition at line 1248 of file AbstractInterpretation.cpp.

1249{
1250 const ICFGNode* node = cmp->getICFGNode();
1251 const AbstractValue& lhsValue = getAbsValue(cmp->getOpVar(0), node);
1252 const AbstractValue& rhsValue = getAbsValue(cmp->getOpVar(1), node);
1253 const bool pointerCmp = cmp->getOpVar(0)->getType()->isPointerTy();
1254 assert(pointerCmp == cmp->getOpVar(1)->getType()->isPointerTy() &&
1255 "CmpStmt operands must belong to the same value domain");
1256
1258 if (pointerCmp)
1259 {
1260 result = evaluatePointerCmp(cmp->getPredicate(), lhsValue.getAddrs(),
1261 rhsValue.getAddrs());
1262 }
1263 else
1264 {
1265 const IntervalValue lhs = lhsValue.isInterval()
1266 ? lhsValue.getInterval()
1268 const IntervalValue rhs = rhsValue.isInterval()
1269 ? rhsValue.getInterval()
1271 result = evaluateIntervalCmp(cmp->getPredicate(), lhs, rhs);
1272 }
1273 updateAbsValue(cmp->getRes(), result, node);
1274}
IntervalValue evaluateIntervalCmp(u32_t predicate, const IntervalValue &lhs, const IntervalValue &rhs) const
IntervalValue evaluatePointerCmp(u32_t predicate, const AddressValue &lhs, const AddressValue &rhs) const

◆ updateStateOnCopy()

void AbstractInterpretation::updateStateOnCopy ( const CopyStmt *  copy)
private

Definition at line 1291 of file AbstractInterpretation.cpp.

1292{
1293 const ICFGNode* node = copy->getICFGNode();
1294 const SVFVar* lhsVar = copy->getLHSVar();
1295 const SVFVar* rhsVar = copy->getRHSVar();
1296
1297 auto getZExtValue = [&](const SVFVar* var)
1298 {
1299 const SVFType* type = var->getType();
1300 if (SVFUtil::isa<SVFIntegerType>(type))
1301 {
1302 u32_t bits = type->getByteSize() * 8;
1303 const AbstractValue& val = getAbsValue(var, node);
1304 if (val.getInterval().is_numeral())
1305 {
1306 if (bits == 8)
1307 {
1308 int8_t signed_i8_value = val.getInterval().getIntNumeral();
1311 }
1312 else if (bits == 16)
1313 {
1314 s16_t signed_i16_value = val.getInterval().getIntNumeral();
1317 }
1318 else if (bits == 32)
1319 {
1320 s32_t signed_i32_value = val.getInterval().getIntNumeral();
1323 }
1324 else if (bits == 64)
1325 {
1326 s64_t signed_i64_value = val.getInterval().getIntNumeral();
1328 }
1329 else
1330 assert(false && "cannot support int type other than u8/16/32/64");
1331 }
1332 else
1333 {
1334 return IntervalValue::top();
1335 }
1336 }
1337 return IntervalValue::top();
1338 };
1339
1340 auto getTruncValue = [&](const SVFVar* var, const SVFType* dstType)
1341 {
1342 const IntervalValue& itv = getAbsValue(var, node).getInterval();
1343 if(itv.isBottom()) return itv;
1345 s64_t int_ub = itv.ub().getIntNumeral();
1346 u32_t dst_bits = dstType->getByteSize() * 8;
1347 if (dst_bits == 8)
1348 {
1349 int8_t s8_lb = static_cast<int8_t>(int_lb);
1350 int8_t s8_ub = static_cast<int8_t>(int_ub);
1351 if (s8_lb > s8_ub)
1353 return IntervalValue(s8_lb, s8_ub);
1354 }
1355 else if (dst_bits == 16)
1356 {
1357 s16_t s16_lb = static_cast<s16_t>(int_lb);
1358 s16_t s16_ub = static_cast<s16_t>(int_ub);
1359 if (s16_lb > s16_ub)
1361 return IntervalValue(s16_lb, s16_ub);
1362 }
1363 else if (dst_bits == 32)
1364 {
1365 s32_t s32_lb = static_cast<s32_t>(int_lb);
1366 s32_t s32_ub = static_cast<s32_t>(int_ub);
1367 if (s32_lb > s32_ub)
1369 return IntervalValue(s32_lb, s32_ub);
1370 }
1371 else
1372 {
1373 assert(false && "cannot support dst int type other than u8/16/32");
1374 abort();
1375 }
1376 };
1377
1378 const AbstractValue& rhsVal = getAbsValue(rhsVar, node);
1379
1380 if (copy->getCopyKind() == CopyStmt::COPYVAL)
1381 {
1383 }
1384 else if (copy->getCopyKind() == CopyStmt::ZEXT)
1385 {
1386 updateAbsValue(lhsVar, getZExtValue(rhsVar), node);
1387 }
1388 else if (copy->getCopyKind() == CopyStmt::SEXT)
1389 {
1390 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1391 }
1392 else if (copy->getCopyKind() == CopyStmt::FPTOSI)
1393 {
1394 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1395 }
1396 else if (copy->getCopyKind() == CopyStmt::FPTOUI)
1397 {
1398 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1399 }
1400 else if (copy->getCopyKind() == CopyStmt::SITOFP)
1401 {
1402 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1403 }
1404 else if (copy->getCopyKind() == CopyStmt::UITOFP)
1405 {
1406 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1407 }
1408 else if (copy->getCopyKind() == CopyStmt::TRUNC)
1409 {
1410 updateAbsValue(lhsVar, getTruncValue(rhsVar, lhsVar->getType()), node);
1411 }
1412 else if (copy->getCopyKind() == CopyStmt::FPTRUNC)
1413 {
1414 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1415 }
1416 else if (copy->getCopyKind() == CopyStmt::INTTOPTR)
1417 {
1418 //insert nullptr
1419 }
1420 else if (copy->getCopyKind() == CopyStmt::PTRTOINT)
1421 {
1423 }
1424 else if (copy->getCopyKind() == CopyStmt::BITCAST)
1425 {
1426 if (rhsVal.isAddr())
1428 }
1429 else
1430 assert(false && "undefined copy kind");
1431}
signed short s16_t
Definition GeneralType.h:74
unsigned short u16_t
Definition GeneralType.h:73

◆ updateStateOnGep()

void AbstractInterpretation::updateStateOnGep ( const GepStmt *  gep)
private

Definition at line 980 of file AbstractInterpretation.cpp.

981{
982 const ICFGNode* node = gep->getICFGNode();
984 AddressValue gepAddrs = getGepObjAddrs(SVFUtil::cast<ValVar>(gep->getRHSVar()), offsetPair);
985 updateAbsValue(gep->getLHSVar(), gepAddrs, node);
986}
AddressValue getGepObjAddrs(const ValVar *pointer, IntervalValue offset)
IntervalValue getGepElementIndex(const GepStmt *gep)

◆ updateStateOnLoad()

void AbstractInterpretation::updateStateOnLoad ( const LoadStmt *  load)
private

Definition at line 1276 of file AbstractInterpretation.cpp.

1277{
1278 const ICFGNode* node = load->getICFGNode();
1280 loadValue(SVFUtil::cast<ValVar>(load->getRHSVar()), node);
1281 updateAbsValue(load->getLHSVar(), loaded, node);
1282}
virtual AbstractValue loadValue(const ValVar *pointer, const ICFGNode *node)
Read memory through the pointer's address targets.
const ValVar * getLHSVar() const

◆ updateStateOnPhi()

void AbstractInterpretation::updateStateOnPhi ( const PhiStmt *  phi)
private

Definition at line 1007 of file AbstractInterpretation.cpp.

1008{
1009 const ICFGNode* icfgNode = phi->getICFGNode();
1011 for (u32_t i = 0; i < phi->getOpVarNum(); i++)
1012 {
1013 const ICFGNode* opICFGNode = phi->getOpICFGNode(i);
1015 {
1017 const AbstractValue& opVal = getAbsValue(phi->getOpVar(i), opICFGNode);
1019 if (edge)
1020 {
1021 const IntraCFGEdge* intraEdge = SVFUtil::cast<IntraCFGEdge>(edge);
1022 if (intraEdge->getCondition())
1023 {
1025 rhs.join_with(opVal);
1026 }
1027 else
1028 rhs.join_with(opVal);
1029 }
1030 else
1031 {
1032 rhs.join_with(opVal);
1033 }
1034 }
1035 }
1036 updateAbsValue(phi->getRes(), rhs, icfgNode);
1037}
ICFGEdge * getICFGEdge(const ICFGNode *src, const ICFGNode *dst, ICFGEdge::ICFGEdgeK kind)
Get a SVFG edge according to src and dst.
Definition ICFG.cpp:312

◆ updateStateOnRet()

void AbstractInterpretation::updateStateOnRet ( const RetPE *  retPE)
private

Definition at line 1059 of file AbstractInterpretation.cpp.

1060{
1061 const ICFGNode* node = retPE->getICFGNode();
1062 const AbstractValue& rhsVal = getAbsValue(retPE->getRHSVar(), node);
1063 updateAbsValue(retPE->getLHSVar(), rhsVal, node);
1064}
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const

◆ updateStateOnSelect()

void AbstractInterpretation::updateStateOnSelect ( const SelectStmt *  select)
private

Definition at line 988 of file AbstractInterpretation.cpp.

989{
990 const ICFGNode* node = select->getICFGNode();
991 const AbstractValue& condVal = getAbsValue(select->getCondition(), node);
992 const AbstractValue& tVal = getAbsValue(select->getTrueValue(), node);
993 const AbstractValue& fVal = getAbsValue(select->getFalseValue(), node);
995 if (condVal.getInterval().is_numeral())
996 {
998 }
999 else
1000 {
1001 resVal = tVal;
1002 resVal.join_with(fVal);
1003 }
1004 updateAbsValue(select->getRes(), resVal, node);
1005}
bool is_zero() const
Return true if the IntervalValue is [0, 0].

◆ updateStateOnStore()

void AbstractInterpretation::updateStateOnStore ( const StoreStmt *  store)
private

Definition at line 1284 of file AbstractInterpretation.cpp.

1285{
1286 const ICFGNode* node = store->getICFGNode();
1287 AbstractValue val = getAbsValue(store->getRHSVar(), node);
1288 storeValue(SVFUtil::cast<ValVar>(store->getLHSVar()), val, node);
1289}
virtual void storeValue(const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const

◆ widenCycleState()

bool AbstractInterpretation::widenCycleState ( const AbstractState &  prev,
const AbstractState &  cur,
const ICFGCycleWTO *  cycle 
)
protectedvirtual

Widen prev with cur; write the widened state to trace[cycle_head]. Returns true when next == prev (fixpoint). Semi-sparse subclass additionally scatters ValVars to their def-sites.

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 171 of file AELoopRecursion.cpp.

173{
176 // Always write back (even at fixpoint) so cycle_head's trace holds the
177 // widened state for the upcoming narrowing phase.
178 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
180 return next == prev;
181}
AbstractState widening(const AbstractState &other)
domain widen with other, and return the widened domain

Friends And Related Symbol Documentation

◆ AEAPI

friend class AEAPI
friend

Definition at line 63 of file AbstractInterpretation.h.

◆ AEStat

Definition at line 62 of file AbstractInterpretation.h.

◆ BufOverflowDetector

Definition at line 64 of file AbstractInterpretation.h.

◆ NullptrDerefDetector

Definition at line 65 of file AbstractInterpretation.h.

Member Data Documentation

◆ abstractTrace

Map<const ICFGNode*, AbstractState> SVF::AbstractInterpretation::abstractTrace
protected

per-node trace; owned here

Definition at line 365 of file AbstractInterpretation.h.

◆ allAnalyzedNodes

Set<const ICFGNode*> SVF::AbstractInterpretation::allAnalyzedNodes
private

Definition at line 355 of file AbstractInterpretation.h.

◆ api

AEAPI* SVF::AbstractInterpretation::api {nullptr}
private

Execution State, used to store the Interval Value of every SVF variable.

Definition at line 330 of file AbstractInterpretation.h.

330{nullptr};

◆ callGraph

CallGraph* SVF::AbstractInterpretation::callGraph
private

Definition at line 333 of file AbstractInterpretation.h.

◆ detectors

std::vector<std::unique_ptr<AEDetector> > SVF::AbstractInterpretation::detectors
private

Definition at line 358 of file AbstractInterpretation.h.

◆ func_map

Map<std::string, std::function<void(const CallICFGNode*)> > SVF::AbstractInterpretation::func_map
private

Definition at line 353 of file AbstractInterpretation.h.

◆ icfg

ICFG* SVF::AbstractInterpretation::icfg
private

Definition at line 332 of file AbstractInterpretation.h.

◆ moduleName

std::string SVF::AbstractInterpretation::moduleName
private

Definition at line 356 of file AbstractInterpretation.h.

◆ preAnalysis

AEWTO* SVF::AbstractInterpretation::preAnalysis {nullptr}
protected

Definition at line 364 of file AbstractInterpretation.h.

364{nullptr};

◆ stat

AEStat* SVF::AbstractInterpretation::stat
private

Definition at line 334 of file AbstractInterpretation.h.

◆ svfir

SVFIR* SVF::AbstractInterpretation::svfir {nullptr}
protected

Data and helpers reachable from SparseAbstractInterpretation.

Definition at line 363 of file AbstractInterpretation.h.

363{nullptr};

◆ utils

AbsExtAPI* SVF::AbstractInterpretation::utils
private

Definition at line 359 of file AbstractInterpretation.h.


The documentation for this class was generated from the following files: