Static Value-Flow Analysis
Loading...
Searching...
No Matches
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

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)
 Virtual so full-sparse can layer the GepObj overlay on top.
 
virtual void storeValue (const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
 
const SVFType * getPointeeElement (const ObjVar *var, const ICFGNode *node)
 
u32_t 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 ()
 
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)
 
void collectBranchRefinement (const IntraCFGEdge *edge, AbstractState &as)
 
virtual void recordBranchRefinement (NodeID objId, const IntervalValue &narrowed, AbstractState &as, const ICFGNode *loadIcfg, const ICFGNode *succ)
 
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, AbstractState &as)
 Returns true if the switch branch is feasible.
 
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:231
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:120

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

◆ collectBranchRefinement()

void AbstractInterpretation::collectBranchRefinement ( const IntraCFGEdge *  edge,
AbstractState &  as 
)
protected

Collect branch-induced interval refinement after a feasible edge has been selected for normal CFG-state merging.

Definition at line 523 of file AbstractInterpretation.cpp.

525{
526 const SVFVar* cond = edge->getCondition();
527 const ICFGNode* pred = edge->getSrcNode();
528 const ICFGNode* succNode = edge->getDstNode();
529 s64_t succ = edge->getSuccessorCondValue();
530
531 assert(!cond->getInEdges().empty() &&
532 "branch condition has no defining edge?");
533 const SVFStmt* condDef = *cond->getInEdges().begin();
534
535 if (const CmpStmt* cmpStmt = SVFUtil::dyn_cast<CmpStmt>(condDef))
536 {
537 s32_t predicate = cmpStmt->getPredicate();
538
539 if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
540 cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
541 {
542 // p == NULL / p != NULL: no interval obj to refine.
543 }
544 else
545 {
546 AbstractValue opVal[2] = {getAbsValue(cmpStmt->getOpVar(0), pred),
547 getAbsValue(cmpStmt->getOpVar(1), pred)
548 };
549
550 const bool hasIntervalCmp =
551 opVal[0].isInterval() && opVal[1].isInterval();
552 if (!hasIntervalCmp && (opVal[0].isAddr() || opVal[1].isAddr()))
553 {
554 // Pointer-valued cmp: branch feasibility only.
555 }
556 else
557 {
558 for (int i = 0; i < 2; i++)
559 {
560 const int other = 1 - i;
561 const LoadStmt* load =
562 findBackingLoad(cmpStmt->getOpVar(i));
563
564 if (opVal[i].getInterval().is_numeral())
565 {
566 // Example: in x < 5, operand 5 is not refined.
567 }
568 else if (!opVal[other].getInterval().is_numeral())
569 {
570 // Example: x < y, neither side has a fixed bound.
571 }
572 else if (!load)
573 {
574 // Example: cmp uses a computed temporary, not load p.
575 }
576 else
577 {
579 predicate, succ, i == 0, opVal[i].getInterval(),
580 opVal[other].getInterval());
581
582 if (narrowed.isTop())
583 {
584 // != and unsupported predicates reach here.
585 }
586 else
587 {
588 const ICFGNode* loadIcfg = load->getICFGNode();
589 const AbstractValue& ptrVal =
591 if (!ptrVal.isAddr())
592 {
593 // Cannot map load p back to concrete ObjVars.
594 }
595 else
596 {
597 for (const auto& addr : ptrVal.getAddrs())
598 {
599 NodeID objId = as.getIDFromAddr(addr);
602 }
603 }
604 }
605 }
606 }
607 }
608 }
609 }
610 else
611 {
612 const SVFVar* var = cond;
613
615 IntervalValue switch_cond = condVal.getInterval();
617 if (switch_cond.isBottom())
618 {
619 // This case label is not reachable from cond's interval.
620 }
621 else
622 {
623 as[var->getId()] = AbstractValue(switch_cond);
624
626 for (SVFStmt* stmt : var->getInEdges())
627 stmtList.push(stmt);
628 while (!stmtList.empty())
629 {
630 const SVFStmt* stmt = stmtList.pop();
631 const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt);
632 if (!load)
633 {
634 // Skip non-load definitions of the switch condition.
635 }
636 else
637 {
638 const ICFGNode* loadIcfg = load->getICFGNode();
639 const AbstractValue& ptrVal =
641 if (!ptrVal.isAddr())
642 {
643 // Cannot map load p back to concrete ObjVars.
644 }
645 else
646 {
647 for (const auto& addr : ptrVal.getAddrs())
648 {
649 NodeID objId = as.getIDFromAddr(addr);
652 }
653 }
654 }
655 }
656 }
657 }
658}
static const LoadStmt * findBackingLoad(const SVFVar *var)
static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ, bool isLHS, const IntervalValue &self, const IntervalValue &other)
virtual const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node)
virtual void recordBranchRefinement(NodeID objId, const IntervalValue &narrowed, AbstractState &as, const ICFGNode *loadIcfg, const ICFGNode *succ)
bool isInterval() const
const GEdgeSetTy & getInEdges() const
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
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:237
NodeID getId() const
Get ID.
Definition SVFValue.h:158
bool isProgEntryFunction(const FunObjVar *)
Program entry function e.g. main.
Definition SVFUtil.cpp:446
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:82
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58

