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 }
 

Public Member Functions

virtual void runOnModule ()
 
virtual ~AbstractInterpretation ()
 Destructor.
 
void analyse ()
 Program entry.
 
void analyzeFromAllProgEntries ()
 Analyze all entry points (functions without callers)
 
std::deque< const FunObjVar * > collectProgEntryFuns ()
 Get all entry point functions (functions without callers)
 
void addDetector (std::unique_ptr< AEDetector > detector)
 
const SVFVargetSVFVar (NodeID varId) const
 Retrieve SVFVar given its ID; asserts if no such variable exists.
 
virtual const AbstractValuegetAbsValue (const ValVar *var, const ICFGNode *node)
 
virtual const AbstractValuegetAbsValue (const ObjVar *var, const ICFGNode *node)
 
virtual const AbstractValuegetAbsValue (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)
 
AbstractStategetAbsState (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)
 
AbstractValue loadValue (const ValVar *pointer, const ICFGNode *node)
 
void storeValue (const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
 
const SVFTypegetPointeeElement (const ObjVar *var, const ICFGNode *node)
 
u32_t getAllocaInstByteSize (const AddrStmt *addr)
 
Map< const ICFGNode *, AbstractState > & getTrace ()
 
AbstractStateoperator[] (const ICFGNode *node)
 

Static Public Member Functions

static AbstractInterpretationgetAEInstance ()
 

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)
 
bool shouldApplyNarrowing (const FunObjVar *fun)
 Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.
 

Protected Attributes

SVFIRsvfir {nullptr}
 Data and helpers reachable from SparseAbstractInterpretation.
 
AEWTOpreAnalysis {nullptr}
 
Map< const ICFGNode *, AbstractStateabstractTrace
 per-node trace; owned here
 

Private Member Functions

virtual void handleGlobalNode ()
 Initialize abstract state for the global ICFG node and process global statements.
 
bool mergeStatesFromPredecessors (const ICFGNode *node)
 
bool isBranchFeasible (const IntraCFGEdge *edge, AbstractState &as)
 Returns true if the branch is reachable; narrows as in-place.
 
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=nullptr)
 Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration.
 
void handleFunction (const ICFGNode *funEntry, const CallICFGNode *caller=nullptr)
 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 isCmpBranchFeasible (const IntraCFGEdge *edge, AbstractState &as)
 Returns true if the cmp-conditional branch is feasible; narrows as in-place.
 
bool isSwitchBranchFeasible (const IntraCFGEdge *edge, AbstractState &as)
 Returns true if the switch branch is feasible; narrows as in-place.
 
void updateStateOnAddr (const AddrStmt *addr)
 
void updateStateOnBinary (const BinaryOPStmt *binary)
 
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)
 
AbsExtAPIgetUtils ()
 
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 FunObjVargetCallee (const CallICFGNode *callNode)
 Get callee function: directly for direct calls, via pointer analysis for indirect calls.
 

Private Attributes

AEAPIapi {nullptr}
 Execution State, used to store the Interval Value of every SVF variable.
 
ICFGicfg
 
CallGraphcallGraph
 
AEStatstat
 
Map< std::string, std::function< void(const CallICFGNode *)> > func_map
 
Set< const ICFGNode * > allAnalyzedNodes
 
std::string moduleName
 
std::vector< std::unique_ptr< AEDetector > > detectors
 
AbsExtAPIutils
 

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

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

63{
64 stat = new AEStat(this);
65 // Run Andersen's pointer analysis and build WTO
67 icfg = svfir->getICFG();
72}
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:427
ICFG * getICFG() const
Definition SVFIR.h:229
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:118

Member Function Documentation

◆ addDetector()

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

Definition at line 118 of file AbstractInterpretation.h.

119 {
120 detectors.push_back(std::move(detector));
121 }
std::vector< std::unique_ptr< AEDetector > > detectors
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ analyse()

void AbstractInterpretation::analyse ( )

Program entry.

Program entry - analyze from all entry points (multi-entry analysis is the default)

Definition at line 144 of file AbstractInterpretation.cpp.

145{
146 // Always use multi-entry analysis from all entry points
148}
void analyzeFromAllProgEntries()
Analyze all entry points (functions without callers)

◆ analyzeFromAllProgEntries()

void AbstractInterpretation::analyzeFromAllProgEntries ( )

Analyze all entry points (functions without callers)

Analyze all entry points (functions without callers) - for whole-program analysis. Abstract state is shared across entry points so that functions analyzed from earlier entries are not re-analyzed from scratch.

Definition at line 153 of file AbstractInterpretation.cpp.

154{
155 // Collect all entry point functions
156 std::deque<const FunObjVar*> entryFunctions = collectProgEntryFuns();
157
158 if (entryFunctions.empty())
159 {
160 assert(false && "No entry functions found for analysis");
161 return;
162 }
163 // handle Global ICFGNode of SVFModule
165 for (const FunObjVar* entryFun : entryFunctions)
166 {
169 }
170}
virtual void handleGlobalNode()
Initialize abstract state for the global ICFG node and process global statements.
void handleFunction(const ICFGNode *funEntry, const CallICFGNode *caller=nullptr)
Handle a function body via worklist-driven WTO traversal starting from funEntry.
std::deque< const FunObjVar * > collectProgEntryFuns()
Get all entry point functions (functions without callers)
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:242

◆ collectProgEntryFuns()

std::deque< const FunObjVar * > AbstractInterpretation::collectProgEntryFuns ( )

Get all entry point functions (functions without callers)

Collect entry point functions for analysis. Entry points are functions without callers (no incoming edges in CallGraph). Uses a deque to allow efficient insertion at front for prioritizing main()

Definition at line 111 of file AbstractInterpretation.cpp.

112{
113 std::deque<const FunObjVar*> entryFunctions;
114
115 for (auto it = callGraph->begin(); it != callGraph->end(); ++it)
116 {
117 const CallGraphNode* cgNode = it->second;
118 const FunObjVar* fun = cgNode->getFunction();
119
120 // Skip declarations
121 if (fun->isDeclaration())
122 continue;
123
124 // Entry points are functions without callers (no incoming edges)
125 if (cgNode->getInEdges().empty())
126 {
127 // If main exists, put it first for priority using deque's push_front
128 if (fun->getName() == "main")
129 {
130 entryFunctions.push_front(fun);
131 }
132 else
133 {
134 entryFunctions.push_back(fun);
135 }
136 }
137 }
138
139 return entryFunctions;
140}
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
bool isDeclaration() const
iterator begin()
Iterators.
const GEdgeSetTy & getInEdges() const
virtual const std::string & getName() const
Definition SVFValue.h:189

