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

#include <SparseAbstractInterpretation.h>

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

Public Member Functions

 FullSparseAbstractInterpretation ()
 
 ~FullSparseAbstractInterpretation () override
 
- Public Member Functions inherited from SVF::SemiSparseAbstractInterpretation
 SemiSparseAbstractInterpretation ()
 
 ~SemiSparseAbstractInterpretation () override=default
 
- Public Member Functions inherited from SVF::AbstractInterpretation
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 SVFVargetSVFVar (NodeID varId) const
 Retrieve SVFVar given its ID; asserts if no such variable exists.
 
AbstractStategetAbsState (const ICFGNode *node)
 
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.
 
const SVFTypegetPointeeElement (const ObjVar *var, const ICFGNode *node)
 
u32_t getAllocaInstByteSize (const AddrStmt *addr)
 
Map< const ICFGNode *, AbstractState > & getTrace ()
 
AbstractStateoperator[] (const ICFGNode *node)
 

Protected Member Functions

void joinStates (AbstractState &dst, const AbstractState &src) override
 
void storeValue (const ValVar *pointer, const AbstractValue &val, const ICFGNode *node) override
 
bool mergeStatesFromPredecessors (const ICFGNode *node) override
 
void recordBranchRefinement (NodeID objId, const IntervalValue &narrowed, AbstractState &as, const ICFGNode *loadIcfg, const ICFGNode *succ) override
 
- Protected Member Functions inherited from SVF::SemiSparseAbstractInterpretation
AbstractState getFullCycleHeadState (const ICFGCycleWTO *cycle) override
 
bool widenCycleState (const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle) override
 
bool narrowCycleState (const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle) override
 
const AbstractValuegetAbsValue (const ValVar *var, const ICFGNode *node) override
 
bool hasAbsValue (const ValVar *var, const ICFGNode *node) const override
 Side-effect-free existence check.
 
void updateAbsValue (const ValVar *var, const AbstractValue &val, const ICFGNode *node) override
 
void updateAbsState (const ICFGNode *node, const AbstractState &state) override
 
void joinStates (AbstractState &dst, const AbstractState &src) override
 
const ICFGNodegetICFGNode (const ValVar *var) const
 
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)
 
- Protected Member Functions inherited from SVF::AbstractInterpretation
 AbstractInterpretation ()
 
bool isBranchEdgeFeasible (const IntraCFGEdge *edge, AbstractState &as)
 
void collectBranchRefinement (const IntraCFGEdge *edge, AbstractState &as)
 
bool shouldApplyNarrowing (const FunObjVar *fun)
 Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.
 

Private Member Functions

void pullObjValueFlows (const ICFGNode *node)
 
bool isIndirectSVFGEdgeFeasible (const IndirectSVFGEdge *edge, const VFGNode *dst)
 
bool isICFGPathFeasible (const ICFGNode *src, const ICFGNode *dst)
 
bool isIntraEdgeBranchFeasible (const IntraCFGEdge *edge, const ICFGNode *src)
 Return whether this intra edge is allowed by the current branch state.
 
void propagateAndApplyRefinement (const ICFGNode *node)
 
void buildSVFG ()
 Build the SVFG on top of the semi-sparse precompute.
 

Private Attributes

Map< const ICFGNode *, Map< NodeID, IntervalValue > > refinementTrace
 
std::unique_ptr< SVFGBuildersvfgBuilder
 
SVFGsvfg {nullptr}
 View pointer into svfgBuilder's graph; non-null after buildSVFG().
 

Additional Inherited Members

- Public Types inherited from SVF::AbstractInterpretation
enum  AESparsity { Dense , SemiSparse , Sparse }
 
enum  HandleRecur { TOP , WIDEN_ONLY , WIDEN_NARROW }
 
enum  AEFunEntryMode { MAIN , NO_MAIN }
 