◆ evaluateIntervalCmp()

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

Definition at line 1177 of file AbstractInterpretation.cpp.

1179{
1181 switch (predicate)
1182 {
1183 case CmpStmt::ICMP_EQ:
1184 case CmpStmt::FCMP_OEQ:
1185 case CmpStmt::FCMP_UEQ:
1186 result = (lhs == rhs);
1187 break;
1188 case CmpStmt::ICMP_NE:
1189 case CmpStmt::FCMP_ONE:
1190 case CmpStmt::FCMP_UNE:
1191 result = (lhs != rhs);
1192 break;
1193 case CmpStmt::ICMP_UGT:
1194 case CmpStmt::ICMP_SGT:
1195 case CmpStmt::FCMP_OGT:
1196 case CmpStmt::FCMP_UGT:
1197 result = (lhs > rhs);
1198 break;
1199 case CmpStmt::ICMP_UGE:
1200 case CmpStmt::ICMP_SGE:
1201 case CmpStmt::FCMP_OGE:
1202 case CmpStmt::FCMP_UGE:
1203 result = (lhs >= rhs);
1204 break;
1205 case CmpStmt::ICMP_ULT:
1206 case CmpStmt::ICMP_SLT:
1207 case CmpStmt::FCMP_OLT:
1208 case CmpStmt::FCMP_ULT:
1209 result = (lhs < rhs);
1210 break;
1211 case CmpStmt::ICMP_ULE:
1212 case CmpStmt::ICMP_SLE:
1213 case CmpStmt::FCMP_OLE:
1214 case CmpStmt::FCMP_ULE:
1215 result = (lhs <= rhs);
1216 break;
1218 result = IntervalValue(0, 0);
1219 break;
1220 case CmpStmt::FCMP_TRUE:
1221 result = IntervalValue(1, 1);
1222 break;
1223 case CmpStmt::FCMP_ORD:
1224 case CmpStmt::FCMP_UNO:
1225 // Keep both outcomes because the interval domain does not track NaN.
1226 result = IntervalValue(0, 1);
1227 break;
1228 default:
1229 assert(false && "undefined compare: ");
1230 }
1231 return result;
1232}
@ 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 1131 of file AbstractInterpretation.cpp.

1133{
1135 predicate <= CmpStmt::LAST_ICMP_PREDICATE &&
1136 "pointer comparison must use an ICMP predicate");
1137
1138 const bool lhsTargetKnown =
1139 !lhs.isBottom() && !lhs.contains(BlackHoleObjAddr);
1140 const bool rhsTargetKnown =
1141 !rhs.isBottom() && !rhs.contains(BlackHoleObjAddr);
1143 const bool targetsMayBeEqual = lhs.hasIntersect(rhs);
1144 const bool targetsMustBeEqual =
1145 targetsMayBeEqual && lhs.size() == 1 && rhs.size() == 1;
1146
1148 if (hasUnknownTarget)
1149 {
1150 // Case 1: an unknown target may equal or differ from the other target.
1152 }
1153 else if (!targetsMayBeEqual)
1154 {
1155 // Case 2: known disjoint target sets are definitely unequal.
1157 }
1158 else if (targetsMustBeEqual)
1159 {
1160 // Case 3: intersecting single-target sets contain the same target.
1162 }
1163 else
1164 {
1165 // Case 4: intersecting sets with multiple choices may be equal.
1167 }
1168
1170 if (predicate == CmpStmt::ICMP_EQ)
1171 result = equality;
1172 else if (predicate == CmpStmt::ICMP_NE)
1174 return result;
1175}
#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}
unsigned u32_t
Definition CommandLine.h:18
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:236