◆ 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 168 of file AbstractStateManager.cpp.

169{
171 for (const ObjVar* var : vars)
172 {
174 result.store(addr, as.load(addr));
175 }
176}
unsigned u32_t
Definition CommandLine.h:18
AbstractState & getAbsState(const ICFGNode *node)
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 178 of file AbstractStateManager.cpp.

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

◆ getAbsState() [4/4]

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

Definition at line 158 of file AbstractStateManager.cpp.

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

◆ getAbsValue() [1/3]

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

◆ getAbsValue() [2/3]

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

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

Definition at line 97 of file AbstractStateManager.cpp.

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

◆ 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 top sentinel for genuinely missing entries (e.g. function parameters like argc, 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, SVF::FullSparseAbstractInterpretation, SVF::SemiSparseAbstractInterpretation, SVF::FullSparseAbstractInterpretation, and SVF::FullSparseAbstractInterpretation.

Definition at line 80 of file AbstractStateManager.cpp.

81{
82 u32_t id = var->getId();
84 if (as.getVarToVal().count(id))
85 return as[id];
86 as[id] = IntervalValue::top();
87 return as[id];
88}
static IntervalValue top()
Create the IntervalValue [-inf, +inf].

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

78{
79 static std::unique_ptr<AbstractInterpretation> instance = []()
80 -> std::unique_ptr<AbstractInterpretation>
81 {
82 switch (Options::AESparsity())
83 {
85 return std::unique_ptr<AbstractInterpretation>(
88 return std::unique_ptr<AbstractInterpretation>(
91 default:
92 return std::unique_ptr<AbstractInterpretation>(
94 }
95 }();
96 return *instance;
97}
static const OptionMap< u32_t > AESparsity
Definition Options.h:243

◆ getAllocaInstByteSize()

u32_t AbstractInterpretation::getAllocaInstByteSize ( const AddrStmt addr)

Definition at line 370 of file AbstractStateManager.cpp.

371{
372 const ICFGNode* node = addr->getICFGNode();
373 if (const ObjVar* objvar = SVFUtil::dyn_cast<ObjVar>(addr->getRHSVar()))
374 {
376 {
377 return svfir->getBaseObject(objvar->getId())->getByteSizeOfObj();
378 }
379 else
380 {
381 const std::vector<SVFVar*>& sizes = addr->getArrSize();
382 u32_t elementSize = 1;
383 u64_t res = elementSize;
384 for (const SVFVar* value : sizes)
385 {
386 const AbstractValue& sizeVal = getAbsValue(value, node);
387 IntervalValue itv = sizeVal.getInterval();
388 if (itv.isBottom())
390 res = res * itv.ub().getIntNumeral() > Options::MaxFieldLimit()
391 ? Options::MaxFieldLimit() : res * itv.ub().getIntNumeral();
392 }
393 return (u32_t)res;
394 }
395 }
396 assert(false && "Addr rhs value is not ObjVar");
397 abort();
398}
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:35
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:496
unsigned long long u64_t
Definition GeneralType.h:49

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

673{
674 // Direct call: get callee directly from call node
675 if (const FunObjVar* callee = callNode->getCalledFunction())
676 return callee;
677
678 // Indirect call: resolve callee through pointer analysis
680 auto it = callsiteMaps.find(callNode);
681 if (it == callsiteMaps.end())
682 return nullptr;
683
684 NodeID call_id = it->second;
685 if (!hasAbsState(callNode))
686 return nullptr;
687
689 if (!Addrs.isAddr() || Addrs.getAddrs().empty())
690 return nullptr;
691
692 NodeID addr = *Addrs.getAddrs().begin();
693 const SVFVar* func_var = getSVFVar(getAbsState(callNode).getIDFromAddr(addr));
694 return SVFUtil::dyn_cast<FunObjVar>(func_var);
695}
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:451
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:133
u32_t NodeID
Definition GeneralType.h:56

◆ 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 253 of file AbstractStateManager.cpp.

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

◆ getGepElementIndex()

IntervalValue AbstractInterpretation::getGepElementIndex ( const GepStmt gep)

Definition at line 196 of file AbstractStateManager.cpp.

197{
198 const ICFGNode* node = gep->getICFGNode();
199 if (gep->isConstantOffset())
200 return IntervalValue((s64_t)gep->accumulateConstantOffset());
201
202 IntervalValue res(0);
203 for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
204 {
205 const ValVar* var = gep->getOffsetVarAndGepTypePairVec()[i].first;
206 const SVFType* type = gep->getOffsetVarAndGepTypePairVec()[i].second;
207
209 if (const ConstIntValVar* constInt = SVFUtil::dyn_cast<ConstIntValVar>(var))
210 idxLb = idxUb = constInt->getSExtValue();
211 else
212 {
214 if (idxItv.isBottom())
215 idxLb = idxUb = 0;
216 else
217 {
219 idxUb = idxItv.ub().getIntNumeral();
220 }
221 }
222
223 if (SVFUtil::isa<SVFPointerType>(type))
224 {
225 u32_t elemNum = gep->getAccessPath().getElementNum(gep->getAccessPath().gepSrcPointeeType());
226 idxLb = (double)Options::MaxFieldLimit() / elemNum < idxLb ? Options::MaxFieldLimit() : idxLb * elemNum;
227 idxUb = (double)Options::MaxFieldLimit() / elemNum < idxUb ? Options::MaxFieldLimit() : idxUb * elemNum;
228 }
229 else
230 {
232 {
233 const std::vector<u32_t>& so = PAG::getPAG()->getTypeInfo(type)->getFlattenedElemIdxVec();
234 if (so.empty() || idxUb >= (APOffset)so.size() || idxLb < 0)
235 idxLb = idxUb = 0;
236 else
237 {
240 }
241 }
242 else
243 idxLb = idxUb = 0;
244 }
245 res = res + IntervalValue(idxLb, idxUb);
246 }
247 res.meet_with(IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit()));
248 if (res.isBottom())
249 res = IntervalValue(0);
250 return res;
251}
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:144
const StInfo * getTypeInfo(const SVFType *T) const
Get struct info.
Definition IRGraph.cpp:242
const BoundedInt & lb() const
Return the lower bound.
static Option< bool > ModelArrays
Definition Options.h:185
std::vector< u32_t > & getFlattenedElemIdxVec()
Definition SVFType.h:125
s64_t APOffset
Definition GeneralType.h:60

◆ getGepObjAddrs()

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

Definition at line 313 of file AbstractStateManager.cpp.

314{
315 const ICFGNode* node = pointer->getICFGNode();
318 APOffset lb = offset.lb().getIntNumeral() < Options::MaxFieldLimit() ? offset.lb().getIntNumeral()
320 APOffset ub = offset.ub().getIntNumeral() < Options::MaxFieldLimit() ? offset.ub().getIntNumeral()
322 for (APOffset i = lb; i <= ub; i++)
323 {
324 const AbstractValue& addrs = getAbsValue(pointer, node);
325 for (const auto& addr : addrs.getAddrs())
326 {
327 s64_t baseObj = as.getIDFromAddr(addr);
328 assert(SVFUtil::isa<ObjVar>(svfir->getSVFVar(baseObj)) && "Fail to get the base object address!");
332 }
333 }
334 return gepAddrs;
335}
buffer offset
Definition cJSON.cpp:1113
const GepObjVar * getGepObjVar(NodeID id) const
Definition SVFIR.h:167
const ICFGNode * getICFGNode() const

◆ getPointeeElement()

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

Definition at line 355 of file AbstractStateManager.cpp.

356{
357 const AbstractValue& ptrVal = getAbsValue(var, node);
358 if (!ptrVal.isAddr())
359 return nullptr;
360 for (auto addr : ptrVal.getAddrs())
361 {
363 if (objId == 0)
364 continue;
365 return svfir->getBaseObject(objId)->getType();
366 }
367 return nullptr;
368}
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 124 of file AbstractInterpretation.h.

125 {
126 return svfir->getSVFVar(varId);
127 }

◆ getTrace()

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

Definition at line 183 of file AbstractInterpretation.h.

184 {
185 return abstractTrace;
186 }

◆ getUtils()

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

Definition at line 279 of file AbstractInterpretation.h.

280 {
281 return utils;
282 }

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

640{
641 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
642 {
643 if (isExtCall(callNode))
644 {
646 }
647 else
648 {
649 // Handle both direct and indirect calls uniformly
651 }
652 }
653 else
654 assert (false && "it is not call node");
655}
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 662 of file AbstractInterpretation.cpp.

663{
665 for (auto& detector : detectors)
666 {
667 detector->handleStubFunctions(callNode);
668 }
669}
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 706 of file AbstractInterpretation.cpp.

707{
709 return;
710
711 // Direct call: callee is known
712 if (const FunObjVar* callee = callNode->getCalledFunction())
713 {
716 const RetICFGNode* retNode = callNode->getRetICFGNode();
718 return;
719 }
720
721 // Indirect call: use Andersen's call graph to get all resolved callees.
722 const RetICFGNode* retNode = callNode->getRetICFGNode();
724 {
726 for (const FunObjVar* callee : callees)
727 {
728 if (callee->isDeclaration())
729 continue;
732 }
733 }
734 // Resume return node from caller's state (context-insensitive)
736}
bool skipRecursiveCall(const CallICFGNode *callNode)
Skip recursive callsites (within SCC); entry calls from outside SCC are not skipped.
virtual void updateAbsState(const ICFGNode *node, const AbstractState &state)
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 = nullptr 
)
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 611 of file AbstractInterpretation.cpp.

612{
613 auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
614 if (it == preAnalysis->getFuncToWTO().end())
615 return;
616
617 // Push all top-level WTO components into the worklist in WTO order
618 FIFOWorkList<const ICFGWTOComp*> worklist(it->second->getWTOComponents());
619
620 while (!worklist.empty())
621 {
622 const ICFGWTOComp* comp = worklist.pop();
623
624 if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
625 {
626 const ICFGNode* node = singleton->getICFGNode();
628 handleICFGNode(node);
629 }
630 else if (const ICFGCycleWTO* cycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
631 {
632 if (mergeStatesFromPredecessors(cycle->head()->getICFGNode()))
634 }
635 }
636}
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.
bool mergeStatesFromPredecessors(const ICFGNode *node)
virtual void handleLoopOrRecursion(const ICFGCycleWTO *cycle, const CallICFGNode *caller=nullptr)
Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration.
WTONode< ICFG > ICFGSingletonWTO
Definition ICFGWTO.h:45
WTOComponent< ICFG > ICFGWTOComp
Definition ICFGWTO.h:44

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

178{
179 const ICFGNode* node = icfg->getGlobalICFGNode();
180 // Global init is one of the few legitimate direct-mutation sites:
181 // updateAbsState filters out ValVars in semi-sparse mode, but NullPtr/
182 // BlkPtr have no SVFVar so we cannot route them through updateAbsValue.
183 // Use the manager's operator[] (auto-creates the entry if absent).
184 AbstractState& init = abstractTrace[node];
185 init = AbstractState();
186 // TODO: we cannot find right SVFVar for NullPtr, so we use init[NullPtr]
187 // directly. Same for BlkPtr below.
189
190 // Global Node, we just need to handle addr, load, store, copy and gep
191 for (const SVFStmt *stmt: node->getSVFStmts())
192 {
194 }
195
196 // BlkPtr represents a pointer whose target is statically unknown (e.g., from
197 // int2ptr casts, external function returns, or unmodeled instructions like
198 // AtomicCmpXchg). It should be an address pointing to the BlackHole object
199 // (ID=2), NOT an interval top.
200 //
201 // History: this was originally set to IntervalValue::top() as a quick fix when
202 // the analysis crashed on programs containing uninitialized BlkPtr. However,
203 // BlkPtr is semantically a *pointer* (address domain), not a numeric value
204 // (interval domain). Setting it to interval top broke cross-domain consistency:
205 // the interval domain and address domain gave contradictory information for the
206 // same variable. The correct representation is an AddressValue containing the
207 // BlackHole virtual address, which means "points to unknown memory".
209}
#define BlackHoleObjAddr
virtual void handleSVFStatement(const SVFStmt *stmt)
Dispatch an SVF statement (Addr/Binary/Cmp/Load/Store/Copy/Gep/Select/Phi/Call/Ret) to its handler.
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244
NodeID getBlkPtr() const
Definition IRGraph.h:255

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

553{
554 // Check reachability: pre-state must have been propagated by predecessors
555 bool isFunEntry = SVFUtil::isa<FunEntryICFGNode>(node);
556 if (!hasAbsState(node))
557 {
558 if (isFunEntry)
559 {
560 // Entry point with no callers: inherit from global node
564 else
566 }
567 else
568 {
569 return false; // unreachable node
570 }
571 }
572
573 // Store the previous state for fixpoint detection
575
576 stat->getBlockTrace()++;
578
579 // Handle SVF statements
580 for (const SVFStmt *stmt: node->getSVFStmts())
581 {
583 }
584
585 // Handle call sites
586 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
587 {
589 }
590
591 // Run detectors
592 for (auto& detector: detectors)
593 detector->detect(node);
595
596 // Track this node as analyzed (for coverage statistics across all entry points)
597 allAnalyzedNodes.insert(node);
598
599 if (getAbsState(node) == prevState)
600 return false;
601
602 return true;
603}
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 = nullptr 
)
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:246
static const Option< u32_t > WidenDelay
Definition Options.h:244

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

742{
743 if (const AddrStmt *addr = SVFUtil::dyn_cast<AddrStmt>(stmt))
744 {
746 }
747 else if (const BinaryOPStmt *binary = SVFUtil::dyn_cast<BinaryOPStmt>(stmt))
748 {
750 }
751 else if (const CmpStmt *cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
752 {
754 }
755 else if (SVFUtil::isa<UnaryOPStmt>(stmt))
756 {
757 }
758 else if (SVFUtil::isa<BranchStmt>(stmt))
759 {
760 // branch stmt is handled in hasBranchES
761 }
762 else if (const LoadStmt *load = SVFUtil::dyn_cast<LoadStmt>(stmt))
763 {
764 updateStateOnLoad(load);
765 }
766 else if (const StoreStmt *store = SVFUtil::dyn_cast<StoreStmt>(stmt))
767 {
768 updateStateOnStore(store);
769 }
770 else if (const CopyStmt *copy = SVFUtil::dyn_cast<CopyStmt>(stmt))
771 {
773 }
774 else if (const GepStmt *gep = SVFUtil::dyn_cast<GepStmt>(stmt))
775 {
777 }
778 else if (const SelectStmt *select = SVFUtil::dyn_cast<SelectStmt>(stmt))
779 {
781 }
782 else if (const PhiStmt *phi = SVFUtil::dyn_cast<PhiStmt>(stmt))
783 {
785 }
786 else if (const CallPE *callPE = SVFUtil::dyn_cast<CallPE>(stmt))
787 {
788 // To handle Call Edge
789 updateStateOnCall(callPE);
790 }
791 else if (const RetPE *retPE = SVFUtil::dyn_cast<RetPE>(stmt))
792 {
793 updateStateOnRet(retPE);
794 }
795 else
796 assert(false && "implement this part");
797 // NullPtr should not be changed by any statement. If the entry is missing
798 // (not yet auto-inserted) we treat that as "unchanged" — only check the
799 // entry if it actually exists.
800 {
801 const auto& vmap = getAbsState(stmt->getICFGNode()).getVarToVal();
802 auto it = vmap.find(IRGraph::NullPtr);
803 assert(it == vmap.end() ||
804 (!it->second.isInterval() && !it->second.isAddr()));
805 }
806}
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, and SVF::FullSparseAbstractInterpretation.

Definition at line 119 of file AbstractStateManager.cpp.

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

◆ hasAbsValue() [2/3]

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

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

Definition at line 127 of file AbstractStateManager.cpp.

128{
129 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
130 return hasAbsValue(objVar, node);
131 if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
132 return hasAbsValue(valVar, node);
133 return false;
134}
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, SVF::FullSparseAbstractInterpretation, SVF::SemiSparseAbstractInterpretation, SVF::FullSparseAbstractInterpretation, and SVF::FullSparseAbstractInterpretation.

Definition at line 111 of file AbstractStateManager.cpp.

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

◆ isBranchFeasible()

bool AbstractInterpretation::isBranchFeasible ( const IntraCFGEdge edge,
AbstractState as 
)
private

Returns true if the branch is reachable; narrows as in-place.

Definition at line 536 of file AbstractInterpretation.cpp.

538{
539 const SVFVar* cmpVar = edge->getCondition();
540 assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
541 if (SVFUtil::isa<CmpStmt>(*cmpVar->getInEdges().begin()))
542 return isCmpBranchFeasible(edge, as);
544}
bool isSwitchBranchFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the switch branch is feasible; narrows as in-place.
bool isCmpBranchFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the cmp-conditional branch is feasible; narrows as in-place.

◆ isCmpBranchFeasible()

bool AbstractInterpretation::isCmpBranchFeasible ( const IntraCFGEdge edge,
AbstractState as 
)
private

Returns true if the cmp-conditional branch is feasible; narrows as in-place.

Definition at line 440 of file AbstractInterpretation.cpp.

442{
443 const ICFGNode* pred = edge->getSrcNode();
444 s64_t succ = edge->getSuccessorCondValue();
445 const CmpStmt* cmpStmt = SVFUtil::cast<CmpStmt>(
446 *edge->getCondition()->getInEdges().begin());
447 s32_t predicate = cmpStmt->getPredicate();
448
449 if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
450 cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
451 return true;
452
454 {
455 getAbsValue(cmpStmt->getOpVar(0), pred),
456 getAbsValue(cmpStmt->getOpVar(1), pred)
457 };
458 if (opVal[0].isAddr() || opVal[1].isAddr())
459 return true;
460
461 // Feasibility check: cmp result must be compatible with branch successor
464 if (resVal.isBottom())
465 return false;
466
467 // For each operand: if it is the variable side (non-constant), has a
468 // backing load, and the branch imposes a useful constraint, narrow the
469 // ObjVar behind the load.
470 for (int i = 0; i < 2; i++)
471 {
472 if (opVal[i].getInterval().is_numeral() || !opVal[1-i].getInterval().is_numeral())
473 continue; // skip constant operands and var-vs-var
474
475 if (const LoadStmt* load = findBackingLoad(cmpStmt->getOpVar(i)))
476 {
478 predicate, succ, i == 0,
479 opVal[i].getInterval(), opVal[1-i].getInterval());
480
481 if (!narrowed.isTop())
482 {
483 const AbstractValue& ptrVal = getAbsValue(load->getRHSVar(), pred);
484 if (ptrVal.isAddr())
485 {
486 for (const auto& addr : ptrVal.getAddrs())
487 {
488 NodeID objId = as.getIDFromAddr(addr);
489 if (as.inAddrToValTable(objId))
490 as.load(addr).meet_with(narrowed);
491 }
492 }
493 }
494 }
495 }
496 return true;
497}
static const LoadStmt * findBackingLoad(const SVFVar *var)
static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ, bool isLHS, const IntervalValue &self, const IntervalValue &other)
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
signed s32_t
Definition GeneralType.h:48

◆ isExtCall()

bool AbstractInterpretation::isExtCall ( const CallICFGNode callNode)
privatevirtual

Definition at line 657 of file AbstractInterpretation.cpp.

658{
659 return SVFUtil::isExtCall(callNode->getCalledFunction());
660}
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:437

◆ 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

◆ isSwitchBranchFeasible()

bool AbstractInterpretation::isSwitchBranchFeasible ( const IntraCFGEdge edge,
AbstractState as 
)
private

Returns true if the switch branch is feasible; narrows as in-place.

Definition at line 499 of file AbstractInterpretation.cpp.

501{
502 const ICFGNode* pred = edge->getSrcNode();
503 s64_t succ = edge->getSuccessorCondValue();
504 const SVFVar* var = edge->getCondition();
505
506 if (!as.inVarToValTable(var->getId()) && !as.inVarToAddrsTable(var->getId()))
507 as[var->getId()] = getAbsValue(var, pred);
508 IntervalValue& switch_cond = as[var->getId()].getInterval();
510 if (switch_cond.isBottom())
511 return false;
512
514 for (SVFStmt* stmt : var->getInEdges())
515 stmtList.push(stmt);
516 while (!stmtList.empty())
517 {
518 const SVFStmt* stmt = stmtList.pop();
519 if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
520 {
521 const AbstractValue& ptrVal = getAbsValue(load->getRHSVar(), pred);
522 if (ptrVal.isAddr())
523 {
524 for (const auto& addr : ptrVal.getAddrs())
525 {
526 NodeID objId = as.getIDFromAddr(addr);
527 if (as.inAddrToValTable(objId))
528 as.load(addr).meet_with(switch_cond);
529 }
530 }
531 }
532 }
533 return true;
534}

◆ 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.

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 
)