- Static Public Member Functions inherited from SVF::AbstractInterpretation
static AbstractInterpretationgetAEInstance ()
 
- Protected Attributes inherited from SVF::AbstractInterpretation
SVFIRsvfir {nullptr}
 Data and helpers reachable from SparseAbstractInterpretation.
 
AEWTOpreAnalysis {nullptr}
 
Map< const ICFGNode *, AbstractStateabstractTrace
 per-node trace; owned here
 

Detailed Description

Abstract Interpretation for Options::AESparsity::Sparse (full-sparse).

In full-sparse mode both ValVars and ObjVars live at their SVFG def-sites; reads query the SVFG for the reaching-def site, writes happen at def-sites. See doc/plan-full-sparse.md for the phase plan; Phase 1 routes ValVar and ObjVar reads through the SVFG.

Definition at line 85 of file SparseAbstractInterpretation.h.

Constructor & Destructor Documentation

◆ FullSparseAbstractInterpretation()

SVF::FullSparseAbstractInterpretation::FullSparseAbstractInterpretation ( )
inline

Definition at line 88 of file SparseAbstractInterpretation.h.

89 {
90 buildSVFG();
91 }
void buildSVFG()
Build the SVFG on top of the semi-sparse precompute.

◆ ~FullSparseAbstractInterpretation()

FullSparseAbstractInterpretation::~FullSparseAbstractInterpretation ( )
overridedefault

Member Function Documentation

◆ buildSVFG()

void FullSparseAbstractInterpretation::buildSVFG ( )
private

Build the SVFG on top of the semi-sparse precompute.

Definition at line 44 of file SparseAbstractInterpretation.cpp.

45{
46 svfgBuilder = std::make_unique<SVFGBuilder>(true);
48}
AndersenWaveDiff * getPointerAnalysis() const
Accessors for Andersen's results.
Definition AEWTO.h:56
SVFG * svfg
View pointer into svfgBuilder's graph; non-null after buildSVFG().

◆ isICFGPathFeasible()

bool FullSparseAbstractInterpretation::isICFGPathFeasible ( const ICFGNode src,
const ICFGNode dst 
)
private

Return whether a branch-feasible ICFG path exists from src to dst. Conditional edges are checked with a pure branch-feasibility query, so path probing does not create branch-refinement side effects.

Definition at line 363 of file SparseAbstractInterpretation.cpp.

365{
366 bool feasible = true;
367 if (!src || !dst)
368 {
369 feasible = true;
370 }
371 else if (src == dst)
372 {
373 feasible = true;
374 }
375 else
376 {
377 const FunObjVar* fun = src->getFun();
378 if (!fun || fun != dst->getFun())
379 {
380 feasible = true;
381 }
382 else
383 {
384 feasible = false;
385 std::deque<const ICFGNode*> worklist;
386 Set<const ICFGNode*> visited;
387 worklist.push_back(src);
388 visited.insert(src);
389
390 while (!worklist.empty() && !feasible)
391 {
392 const ICFGNode* cur = worklist.front();
393 worklist.pop_front();
394
395 // Treat a call as an intra-procedural summary edge for path
396 // queries. Feasibility of the callee body is handled by the
397 // normal analysis; here we only need caller-side reachability,
398 // e.g. entry -> ret-site.
399 if (const CallICFGNode* call =
400 SVFUtil::dyn_cast<CallICFGNode>(cur))
401 {
402 const ICFGNode* succ = call->getRetICFGNode();
403 if (!succ || succ->getFun() != fun)
404 {
405 // Ignore missing or cross-function return summaries.
406 }
407 else if (succ == dst)
408 {
409 feasible = true;
410 }
411 else if (!visited.count(succ))
412 {
413 visited.insert(succ);
414 worklist.push_back(succ);
415 }
416 else
417 {
418 // Already visited.
419 }
420 }
421
422 for (const ICFGEdge* edge : cur->getOutEdges())
423 {
424 const IntraCFGEdge* intraEdge =
425 SVFUtil::dyn_cast<IntraCFGEdge>(edge);
426 const ICFGNode* succ =
427 intraEdge ? intraEdge->getDstNode() : nullptr;
428
429 if (!intraEdge)
430 {
431 // Non-intra ICFG edges are not part of this path query.
432 }
433 else if (!succ || succ->getFun() != fun)
434 {
435 // Keep the query inside src's function.
436 }
437 else if (!isIntraEdgeBranchFeasible(intraEdge, cur))
438 {
439 // The conditional edge is unreachable in cur's state.
440 }
441 else if (succ == dst)
442 {
443 feasible = true;
444 }
445 else if (!visited.count(succ))
446 {
447 visited.insert(succ);
448 worklist.push_back(succ);
449 }
450 else
451 {
452 // Already visited.
453 }
454 }
455 }
456 }
457 }
458
459 return feasible;
460}
bool isIntraEdgeBranchFeasible(const IntraCFGEdge *edge, const ICFGNode *src)
Return whether this intra edge is allowed by the current branch state.
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
Definition ICFGNode.h:74
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ isIndirectSVFGEdgeFeasible()