◆ getAllocaInstByteSize()

u32_t AbstractInterpretation::getAllocaInstByteSize ( const AddrStmt *  addr)

Definition at line 387 of file AbstractStateManager.cpp.

388{
389 const ICFGNode* node = addr->getICFGNode();
390 if (const ObjVar* objvar = SVFUtil::dyn_cast<ObjVar>(addr->getRHSVar()))
391 {
393 {
394 return svfir->getBaseObject(objvar->getId())->getByteSizeOfObj();
395 }
396 else
397 {
398 const std::vector<SVFVar*>& sizes = addr->getArrSize();
399 u32_t elementSize = 1;
400 u64_t res = elementSize;
401 for (const SVFVar* value : sizes)
402 {
403 const AbstractValue& sizeVal = getAbsValue(value, node);
404 IntervalValue itv = sizeVal.getInterval();
405 if (itv.isBottom())
407 res = res * itv.ub().getIntNumeral() > Options::MaxFieldLimit()
408 ? Options::MaxFieldLimit() : res * itv.ub().getIntNumeral();
409 }
410 return (u32_t)res;
411 }
412 }
413 assert(false && "Addr rhs value is not ObjVar");
414 abort();
415}
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:498
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 828 of file AbstractInterpretation.cpp.

829{
830 // Direct call: get callee directly from call node
831 if (const FunObjVar* callee = callNode->getCalledFunction())
832 return callee;
833
834 // Indirect call: resolve callee through pointer analysis
836 auto it = callsiteMaps.find(callNode);
837 if (it == callsiteMaps.end())
838 return nullptr;
839
840 NodeID call_id = it->second;
841 if (!hasAbsState(callNode))
842 return nullptr;
843
845 if (!Addrs.isAddr() || Addrs.getAddrs().empty())
846 return nullptr;
847
848 NodeID addr = *Addrs.getAddrs().begin();
849 const SVFVar* func_var = getSVFVar(getAbsState(callNode).getIDFromAddr(addr));
850 return SVFUtil::dyn_cast<FunObjVar>(func_var);
851}
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:453
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:135

◆ 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:178
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
static bool isNullOrBlackHoleAddr(u32_t addr)
Whether addr has no concrete backing memory object.
const GepObjVar * getGepObjVar(NodeID id) const
Definition SVFIR.h:169
const ICFGNode * getICFGNode() const

◆ getPointeeElement()

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

Definition at line 372 of file AbstractStateManager.cpp.

373{
374 const AbstractValue& ptrVal = getAbsValue(var, node);
375 if (!ptrVal.isAddr())
376 return nullptr;
377 for (auto addr : ptrVal.getAddrs())
378 {
380 if (objId == 0)
381 continue;
382 return svfir->getBaseObject(objId)->getType();
383 }
384 return nullptr;
385}
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 192 of file AbstractInterpretation.h.

193 {
194 return abstractTrace;
195 }

◆ getUtils()

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

Definition at line 318 of file AbstractInterpretation.h.

319 {
320 return utils;
321 }

◆ 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 795 of file AbstractInterpretation.cpp.

796{
797 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
798 {
799 if (isExtCall(callNode))
800 {
802 }
803 else
804 {
805 // Handle both direct and indirect calls uniformly
807 }
808 }
809 else
810 assert (false && "it is not call node");
811}
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 818 of file AbstractInterpretation.cpp.

819{
821 for (auto& detector : detectors)
822 {
823 detector->handleStubFunctions(callNode);
824 }
825}
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 862 of file AbstractInterpretation.cpp.

863{
865 return;
866
867 // Direct call: callee is known
868 if (const FunObjVar* callee = callNode->getCalledFunction())
869 {
872 const RetICFGNode* retNode = callNode->getRetICFGNode();
874 return;
875 }
876
877 // Indirect call: use Andersen's call graph to get all resolved callees.
878 const RetICFGNode* retNode = callNode->getRetICFGNode();
880 {
882 for (const FunObjVar* callee : callees)
883 {
884 if (callee->isDeclaration())
885 continue;
888 }
889 }
890 // Resume return node from caller's state (context-insensitive)
892}
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 768 of file AbstractInterpretation.cpp.