Definition at line 337 of file AbstractStateManager.cpp.

338{
339 const AbstractValue& ptrVal = getAbsValue(pointer, node);
341 AbstractValue res;
342 for (auto addr : ptrVal.getAddrs())
343 res.join_with(as.load(addr));
344 return res;
345}

◆ mergeStatesFromPredecessors()

bool AbstractInterpretation::mergeStatesFromPredecessors ( const ICFGNode node)
private

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.

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.

Definition at line 217 of file AbstractInterpretation.cpp.

218{
219 // Collect all feasible predecessor states, then merge at the end.
221 bool hasFeasiblePred = false;
222
223 for (auto& edge : node->getInEdges())
224 {
225 const ICFGNode* pred = edge->getSrcNode();
226 if (!hasAbsState(pred))
227 continue;
228
229 if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
230 {
231 if (intraCfgEdge->getCondition())
232 {
235 {
237 hasFeasiblePred = true;
238 }
239 }
240 else
241 {
243 hasFeasiblePred = true;
244 }
245 }
246 else if (SVFUtil::isa<CallCFGEdge>(edge))
247 {
249 hasFeasiblePred = true;
250 }
251 else if (SVFUtil::isa<RetCFGEdge>(edge))
252 {
253 switch (Options::HandleRecur())
254 {
255 case TOP:
257 hasFeasiblePred = true;
258 break;
259 case WIDEN_ONLY:
260 case WIDEN_NARROW:
261 {
262 const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
263 const CallICFGNode* callSite = returnSite->getCallICFGNode();
265 {
267 hasFeasiblePred = true;
268 }
269 break;
270 }
271 }
272 }
273 }
274
275 if (!hasFeasiblePred)
276 return false;
277
278 updateAbsState(node, merged);
279
280 return true;
281}
bool isBranchFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the branch is reachable; narrows as in-place.
virtual void joinStates(AbstractState &dst, const AbstractState &src)