bool FullSparseAbstractInterpretation::isIndirectSVFGEdgeFeasible ( const IndirectSVFGEdge edge,
const VFGNode dst 
)
private

Return whether an indirect SVFG edge should be pulled into dst. Besides branch-feasible ICFG reachability, this rejects paths where another store to the same points-to object kills the edge's value.

Definition at line 253 of file SparseAbstractInterpretation.cpp.

255{
256 assert(edge && "Indirect SVFG edge must exist");
257 assert(dst && "Indirect SVFG edge must have a destination node");
258
259 const SVFGNode* src = SVFUtil::dyn_cast<SVFGNode>(edge->getSrcNode());
260 assert(src && "Indirect SVFG edge must have an SVFG source node");
261
262 const ICFGNode* srcICFG = src->getICFGNode();
263 const ICFGNode* dstICFG = dst->getICFGNode();
264 assert(srcICFG && "SVFG source node must have an ICFG node");
265 assert(dstICFG && "SVFG destination node must have an ICFG node");
266
267 const FunObjVar* fun = srcICFG->getFun();
268 bool feasible = true;
269 if (srcICFG == dstICFG)
270 {
271 feasible = true;
272 }
273 else if (!fun || fun != dstICFG->getFun())
274 {
275 feasible = true;
276 }
277 else
278 {
279 feasible = false;
280 std::deque<const ICFGNode*> worklist;
281 Set<const ICFGNode*> visited;
282 worklist.push_back(srcICFG);
283 visited.insert(srcICFG);
284
285 while (!worklist.empty() && !feasible)
286 {
287 const ICFGNode* cur = worklist.front();
288 worklist.pop_front();
289
290 if (cur != srcICFG && hasRedefineToSameObj(cur, edge))
291 {
292 // This ICFG path redefines the same object before dst.
293 }
294 else
295 {
296 // Treat a call as an intra-procedural summary edge for path
297 // queries. Feasibility of the callee body is handled by the
298 // normal analysis; here we only need caller-side reachability,
299 // e.g. entry -> ret-site.
300 if (const CallICFGNode* call =
301 SVFUtil::dyn_cast<CallICFGNode>(cur))
302 {
303 const ICFGNode* succ = call->getRetICFGNode();
304 if (!succ || succ->getFun() != fun)
305 {
306 // Ignore missing or cross-function return summaries.
307 }
308 else if (succ == dstICFG)
309 {
310 feasible = true;
311 }
312 else if (!visited.count(succ))
313 {
314 visited.insert(succ);
315 worklist.push_back(succ);
316 }
317 else
318 {
319 // Already visited.
320 }
321 }
322
323 for (const ICFGEdge* icfgEdge : cur->getOutEdges())
324 {
325 const IntraCFGEdge* intraEdge =
326 SVFUtil::dyn_cast<IntraCFGEdge>(icfgEdge);
327 const ICFGNode* succ =
328 intraEdge ? intraEdge->getDstNode() : nullptr;
329
330 if (!intraEdge)
331 {
332 // Non-intra ICFG edges are not part of this path query.
333 }
334 else if (!succ || succ->getFun() != fun)
335 {
336 // Keep the query inside src's function.
337 }
338 else if (!isIntraEdgeBranchFeasible(intraEdge, cur))
339 {
340 // The conditional edge is unreachable in cur's state.
341 }
342 else if (succ == dstICFG)
343 {
344 feasible = true;
345 }
346 else if (!visited.count(succ))
347 {
348 visited.insert(succ);
349 worklist.push_back(succ);
350 }
351 else
352 {
353 // Already visited.
354 }
355 }
356 }
357 }
358 }
359
360 return feasible;
361}
static bool hasRedefineToSameObj(const ICFGNode *node, const IndirectSVFGEdge *edge)
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
Definition VFGNode.h:67