769{
770 auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
771 assert(it != preAnalysis->getFuncToWTO().end() && "Missing WTO for function");
772
773 // Push all top-level WTO components into the worklist in WTO order
774 FIFOWorkList<const ICFGWTOComp*> worklist(it->second->getWTOComponents());
775
776 while (!worklist.empty())
777 {
778 const ICFGWTOComp* comp = worklist.pop();
779
780 if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
781 {
782 const ICFGNode* node = singleton->getICFGNode();
784 handleICFGNode(node);
785 }
786 else if (const ICFGCycleWTO* cycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
787 {
788 if (mergeStatesFromPredecessors(cycle->head()->getICFGNode()))
790 }
791 }
792}
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:254

◆ 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 709 of file AbstractInterpretation.cpp.

710{
711 // Check reachability: pre-state must have been propagated by predecessors
712 bool isFunEntry = SVFUtil::isa<FunEntryICFGNode>(node);
713 if (!hasAbsState(node))
714 {
715 if (isFunEntry)
716 {
717 // Entry point with no callers: inherit from global node
721 else
723 }
724 else
725 {
726 return false; // unreachable node
727 }
728 }
729
730 // Store the previous state for fixpoint detection
732
733 stat->getBlockTrace()++;
735
736 // Handle SVF statements
737 for (const SVFStmt *stmt: node->getSVFStmts())
738 {
739 handleSVFStatement(stmt);
740 }
741
742 // Handle call sites
743 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
744 {
746 }
747
748 // Run detectors
749 for (auto& detector: detectors)
750 detector->detect(node);
752
753 // Track this node as analyzed (for coverage statistics across all entry points)
754 allAnalyzedNodes.insert(node);
755
756 if (getAbsState(node) == prevState)
757 return false;
758
759 return true;
760}
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:240
static const Option< u32_t > WidenDelay
Definition Options.h:238

◆ 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 897 of file AbstractInterpretation.cpp.

898{
899 if (const AddrStmt *addr = SVFUtil::dyn_cast<AddrStmt>(stmt))
900 {
902 }
903 else if (const BinaryOPStmt *binary = SVFUtil::dyn_cast<BinaryOPStmt>(stmt))
904 {
906 }
907 else if (const CmpStmt *cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
908 {
910 }
911 else if (SVFUtil::isa<UnaryOPStmt>(stmt))
912 {
913 }
914 else if (SVFUtil::isa<BranchStmt>(stmt))
915 {
916 // branch stmt is handled in hasBranchES
917 }
918 else if (const LoadStmt *load = SVFUtil::dyn_cast<LoadStmt>(stmt))
919 {
920 updateStateOnLoad(load);
921 }
922 else if (const StoreStmt *store = SVFUtil::dyn_cast<StoreStmt>(stmt))
923 {
924 updateStateOnStore(store);
925 }
926 else if (const CopyStmt *copy = SVFUtil::dyn_cast<CopyStmt>(stmt))
927 {
929 }
930 else if (const GepStmt *gep = SVFUtil::dyn_cast<GepStmt>(stmt))
931 {
933 }
934 else if (const SelectStmt *select = SVFUtil::dyn_cast<SelectStmt>(stmt))
935 {
937 }
938 else if (const PhiStmt *phi = SVFUtil::dyn_cast<PhiStmt>(stmt))
939 {
941 }
942 else if (const CallPE *callPE = SVFUtil::dyn_cast<CallPE>(stmt))
943 {
944 // To handle Call Edge
945 updateStateOnCall(callPE);
946 }
947 else if (const RetPE *retPE = SVFUtil::dyn_cast<RetPE>(stmt))
948 {
949 updateStateOnRet(retPE);
950 }
951 else
952 assert(false && "implement this part");
953 // NullPtr should not be changed by any statement. If the entry is missing
954 // (not yet auto-inserted) we treat that as "unchanged" — only check the
955 // entry if it actually exists.
956 {
957 const auto& vmap = getAbsState(stmt->getICFGNode()).getVarToVal();
958 auto it = vmap.find(IRGraph::NullPtr);
959 (void)it; // Suppress warning of unused variable under release build
960 assert(it == vmap.end() ||
961 (it->second.isAddr() &&
962 it->second.getAddrs().equals(AddressValue(NullMemAddr))));
963 }
964}
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 as or branch refinement traces.

Definition at line 693 of file AbstractInterpretation.cpp.

695{
696 const SVFVar* cmpVar = edge->getCondition();
697 assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
698 if (SVFUtil::isa<CmpStmt>(*cmpVar->getInEdges().begin()))
701}
bool isCmpBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the cmp-conditional branch is feasible.
bool isSwitchBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the switch 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 491 of file AbstractInterpretation.cpp.

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

◆ isExtCall()

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

Definition at line 813 of file AbstractInterpretation.cpp.

814{
815 return SVFUtil::isExtCall(callNode->getCalledFunction());
816}
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:441

◆ 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

◆ isSwitchBranchEdgeFeasible()

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

Returns true if the switch branch is feasible.

Definition at line 508 of file AbstractInterpretation.cpp.

510{
511 const ICFGNode* pred = edge->getSrcNode();
512 s64_t succ = edge->getSuccessorCondValue();
513 const SVFVar* var = edge->getCondition();
514
516 IntervalValue switch_cond = condVal.getInterval();
518 if (switch_cond.isBottom())
519 return false;
520 return true;
521}

◆ 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

Virtual so full-sparse can layer the GepObj overlay on top.

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. Virtual so full-sparse can layer per-MRSVFGNode obj pulls on top of the base ICFG-edge merge.

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). The join is dispatched through the manager so semi-sparse can skip ValVar merging. 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
280 if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
281 {
282 if (intraCfgEdge->getCondition())
283 {
286 {
289 hasFeasiblePred = true;
290 }
291 }
292 else
293 {
295 hasFeasiblePred = true;
296 }
297 }
298 else if (SVFUtil::isa<CallCFGEdge>(edge))
299 {
301 hasFeasiblePred = true;
302 }
303 else if (SVFUtil::isa<RetCFGEdge>(edge))
304 {
305 switch (Options::HandleRecur())
306 {
307 case TOP:
309 hasFeasiblePred = true;
310 break;
311 case WIDEN_ONLY:
312 case WIDEN_NARROW:
313 {
314 const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
315 const CallICFGNode* callSite = returnSite->getCallICFGNode();
317 {
319 hasFeasiblePred = true;
320 }
321 break;
322 }
323 }
324 }
325 }
326
327 if (!hasFeasiblePred)
328 return false;
329
330 updateAbsState(node, merged);
331
332 return true;
333}
bool isBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
virtual void joinStates(AbstractState &dst, const AbstractState &src)
void collectBranchRefinement(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 196 of file AbstractInterpretation.h.

197 {
198 return abstractTrace[node];
199 }

◆ recordBranchRefinement()

void AbstractInterpretation::recordBranchRefinement ( NodeID  objId,
const IntervalValue &  narrowed,
AbstractState &  as,
const ICFGNode *  loadIcfg,
const ICFGNode *  succ 
)
protectedvirtual

Hook called by collectBranchRefinement for each obj that the branch narrows. Default (dense/semi): MEET narrowed onto obj's value (read at loadIcfg where sparse keeps it) and write the result into the local as (per-edge predState copy) so joinStates carries it to succ. FullSparse overrides to capture into refinementTrace[succ] instead.

Reimplemented in SVF::FullSparseAbstractInterpretation.

Definition at line 660 of file AbstractInterpretation.cpp.

663{
664 // Default (dense / semi-sparse): MEET narrowed onto obj's current
665 // value, store back into the local `as`. Caller's joinStates
666 // propagates `as` into `merged`, then `updateAbsState(succ, merged)`
667 // commits it to trace[succ].
668 //
669 // We can't go through the polymorphic updateAbsValue here: `as` is
670 // a transient per-edge predState copy that lives outside
671 // abstractTrace, so it has no node id. Writing via `updateAbsValue`
672 // with `succ` as the node would land in trace[succ] but get
673 // clobbered by the subsequent `updateAbsState(succ, merged)`; with
674 // `loadIcfg` it would corrupt the obj's authoritative value at its
675 // load site. AbstractState::store on the transient `as` is the
676 // only sound primitive — and recordBranchRefinement itself is the
677 // virtual customisation point (FullSparse routes to
678 // refinementTrace instead of touching `as`).
679 const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(objId));
681 {
683 if (cur.isInterval())
684 {
688 as.store(addr, AbstractValue(itv));
689 }
690 }
691}