◆ 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 187 of file AbstractInterpretation.h.

188 {
189 return abstractTrace[node];
190 }

◆ runOnModule()

void AbstractInterpretation::runOnModule ( )
virtual

collect checkpoint

Definition at line 45 of file AbstractInterpretation.cpp.

46{
47 stat->startClk();
48 utils = new AbsExtAPI(this);
51
52 analyse();
54 stat->endClk();
56 if (Options::PStat())
58 for (auto& detector: detectors)
59 detector->reportBug();
60}
void finializeStat()
Definition AEStat.cpp:44
void performStat() override
Definition AEStat.cpp:121
Handles external API calls and manages abstract states.
Definition AbsExtAPI.h:43
void collectCheckPoint()
void checkPointAllSet()
static const Option< bool > PStat
Definition Options.h:116
virtual void endClk()
Definition SVFStat.h:63
virtual void startClk()
Definition SVFStat.h:58

◆ 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 
)

Definition at line 347 of file AbstractStateManager.cpp.

348{
349 const AbstractValue& ptrVal = getAbsValue(pointer, node);
351 for (auto addr : ptrVal.getAddrs())
352 as.store(addr, val);
353}

◆ 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 141 of file AbstractStateManager.cpp.

142{
145 as.store(addr, val);
146}

◆ updateAbsValue() [2/3]

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