◆ isIntraEdgeBranchFeasible()

bool FullSparseAbstractInterpretation::isIntraEdgeBranchFeasible ( const IntraCFGEdge edge,
const ICFGNode src 
)
private

Return whether this intra edge is allowed by the current branch state.

Definition at line 462 of file SparseAbstractInterpretation.cpp.

464{
465 bool feasible = true;
466 if (!edge->getCondition())
467 {
468 feasible = true;
469 }
470 else if (!hasAbsState(src))
471 {
472 feasible = true;
473 }
474 else
475 {
478 }
479
480 return feasible;
481}
AbstractState & getAbsState(const ICFGNode *node)
bool isBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
bool hasAbsState(const ICFGNode *node)

◆ joinStates()

void FullSparseAbstractInterpretation::joinStates ( AbstractState dst,
const AbstractState src 
)
overrideprotectedvirtual

Full-sparse does not merge normal value-flow state along ICFG edges. The ICFG join carries only side-channel state that is not represented as MemorySSA def-use flow: GepObjVar field snapshots and _freedAddrs. Base/Dummy ObjVars are populated later by pullObjValueFlows from SVFG indirect in-edges; ValVars stay at their def-sites.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 64 of file SparseAbstractInterpretation.cpp.

66{
67 // Propagate GepObjVar entries along ICFG edges. Kill semantics
68 // come from handleNode's as.store(addr, val) overwriting trace at
69 // store sites (not from a JOIN here), so joinStates only forwards
70 // the post-write snapshot. This lets Gep fields scattered across
71 // many store ICFG nodes converge at downstream use sites, and lets
72 // extapi handlers (memcpy/memset/strlen) read upstream-written
73 // values via plain as.load(srcAddr). Base/Dummy are NOT propagated
74 // here — they ride pullObjValueFlows Step 1 (SVFG indirect edges, with
75 // MSSA chi/mu kill semantics).
76 for (const auto& [id, val] : src.getLocToVal())
77 {
78 if (!SVFUtil::isa<GepObjVar>(svfir->getGNode(id)))
79 continue;
81 if (dst.getLocToVal().count(id))
82 dst.load(addr).join_with(val);
83 else
84 dst.store(addr, val);
85 }
86 for (NodeID a : src.getFreedAddrs())
87 dst.addToFreedAddrs(a);
88}
unsigned u32_t
Definition CommandLine.h:18
cJSON * a
Definition cJSON.cpp:2560
SVFIR * svfir
Data and helpers reachable from SparseAbstractInterpretation.
const AddrToAbsValMap & getLocToVal() const
get loc2val map
void store(u32_t addr, const AbstractValue &val)
virtual AbstractValue & load(u32_t addr)
static u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.
void join_with(const AbstractValue &other)
NodeType * getGNode(NodeID id) const
Get a node.
u32_t NodeID
Definition GeneralType.h:56