◆ 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:115
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)
bool isAddr() const

◆ 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

Reimplemented in SVF::FullSparseAbstractInterpretation.

Definition at line 359 of file AbstractStateManager.cpp.

360{
361 const AbstractValue& ptrVal = getAbsValue(pointer, node);
363 for (auto addr : ptrVal.getAddrs())
364 {
365 // Null and black-hole addresses have no backing object.
367 continue;
368 updateAbsValue(svfir->getSVFVar(as.getIDFromAddr(addr)), val, node);
369 }
370}

◆ 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 1053 of file AbstractInterpretation.cpp.

1054{
1055 const ICFGNode* node = addr->getICFGNode();
1056 // initObjVar mutates _varToAbsVal/_addrToAbsVal directly, so we need
1057 // mutable access; route via the manager.
1058 AbstractState& as = getAbsState(node);
1059 as.initObjVar(SVFUtil::cast<ObjVar>(addr->getRHSVar()));
1060 // AddrStmt: lhs(ValVar) = &rhs(ObjVar).
1061 // as[rhsId] stores the ObjVar's virtual address in _varToVal,
1062 // NOT the object contents. So we must use as[] directly for ObjVar.
1063 u32_t rhsId = addr->getRHSVarID();
1064 if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy)
1065 as[rhsId].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType()));
1066 // LHS is a ValVar (pointer), write through the API
1067 updateAbsValue(addr->getLHSVar(), as[rhsId], node);
1068}
IntervalValue getRangeLimitFromType(const SVFType *type)
Gets the range limit from a type.