Reimplemented in SVF::SemiSparseAbstractInterpretation.

Definition at line 148 of file AbstractStateManager.cpp.

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

◆ 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 136 of file AbstractStateManager.cpp.

137{
138 abstractTrace[node][var->getId()] = val;
139}

◆ updateStateOnAddr()

void AbstractInterpretation::updateStateOnAddr ( const AddrStmt addr)
private

Definition at line 895 of file AbstractInterpretation.cpp.

896{
897 const ICFGNode* node = addr->getICFGNode();
898 // initObjVar mutates _varToAbsVal/_addrToAbsVal directly, so we need
899 // mutable access; route via the manager.
901 as.initObjVar(SVFUtil::cast<ObjVar>(addr->getRHSVar()));
902 // AddrStmt: lhs(ValVar) = &rhs(ObjVar).
903 // as[rhsId] stores the ObjVar's virtual address in _varToVal,
904 // NOT the object contents. So we must use as[] directly for ObjVar.
905 u32_t rhsId = addr->getRHSVarID();
906 if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy)
907 as[rhsId].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType()));
908 // LHS is a ValVar (pointer), write through the API
909 updateAbsValue(addr->getLHSVar(), as[rhsId], node);
910}
IntervalValue getRangeLimitFromType(const SVFType *type)
Gets the range limit from a type.

◆ updateStateOnBinary()

void AbstractInterpretation::updateStateOnBinary ( const BinaryOPStmt binary)
private

Definition at line 913 of file AbstractInterpretation.cpp.