◆ mergeStatesFromPredecessors()

bool FullSparseAbstractInterpretation::mergeStatesFromPredecessors ( const ICFGNode node)
overrideprotectedvirtual

Thin wrapper: defer to base for ICFG-edge bookkeeping (predecessor iteration, branch feasibility, joinStates, updateAbsState, reachability return). For reachable nodes, additionally run pullObjValueFlows to populate trace[node] with obj values from SVFG def-sites.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 112 of file SparseAbstractInterpretation.cpp.

114{
115 refinementTrace.erase(node);
116
118 return false;
119
120 pullObjValueFlows(node);
121
122 // Compose pred-inherited refinement on top of branch narrowings
123 // just captured, then MEET into trace[node] so reads see narrowed.
125 return true;
126}
virtual bool mergeStatesFromPredecessors(const ICFGNode *node)
Map< const ICFGNode *, Map< NodeID, IntervalValue > > refinementTrace

◆ propagateAndApplyRefinement()

void FullSparseAbstractInterpretation::propagateAndApplyRefinement ( const ICFGNode node)
private

Compose pred-inherited refinement into refinementTrace[node] (single-pred linear copy / multi-pred intersect-JOIN; any pred without refinement drops the inheritance), then MEET the final refinementTrace[node] into trace[node]._addrToAbsVal so the inherited base getAbsValue(ObjVar*, node) returns the narrowed value directly — no read-time override or cache. Called once per merge as the last step.

Definition at line 502 of file SparseAbstractInterpretation.cpp.

504{
505 // e.g.
506 // if (x > 0) {
507 // use(x); // use 1
508 // use(x); // use 2
509 // }
510 // Step 1: compose pred-inherited refinement into refinementTrace[node].
511 // At use2, we don't have conditional intra-edge, but we can inherit the
512 // refinement from use1's conditional edge. When multiple preds, JOIN the
513 // inherited constraints.
515 bool inheritOk = true;
516 bool first = true;
517 for (auto& e : node->getInEdges())
518 {
519 const ICFGNode* pred = e->getSrcNode();
520 if (hasAbsState(pred))
521 {
522 auto pit = refinementTrace.find(pred);
523 if (pit == refinementTrace.end())
524 {
525 inheritOk = false;
526 break;
527 }
528 else if (first)
529 {
530 inherited = pit->second;
531 first = false;
532 }
533 else
534 {
535 for (auto it = inherited.begin(); it != inherited.end();)
536 {
537 auto eit = pit->second.find(it->first);
538 if (eit == pit->second.end())
539 {
540 it = inherited.erase(it);
541 }
542 else
543 {
544 it->second.join_with(eit->second);
545 ++it;
546 }
547 }
548 }
549 }
550 }
551 if (inheritOk && !first && !inherited.empty())
552 {
553 auto& nodeRef = refinementTrace[node];
554 for (const auto& [id, val] : inherited)
555 {
556 auto rit = nodeRef.find(id);
557 if (rit == nodeRef.end())
558 {
559 nodeRef[id] = val;
560 }
561 else
562 {
563 rit->second.meet_with(val);
564 }
565 }
566 }
567 // e.g.
568 // if (x > 0) {
569 // use(x); // use 1
570 // use(x); // use 2
571 // }
572 // Step 2: at use1, recordBranchRefinement captures the predState's narrowed
573 // constraint into refinementTrace[use1]. At use2, we find the inherited
574 // refinement from use1 and MEET it into the base value so the use observes
575 // the narrowed constraint.
576 auto nit = refinementTrace.find(node);
577 if (nit != refinementTrace.end())
578 {
580 for (const auto& [id, constraint] : nit->second)
581 {
582 if (trace.inAddrToValTable(id))
583 {
585 trace.load(addr).getInterval().meet_with(constraint);
586 }
587 }
588 }
589}
Map< const ICFGNode *, AbstractState > abstractTrace
per-node trace; owned here