◆ updateStateOnBinary()

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

Definition at line 1071 of file AbstractInterpretation.cpp.

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

◆ 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 1028 of file AbstractInterpretation.cpp.

1029{
1030 const ICFGNode* node = callPE->getICFGNode();
1031 const SVFVar* res = callPE->getRes();
1033 for (u32_t i = 0; i < callPE->getOpVarNum(); i++)
1034 {
1035 const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
1037 {
1038 const AbstractValue& opVal = getAbsValue(callPE->getOpVar(i), opICFGNode);
1039 rhs.join_with(opVal);
1040 }
1041 }
1042 updateAbsValue(res, rhs, node);
1043}
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 1234 of file AbstractInterpretation.cpp.

1235{
1236 const ICFGNode* node = cmp->getICFGNode();
1237 const AbstractValue& lhsValue = getAbsValue(cmp->getOpVar(0), node);
1238 const AbstractValue& rhsValue = getAbsValue(cmp->getOpVar(1), node);
1239 const bool pointerCmp = cmp->getOpVar(0)->getType()->isPointerTy();
1240 assert(pointerCmp == cmp->getOpVar(1)->getType()->isPointerTy() &&
1241 "CmpStmt operands must belong to the same value domain");
1242
1244 if (pointerCmp)
1245 {
1246 result = evaluatePointerCmp(cmp->getPredicate(), lhsValue.getAddrs(),
1247 rhsValue.getAddrs());
1248 }
1249 else
1250 {
1251 const IntervalValue lhs = lhsValue.isInterval()
1252 ? lhsValue.getInterval()
1254 const IntervalValue rhs = rhsValue.isInterval()
1255 ? rhsValue.getInterval()
1257 result = evaluateIntervalCmp(cmp->getPredicate(), lhs, rhs);
1258 }
1259 updateAbsValue(cmp->getRes(), result, node);
1260}
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 1277 of file AbstractInterpretation.cpp.