914{
915 const ICFGNode* node = binary->getICFGNode();
916 // Treat bottom (uninitialized) operands as top for soundness
917 const AbstractValue& op0Val = getAbsValue(binary->getOpVar(0), node);
918 const AbstractValue& op1Val = getAbsValue(binary->getOpVar(1), node);
919 IntervalValue lhs = op0Val.getInterval().isBottom() ? IntervalValue::top() : op0Val.getInterval();
920 IntervalValue rhs = op1Val.getInterval().isBottom() ? IntervalValue::top() : op1Val.getInterval();
922 switch (binary->getOpcode())
923 {
926 resVal = (lhs + rhs);
927 break;
930 resVal = (lhs - rhs);
931 break;
934 resVal = (lhs * rhs);
935 break;
939 resVal = (lhs / rhs);
940 break;
944 resVal = (lhs % rhs);
945 break;
947 resVal = (lhs ^ rhs);
948 break;
950 resVal = (lhs & rhs);
951 break;
952 case BinaryOPStmt::Or:
953 resVal = (lhs | rhs);
954 break;
956 resVal = (lhs >> rhs);
957 break;
959 resVal = (lhs << rhs);
960 break;
962 resVal = (lhs >> rhs);
963 break;
964 default:
965 assert(false && "undefined binary: ");
966 }
967 updateAbsValue(binary->getRes(), resVal, node);
968}
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 870 of file AbstractInterpretation.cpp.

871{
872 const ICFGNode* node = callPE->getICFGNode();
873 const SVFVar* res = callPE->getRes();
875 for (u32_t i = 0; i < callPE->getOpVarNum(); i++)
876 {
877 const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
879 {
881 rhs.join_with(opVal);
882 }
883 }
884 updateAbsValue(res, rhs, node);
885}
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
ICFGNode * getICFGNode() const

◆ updateStateOnCmp()

void AbstractInterpretation::updateStateOnCmp ( const CmpStmt cmp)
private

Definition at line 970 of file AbstractInterpretation.cpp.

971{
972 const ICFGNode* node = cmp->getICFGNode();
973 u32_t op0 = cmp->getOpVarID(0);
974 u32_t op1 = cmp->getOpVarID(1);
975 const AbstractValue& op0Val = getAbsValue(cmp->getOpVar(0), node);
976 const AbstractValue& op1Val = getAbsValue(cmp->getOpVar(1), node);
977
978 // if it is address
979 if (op0Val.isAddr() && op1Val.isAddr())
980 {
982 const AddressValue& addrOp0 = op0Val.getAddrs();
983 const AddressValue& addrOp1 = op1Val.getAddrs();
984 if (addrOp0.equals(addrOp1))
985 {
986 resVal = IntervalValue(1, 1);
987 }
988 else if (addrOp0.hasIntersect(addrOp1))
989 {
990 resVal = IntervalValue(0, 1);
991 }
992 else
993 {
994 resVal = IntervalValue(0, 0);
995 }
996 updateAbsValue(cmp->getRes(), resVal, node);
997 }
998 // if op0 or op1 is nullptr, compare abstractValue instead of touching addr or interval
999 else if (op0 == IRGraph::NullPtr || op1 == IRGraph::NullPtr)
1000 {
1001 IntervalValue resVal = (op0Val.equals(op1Val)) ? IntervalValue(1, 1) : IntervalValue(0, 0);
1002 updateAbsValue(cmp->getRes(), resVal, node);
1003 }
1004 else
1005 {
1006 {
1008 if (op0Val.isInterval() && op1Val.isInterval())
1009 {
1010 // Treat bottom (uninitialized) operands as top for soundness
1011 IntervalValue lhs = op0Val.getInterval().isBottom() ? IntervalValue::top() : op0Val.getInterval(),
1012 rhs = op1Val.getInterval().isBottom() ? IntervalValue::top() : op1Val.getInterval();
1013 // AbstractValue
1014 auto predicate = cmp->getPredicate();
1015 switch (predicate)
1016 {
1017 case CmpStmt::ICMP_EQ:
1018 case CmpStmt::FCMP_OEQ:
1019 case CmpStmt::FCMP_UEQ:
1020 resVal = (lhs == rhs);
1021 // resVal = (lhs.getInterval() == rhs.getInterval());
1022 break;
1023 case CmpStmt::ICMP_NE:
1024 case CmpStmt::FCMP_ONE:
1025 case CmpStmt::FCMP_UNE:
1026 resVal = (lhs != rhs);
1027 break;
1028 case CmpStmt::ICMP_UGT:
1029 case CmpStmt::ICMP_SGT:
1030 case CmpStmt::FCMP_OGT:
1031 case CmpStmt::FCMP_UGT:
1032 resVal = (lhs > rhs);
1033 break;
1034 case CmpStmt::ICMP_UGE:
1035 case CmpStmt::ICMP_SGE:
1036 case CmpStmt::FCMP_OGE:
1037 case CmpStmt::FCMP_UGE:
1038 resVal = (lhs >= rhs);
1039 break;
1040 case CmpStmt::ICMP_ULT:
1041 case CmpStmt::ICMP_SLT:
1042 case CmpStmt::FCMP_OLT:
1043 case CmpStmt::FCMP_ULT:
1044 resVal = (lhs < rhs);
1045 break;
1046 case CmpStmt::ICMP_ULE:
1047 case CmpStmt::ICMP_SLE:
1048 case CmpStmt::FCMP_OLE:
1049 case CmpStmt::FCMP_ULE:
1050 resVal = (lhs <= rhs);
1051 break;
1053 resVal = IntervalValue(0, 0);
1054 break;
1055 case CmpStmt::FCMP_TRUE:
1056 resVal = IntervalValue(1, 1);
1057 break;
1058 case CmpStmt::FCMP_ORD:
1059 case CmpStmt::FCMP_UNO:
1060 // FCMP_ORD: true if both operands are not NaN
1061 // FCMP_UNO: true if either operand is NaN
1062 // Conservatively return [0, 1] since we don't track NaN
1063 resVal = IntervalValue(0, 1);
1064 break;
1065 default:
1066 assert(false && "undefined compare: ");
1067 }
1068 updateAbsValue(cmp->getRes(), resVal, node);
1069 }
1070 else if (op0Val.isAddr() && op1Val.isAddr())
1071 {
1072 const AddressValue& lhs = op0Val.getAddrs();
1073 const AddressValue& rhs = op1Val.getAddrs();
1074 auto predicate = cmp->getPredicate();
1075 switch (predicate)
1076 {
1077 case CmpStmt::ICMP_EQ:
1078 case CmpStmt::FCMP_OEQ:
1079 case CmpStmt::FCMP_UEQ:
1080 {
1081 if (lhs.hasIntersect(rhs))
1082 {
1083 resVal = IntervalValue(0, 1);
1084 }
1085 else if (lhs.empty() && rhs.empty())
1086 {
1087 resVal = IntervalValue(1, 1);
1088 }
1089 else
1090 {
1091 resVal = IntervalValue(0, 0);
1092 }
1093 break;
1094 }
1095 case CmpStmt::ICMP_NE:
1096 case CmpStmt::FCMP_ONE:
1097 case CmpStmt::FCMP_UNE:
1098 {
1099 if (lhs.hasIntersect(rhs))
1100 {
1101 resVal = IntervalValue(0, 1);
1102 }
1103 else if (lhs.empty() && rhs.empty())
1104 {
1105 resVal = IntervalValue(0, 0);
1106 }
1107 else
1108 {
1109 resVal = IntervalValue(1, 1);
1110 }
1111 break;
1112 }
1113 case CmpStmt::ICMP_UGT:
1114 case CmpStmt::ICMP_SGT:
1115 case CmpStmt::FCMP_OGT:
1116 case CmpStmt::FCMP_UGT:
1117 {
1118 if (lhs.size() == 1 && rhs.size() == 1)
1119 {
1120 resVal = IntervalValue(*lhs.begin() > *rhs.begin());
1121 }
1122 else
1123 {
1124 resVal = IntervalValue(0, 1);
1125 }
1126 break;
1127 }
1128 case CmpStmt::ICMP_UGE:
1129 case CmpStmt::ICMP_SGE:
1130 case CmpStmt::FCMP_OGE:
1131 case CmpStmt::FCMP_UGE:
1132 {
1133 if (lhs.size() == 1 && rhs.size() == 1)
1134 {
1135 resVal = IntervalValue(*lhs.begin() >= *rhs.begin());
1136 }
1137 else
1138 {
1139 resVal = IntervalValue(0, 1);
1140 }
1141 break;
1142 }
1143 case CmpStmt::ICMP_ULT:
1144 case CmpStmt::ICMP_SLT:
1145 case CmpStmt::FCMP_OLT:
1146 case CmpStmt::FCMP_ULT:
1147 {
1148 if (lhs.size() == 1 && rhs.size() == 1)
1149 {
1150 resVal = IntervalValue(*lhs.begin() < *rhs.begin());
1151 }
1152 else
1153 {
1154 resVal = IntervalValue(0, 1);
1155 }
1156 break;
1157 }
1158 case CmpStmt::ICMP_ULE:
1159 case CmpStmt::ICMP_SLE:
1160 case CmpStmt::FCMP_OLE:
1161 case CmpStmt::FCMP_ULE:
1162 {
1163 if (lhs.size() == 1 && rhs.size() == 1)
1164 {
1165 resVal = IntervalValue(*lhs.begin() <= *rhs.begin());
1166 }
1167 else
1168 {
1169 resVal = IntervalValue(0, 1);
1170 }
1171 break;
1172 }
1174 resVal = IntervalValue(0, 0);
1175 break;
1176 case CmpStmt::FCMP_TRUE:
1177 resVal = IntervalValue(1, 1);
1178 break;
1179 case CmpStmt::FCMP_ORD:
1180 case CmpStmt::FCMP_UNO:
1181 // FCMP_ORD: true if both operands are not NaN
1182 // FCMP_UNO: true if either operand is NaN
1183 // Conservatively return [0, 1] since we don't track NaN
1184 resVal = IntervalValue(0, 1);
1185 break;
1186 default:
1187 assert(false && "undefined compare: ");
1188 }
1189 updateAbsValue(cmp->getRes(), resVal, node);
1190 }
1191 }
1192 }
1193}
@ 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