◆ pullObjValueFlows()

void FullSparseAbstractInterpretation::pullObjValueFlows ( const ICFGNode node)
private

SVFG-pull helper: walk each VFG node's indirect SVFG in-edges and pull obj values from upstream def-site traces into trace[node]. Multiple sources (e.g. mphi operands) JOIN.

Definition at line 128 of file SparseAbstractInterpretation.cpp.

129{
131 for (const auto& item : abstractTrace[node].getLocToVal())
132 {
133 NodeID id = item.first;
134 if (SVFUtil::isa<GepObjVar>(svfir->getGNode(id)))
135 denseLocalObjs.set(id);
136 }
137 // e.g.
138 // store i32 7, i32* %p ; def-site D for obj_p
139 // ...
140 // %v = load i32, i32* %p ; use-site U
141 // Step 1: intra-node SVFG-pull. For each VFG node hosted at U, walk
142 // the indirect SVFG in-edges back to D; for every obj id labelling
143 // the edge, JOIN the obj's value at D into U's trace. GepObjVar
144 // labels are pulled exactly. BaseObjVar labels are expanded to every
145 // sibling field via getAllFieldsObjVars because Andersen may label a
146 // field-sensitive consumer with the field-insensitive base.
147 //
148 // Gep fields already present at this node came through the dense
149 // ICFG propagation in joinStates. Treat those as authoritative and
150 // do not re-join older SVFG defs over them; otherwise a killed init
151 // field can be reintroduced at the load site (e.g. a[9] initialized
152 // to 9, overwritten to 10, then pulled back to [9,10]).
153 // Reads/writes go through SemiSparse to bypass FullSparse's refinement
154 // layer (these are def-site pulls, not real stores; refinement is
155 // applied later in propagateAndApplyRefinement).
156 for (const VFGNode* v : node->getVFGNodes())
157 {
158 for (auto eit = v->InEdgeBegin(); eit != v->InEdgeEnd(); ++eit)
159 {
161 SVFUtil::dyn_cast<IndirectSVFGEdge>(*eit);
162 if (indEdge)
163 {
164 const SVFGNode* src =
165 SVFUtil::dyn_cast<SVFGNode>(indEdge->getSrcNode());
166 assert(src && "SVFG incoming edge must have a source node");
167 assert(v && "SVFG incoming edge must have a destination node");
168
169 const ICFGNode* srcICFG = src->getICFGNode();
170 const ICFGNode* dstICFG = v->getICFGNode();
171 assert(srcICFG && "SVFG source node must have an ICFG node");
172 assert(dstICFG &&
173 "SVFG destination node must have an ICFG node");
174
176 continue;
177
179 {
180 for (NodeID id : indEdge->getPointsTo())
181 {
182 SVFVar* gn = svfir->getGNode(id);
184
185 if (SVFUtil::isa<GepObjVar>(gn))
186 {
187 idsToPull.set(id);
188 }
189 else if (auto* base = SVFUtil::dyn_cast<BaseObjVar>(gn))
190 {
192 }
193 else
194 {
195 idsToPull.set(id);
196 }
197
198 for (NodeID fid : idsToPull)
199 {
200 const ObjVar* obj =
201 SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(fid));
202 // Dense Gep propagation has already carried the
203 // current value to this node.
204 if (denseLocalObjs.test(fid))
205 {
206 continue;
207 }
208 if (obj &&
210 obj, srcICFG))
211 {
212 AbstractValue cur;
214 hasAbsValue(obj, node))
215 {
217 getAbsValue(obj, node);
218 }
222 updateAbsValue(obj, cur, node);
223 }
224 }
225 }
226 }
227 }
228 }
229 }
230
231 // Step 2 (boundary pull) intentionally removed: with GepObjVar dense
232 // propagation in joinStates above, Gep field values arrive at use
233 // sites along ICFG edges without needing the boundary pull.
234}
cJSON * item
Definition cJSON.h:222
bool isIndirectSVFGEdgeFeasible(const IndirectSVFGEdge *edge, const VFGNode *dst)
NodeBS & getAllFieldsObjVars(const BaseObjVar *obj)
Get all fields of an object.
Definition SVFIR.cpp:572
const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node) override
void updateAbsValue(const ValVar *var, const AbstractValue &val, const ICFGNode *node) override
bool hasAbsValue(const ValVar *var, const ICFGNode *node) const override
Side-effect-free existence check.
void set(unsigned Idx)