1278{
1279 const ICFGNode* node = copy->getICFGNode();
1280 const SVFVar* lhsVar = copy->getLHSVar();
1281 const SVFVar* rhsVar = copy->getRHSVar();
1282
1283 auto getZExtValue = [&](const SVFVar* var)
1284 {
1285 const SVFType* type = var->getType();
1286 if (SVFUtil::isa<SVFIntegerType>(type))
1287 {
1288 u32_t bits = type->getByteSize() * 8;
1289 const AbstractValue& val = getAbsValue(var, node);
1290 if (val.getInterval().is_numeral())
1291 {
1292 if (bits == 8)
1293 {
1294 int8_t signed_i8_value = val.getInterval().getIntNumeral();
1297 }
1298 else if (bits == 16)
1299 {
1300 s16_t signed_i16_value = val.getInterval().getIntNumeral();
1303 }
1304 else if (bits == 32)
1305 {
1306 s32_t signed_i32_value = val.getInterval().getIntNumeral();
1309 }
1310 else if (bits == 64)
1311 {
1312 s64_t signed_i64_value = val.getInterval().getIntNumeral();
1314 }
1315 else
1316 assert(false && "cannot support int type other than u8/16/32/64");
1317 }
1318 else
1319 {
1320 return IntervalValue::top();
1321 }
1322 }
1323 return IntervalValue::top();
1324 };
1325
1326 auto getTruncValue = [&](const SVFVar* var, const SVFType* dstType)
1327 {
1328 const IntervalValue& itv = getAbsValue(var, node).getInterval();
1329 if(itv.isBottom()) return itv;
1331 s64_t int_ub = itv.ub().getIntNumeral();
1332 u32_t dst_bits = dstType->getByteSize() * 8;
1333 if (dst_bits == 8)
1334 {
1335 int8_t s8_lb = static_cast<int8_t>(int_lb);
1336 int8_t s8_ub = static_cast<int8_t>(int_ub);
1337 if (s8_lb > s8_ub)
1339 return IntervalValue(s8_lb, s8_ub);
1340 }
1341 else if (dst_bits == 16)
1342 {
1343 s16_t s16_lb = static_cast<s16_t>(int_lb);
1344 s16_t s16_ub = static_cast<s16_t>(int_ub);
1345 if (s16_lb > s16_ub)
1347 return IntervalValue(s16_lb, s16_ub);
1348 }
1349 else if (dst_bits == 32)
1350 {
1351 s32_t s32_lb = static_cast<s32_t>(int_lb);
1352 s32_t s32_ub = static_cast<s32_t>(int_ub);
1353 if (s32_lb > s32_ub)
1355 return IntervalValue(s32_lb, s32_ub);
1356 }
1357 else
1358 {
1359 assert(false && "cannot support dst int type other than u8/16/32");
1360 abort();
1361 }
1362 };
1363
1364 const AbstractValue& rhsVal = getAbsValue(rhsVar, node);
1365
1366 if (copy->getCopyKind() == CopyStmt::COPYVAL)
1367 {
1369 }
1370 else if (copy->getCopyKind() == CopyStmt::ZEXT)
1371 {
1372 updateAbsValue(lhsVar, getZExtValue(rhsVar), node);
1373 }
1374 else if (copy->getCopyKind() == CopyStmt::SEXT)
1375 {
1376 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1377 }
1378 else if (copy->getCopyKind() == CopyStmt::FPTOSI)
1379 {
1380 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1381 }
1382 else if (copy->getCopyKind() == CopyStmt::FPTOUI)
1383 {
1384 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1385 }
1386 else if (copy->getCopyKind() == CopyStmt::SITOFP)
1387 {
1388 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1389 }
1390 else if (copy->getCopyKind() == CopyStmt::UITOFP)
1391 {
1392 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1393 }
1394 else if (copy->getCopyKind() == CopyStmt::TRUNC)
1395 {
1396 updateAbsValue(lhsVar, getTruncValue(rhsVar, lhsVar->getType()), node);
1397 }
1398 else if (copy->getCopyKind() == CopyStmt::FPTRUNC)
1399 {
1400 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1401 }
1402 else if (copy->getCopyKind() == CopyStmt::INTTOPTR)
1403 {
1404 //insert nullptr
1405 }
1406 else if (copy->getCopyKind() == CopyStmt::PTRTOINT)
1407 {
1409 }
1410 else if (copy->getCopyKind() == CopyStmt::BITCAST)
1411 {
1412 if (rhsVal.isAddr())
1414 }
1415 else
1416 assert(false && "undefined copy kind");
1417}
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 966 of file AbstractInterpretation.cpp.

967{
968 const ICFGNode* node = gep->getICFGNode();
970 AddressValue gepAddrs = getGepObjAddrs(SVFUtil::cast<ValVar>(gep->getRHSVar()), offsetPair);
971 updateAbsValue(gep->getLHSVar(), gepAddrs, node);
972}
AddressValue getGepObjAddrs(const ValVar *pointer, IntervalValue offset)
IntervalValue getGepElementIndex(const GepStmt *gep)