◆ updateStateOnCopy()

void AbstractInterpretation::updateStateOnCopy ( const CopyStmt copy)
private

Definition at line 1209 of file AbstractInterpretation.cpp.

1210{
1211 const ICFGNode* node = copy->getICFGNode();
1212 const SVFVar* lhsVar = copy->getLHSVar();
1213 const SVFVar* rhsVar = copy->getRHSVar();
1214
1215 auto getZExtValue = [&](const SVFVar* var)
1216 {
1217 const SVFType* type = var->getType();
1218 if (SVFUtil::isa<SVFIntegerType>(type))
1219 {
1220 u32_t bits = type->getByteSize() * 8;
1221 const AbstractValue& val = getAbsValue(var, node);
1222 if (val.getInterval().is_numeral())
1223 {
1224 if (bits == 8)
1225 {
1226 int8_t signed_i8_value = val.getInterval().getIntNumeral();
1229 }
1230 else if (bits == 16)
1231 {
1232 s16_t signed_i16_value = val.getInterval().getIntNumeral();
1235 }
1236 else if (bits == 32)
1237 {
1238 s32_t signed_i32_value = val.getInterval().getIntNumeral();
1241 }
1242 else if (bits == 64)
1243 {
1244 s64_t signed_i64_value = val.getInterval().getIntNumeral();
1246 }
1247 else
1248 assert(false && "cannot support int type other than u8/16/32/64");
1249 }
1250 else
1251 {
1252 return IntervalValue::top();
1253 }
1254 }
1255 return IntervalValue::top();
1256 };
1257
1258 auto getTruncValue = [&](const SVFVar* var, const SVFType* dstType)
1259 {
1260 const IntervalValue& itv = getAbsValue(var, node).getInterval();
1261 if(itv.isBottom()) return itv;
1263 s64_t int_ub = itv.ub().getIntNumeral();
1264 u32_t dst_bits = dstType->getByteSize() * 8;
1265 if (dst_bits == 8)
1266 {
1267 int8_t s8_lb = static_cast<int8_t>(int_lb);
1268 int8_t s8_ub = static_cast<int8_t>(int_ub);
1269 if (s8_lb > s8_ub)
1271 return IntervalValue(s8_lb, s8_ub);
1272 }
1273 else if (dst_bits == 16)
1274 {
1275 s16_t s16_lb = static_cast<s16_t>(int_lb);
1276 s16_t s16_ub = static_cast<s16_t>(int_ub);
1277 if (s16_lb > s16_ub)
1279 return IntervalValue(s16_lb, s16_ub);
1280 }
1281 else if (dst_bits == 32)
1282 {
1283 s32_t s32_lb = static_cast<s32_t>(int_lb);
1284 s32_t s32_ub = static_cast<s32_t>(int_ub);
1285 if (s32_lb > s32_ub)
1287 return IntervalValue(s32_lb, s32_ub);
1288 }
1289 else
1290 {
1291 assert(false && "cannot support dst int type other than u8/16/32");
1292 abort();
1293 }
1294 };
1295
1296 const AbstractValue& rhsVal = getAbsValue(rhsVar, node);
1297
1298 if (copy->getCopyKind() == CopyStmt::COPYVAL)
1299 {
1301 }
1302 else if (copy->getCopyKind() == CopyStmt::ZEXT)
1303 {
1304 updateAbsValue(lhsVar, getZExtValue(rhsVar), node);
1305 }
1306 else if (copy->getCopyKind() == CopyStmt::SEXT)
1307 {
1308 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1309 }
1310 else if (copy->getCopyKind() == CopyStmt::FPTOSI)
1311 {
1312 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1313 }
1314 else if (copy->getCopyKind() == CopyStmt::FPTOUI)
1315 {
1316 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1317 }
1318 else if (copy->getCopyKind() == CopyStmt::SITOFP)
1319 {
1320 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1321 }
1322 else if (copy->getCopyKind() == CopyStmt::UITOFP)
1323 {
1324 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1325 }
1326 else if (copy->getCopyKind() == CopyStmt::TRUNC)
1327 {
1328 updateAbsValue(lhsVar, getTruncValue(rhsVar, lhsVar->getType()), node);
1329 }
1330 else if (copy->getCopyKind() == CopyStmt::FPTRUNC)
1331 {
1332 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1333 }
1334 else if (copy->getCopyKind() == CopyStmt::INTTOPTR)
1335 {
1336 //insert nullptr
1337 }
1338 else if (copy->getCopyKind() == CopyStmt::PTRTOINT)
1339 {
1341 }
1342 else if (copy->getCopyKind() == CopyStmt::BITCAST)
1343 {
1344 if (rhsVal.isAddr())
1346 }
1347 else
1348 assert(false && "undefined copy kind");
1349}
signed short s16_t
Definition GeneralType.h:54
unsigned short u16_t
Definition GeneralType.h:53