◆ recordBranchRefinement()

void FullSparseAbstractInterpretation::recordBranchRefinement ( NodeID  objId,
const IntervalValue narrowed,
AbstractState as,
const ICFGNode loadIcfg,
const ICFGNode succ 
)
overrideprotectedvirtual

Capture branch narrowings into refinementTrace[succ] instead of writing them into the local as: in FullSparse as would be discarded by joinStates (no-op for ObjVar), so we route the narrowing to refinementTrace and let propagateAndApplyRefinement bake it into trace at the end of mergeStatesFromPredecessors.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 483 of file SparseAbstractInterpretation.cpp.

486{
487 if (narrowed.isBottom())
488 return;
489
491 auto rit = succRef.find(objId);
492 if (rit == succRef.end())
493 {
495 }
496 else
497 {
498 rit->second.join_with(narrowed);
499 }
500}

◆ storeValue()

void FullSparseAbstractInterpretation::storeValue ( const ValVar pointer,
const AbstractValue val,
const ICFGNode node 
)
overrideprotectedvirtual

After a store overwrites an ObjVar, clear any branch refinement for that ObjVar at the store's node so stale branch constraints don't propagate past the redefinition.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 90 of file SparseAbstractInterpretation.cpp.

93{
94 // Clear branch refinement for every ObjVar this store overwrites.
95 // A store redefines the ObjVar; the pre-store branch constraint
96 // (inherited into refinementTrace[node]) is immediately stale.
97 // Without this, successors inherit the stale constraint and MEET
98 // it onto the pulled post-store value, erasing the store's effect.
99 const AbstractValue& ptrVal = getAbsValue(pointer, node);
101 for (auto addr : ptrVal.getAddrs())
102 {
103 NodeID objId = as.getIDFromAddr(addr);
104 auto rit = refinementTrace.find(node);
105 if (rit != refinementTrace.end())
106 rit->second.erase(objId);
107 }
108 // Delegate to base for the actual ObjVar update.
110}
virtual void storeValue(const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)

Member Data Documentation

◆ refinementTrace

Map<const ICFGNode*, Map<NodeID, IntervalValue> > SVF::FullSparseAbstractInterpretation::refinementTrace
private

Path-refined obj values produced by branch narrowing. Each entry is the interval constraint (not effective value) so base trace can widen/narrow independently. Cached at branch successors by recordBranchRefinement; propagated and applied by propagateAndApplyRefinement at the end of mergeStatesFromPredecessors.

Definition at line 161 of file SparseAbstractInterpretation.h.

◆ svfg

SVFG* SVF::FullSparseAbstractInterpretation::svfg {nullptr}
private

View pointer into svfgBuilder's graph; non-null after buildSVFG().

Definition at line 171 of file SparseAbstractInterpretation.h.

171{nullptr};

◆ svfgBuilder

std::unique_ptr<SVFGBuilder> SVF::FullSparseAbstractInterpretation::svfgBuilder
private

Owns the SVFG (via SVFGBuilder's internal unique_ptr). Without this, SVFGBuilder would be a local in buildSVFG() and free the graph at scope exit, leaving svfg dangling.

Definition at line 169 of file SparseAbstractInterpretation.h.


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