◆ updateStateOnLoad()

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

Definition at line 1262 of file AbstractInterpretation.cpp.

1263{
1264 const ICFGNode* node = load->getICFGNode();
1266 loadValue(SVFUtil::cast<ValVar>(load->getRHSVar()), node);
1267 updateAbsValue(load->getLHSVar(), loaded, node);
1268}
virtual AbstractValue loadValue(const ValVar *pointer, const ICFGNode *node)
Virtual so full-sparse can layer the GepObj overlay on top.
const ValVar * getLHSVar() const

◆ updateStateOnPhi()

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

Definition at line 993 of file AbstractInterpretation.cpp.

994{
995 const ICFGNode* icfgNode = phi->getICFGNode();
997 for (u32_t i = 0; i < phi->getOpVarNum(); i++)
998 {
999 const ICFGNode* opICFGNode = phi->getOpICFGNode(i);
1001 {
1003 const AbstractValue& opVal = getAbsValue(phi->getOpVar(i), opICFGNode);
1005 if (edge)
1006 {
1007 const IntraCFGEdge* intraEdge = SVFUtil::cast<IntraCFGEdge>(edge);
1008 if (intraEdge->getCondition())
1009 {
1011 rhs.join_with(opVal);
1012 }
1013 else
1014 rhs.join_with(opVal);
1015 }
1016 else
1017 {
1018 rhs.join_with(opVal);
1019 }
1020 }
1021 }
1022 updateAbsValue(phi->getRes(), rhs, icfgNode);
1023}
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 1045 of file AbstractInterpretation.cpp.

1046{
1047 const ICFGNode* node = retPE->getICFGNode();
1048 const AbstractValue& rhsVal = getAbsValue(retPE->getRHSVar(), node);
1049 updateAbsValue(retPE->getLHSVar(), rhsVal, node);
1050}
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const

◆ updateStateOnSelect()

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

Definition at line 974 of file AbstractInterpretation.cpp.

975{
976 const ICFGNode* node = select->getICFGNode();
977 const AbstractValue& condVal = getAbsValue(select->getCondition(), node);
978 const AbstractValue& tVal = getAbsValue(select->getTrueValue(), node);
979 const AbstractValue& fVal = getAbsValue(select->getFalseValue(), node);
981 if (condVal.getInterval().is_numeral())
982 {
984 }
985 else
986 {
987 resVal = tVal;
988 resVal.join_with(fVal);
989 }
990 updateAbsValue(select->getRes(), resVal, node);
991}
bool is_zero() const
Return true if the IntervalValue is [0, 0].

◆ updateStateOnStore()

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

Definition at line 1270 of file AbstractInterpretation.cpp.

1271{
1272 const ICFGNode* node = store->getICFGNode();
1273 AbstractValue val = getAbsValue(store->getRHSVar(), node);
1274 storeValue(SVFUtil::cast<ValVar>(store->getLHSVar()), val, node);
1275}
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 347 of file AbstractInterpretation.h.

◆ allAnalyzedNodes

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

Definition at line 337 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 312 of file AbstractInterpretation.h.

312{nullptr};

◆ callGraph

CallGraph* SVF::AbstractInterpretation::callGraph
private

Definition at line 315 of file AbstractInterpretation.h.

◆ detectors

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

Definition at line 340 of file AbstractInterpretation.h.

◆ func_map

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

Definition at line 335 of file AbstractInterpretation.h.

◆ icfg

ICFG* SVF::AbstractInterpretation::icfg
private

Definition at line 314 of file AbstractInterpretation.h.

◆ moduleName

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

Definition at line 338 of file AbstractInterpretation.h.

◆ preAnalysis

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

Definition at line 346 of file AbstractInterpretation.h.

346{nullptr};

◆ stat

AEStat* SVF::AbstractInterpretation::stat
private

Definition at line 316 of file AbstractInterpretation.h.

◆ svfir

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

Data and helpers reachable from SparseAbstractInterpretation.

Definition at line 345 of file AbstractInterpretation.h.

345{nullptr};

◆ utils

AbsExtAPI* SVF::AbstractInterpretation::utils
private

Definition at line 341 of file AbstractInterpretation.h.


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