◆ updateStateOnGep()

void AbstractInterpretation::updateStateOnGep ( const GepStmt gep)
private

Definition at line 808 of file AbstractInterpretation.cpp.

809{
810 const ICFGNode* node = gep->getICFGNode();
812 AddressValue gepAddrs = getGepObjAddrs(SVFUtil::cast<ValVar>(gep->getRHSVar()), offsetPair);
813 updateAbsValue(gep->getLHSVar(), gepAddrs, node);
814}
AddressValue getGepObjAddrs(const ValVar *pointer, IntervalValue offset)
IntervalValue getGepElementIndex(const GepStmt *gep)

◆ updateStateOnLoad()

void AbstractInterpretation::updateStateOnLoad ( const LoadStmt load)
private

Definition at line 1195 of file AbstractInterpretation.cpp.

1196{
1197 const ICFGNode* node = load->getICFGNode();
1198 updateAbsValue(load->getLHSVar(),
1199 loadValue(SVFUtil::cast<ValVar>(load->getRHSVar()), node), node);
1200}
AbstractValue loadValue(const ValVar *pointer, const ICFGNode *node)
const ValVar * getLHSVar() const
const ValVar * getRHSVar() const

◆ updateStateOnPhi()

void AbstractInterpretation::updateStateOnPhi ( const PhiStmt phi)
private

Definition at line 835 of file AbstractInterpretation.cpp.

836{
837 const ICFGNode* icfgNode = phi->getICFGNode();
839 for (u32_t i = 0; i < phi->getOpVarNum(); i++)
840 {
841 const ICFGNode* opICFGNode = phi->getOpICFGNode(i);
843 {
845 const AbstractValue& opVal = getAbsValue(phi->getOpVar(i), opICFGNode);
847 if (edge)
848 {
849 const IntraCFGEdge* intraEdge = SVFUtil::cast<IntraCFGEdge>(edge);
850 if (intraEdge->getCondition())
851 {
853 rhs.join_with(opVal);
854 }
855 else
856 rhs.join_with(opVal);
857 }
858 else
859 {
860 rhs.join_with(opVal);
861 }
862 }
863 }
864 updateAbsValue(phi->getRes(), rhs, icfgNode);
865}
ICFGEdge * getICFGEdge(const ICFGNode *src, const ICFGNode *dst, ICFGEdge::ICFGEdgeK kind)
Get a SVFG edge according to src and dst.
Definition ICFG.cpp:311

◆ updateStateOnRet()

void AbstractInterpretation::updateStateOnRet ( const RetPE retPE)
private

Definition at line 887 of file AbstractInterpretation.cpp.

888{
889 const ICFGNode* node = retPE->getICFGNode();
890 const AbstractValue& rhsVal = getAbsValue(retPE->getRHSVar(), node);
891 updateAbsValue(retPE->getLHSVar(), rhsVal, node);
892}
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const

◆ updateStateOnSelect()

void AbstractInterpretation::updateStateOnSelect ( const SelectStmt select)
private

Definition at line 816 of file AbstractInterpretation.cpp.

817{
818 const ICFGNode* node = select->getICFGNode();
819 const AbstractValue& condVal = getAbsValue(select->getCondition(), node);
820 const AbstractValue& tVal = getAbsValue(select->getTrueValue(), node);
821 const AbstractValue& fVal = getAbsValue(select->getFalseValue(), node);
823 if (condVal.getInterval().is_numeral())
824 {
826 }
827 else
828 {
829 resVal = tVal;
830 resVal.join_with(fVal);
831 }
832 updateAbsValue(select->getRes(), resVal, node);
833}
bool is_zero() const
Return true if the IntervalValue is [0, 0].

◆ updateStateOnStore()

void AbstractInterpretation::updateStateOnStore ( const StoreStmt store)
private

Definition at line 1202 of file AbstractInterpretation.cpp.

1203{
1204 const ICFGNode* node = store->getICFGNode();
1205 storeValue(SVFUtil::cast<ValVar>(store->getLHSVar()),
1206 getAbsValue(store->getRHSVar(), node), node);
1207}
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 308 of file AbstractInterpretation.h.

◆ allAnalyzedNodes

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

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

273{nullptr};

◆ callGraph

CallGraph* SVF::AbstractInterpretation::callGraph
private

Definition at line 276 of file AbstractInterpretation.h.

◆ detectors

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

Definition at line 301 of file AbstractInterpretation.h.

◆ func_map

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

Definition at line 296 of file AbstractInterpretation.h.

◆ icfg

ICFG* SVF::AbstractInterpretation::icfg
private

Definition at line 275 of file AbstractInterpretation.h.

◆ moduleName

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

Definition at line 299 of file AbstractInterpretation.h.

◆ preAnalysis

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

Definition at line 307 of file AbstractInterpretation.h.

307{nullptr};

◆ stat

AEStat* SVF::AbstractInterpretation::stat
private

Definition at line 277 of file AbstractInterpretation.h.

◆ svfir

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

Data and helpers reachable from SparseAbstractInterpretation.

Definition at line 306 of file AbstractInterpretation.h.

306{nullptr};

◆ utils

AbsExtAPI* SVF::AbstractInterpretation::utils
private

Definition at line 302 of file AbstractInterpretation.h.


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