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 364 of file SparseAbstractInterpretation.cpp.

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

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

465{
466 bool feasible = true;
467 if (!edge->getCondition())
468 {
469 feasible = true;
470 }
471 else if (!hasAbsState(src))
472 {
473 feasible = true;
474 }
475 else
476 {
479 }
480
481 return feasible;
482}
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 503 of file SparseAbstractInterpretation.cpp.

505{
506 // e.g.
507 // if (x > 0) {
508 // use(x); // use 1
509 // use(x); // use 2
510 // }
511 // Step 1: compose pred-inherited refinement into refinementTrace[node].
512 // At use2, we don't have conditional intra-edge, but we can inherit the
513 // refinement from use1's conditional edge. When multiple preds, JOIN the
514 // inherited constraints.
516 bool inheritOk = true;
517 bool first = true;
518 for (auto& e : node->getInEdges())
519 {
520 const ICFGNode* pred = e->getSrcNode();
521 if (hasAbsState(pred))
522 {
523 auto pit = refinementTrace.find(pred);
524 if (pit == refinementTrace.end())
525 {
526 inheritOk = false;
527 break;
528 }
529 else if (first)
530 {
531 inherited = pit->second;
532 first = false;
533 }
534 else
535 {
536 for (auto it = inherited.begin(); it != inherited.end();)
537 {
538 auto eit = pit->second.find(it->first);
539 if (eit == pit->second.end())
540 {
541 it = inherited.erase(it);
542 }
543 else
544 {
545 it->second.join_with(eit->second);
546 ++it;
547 }
548 }
549 }
550 }
551 }
552 if (inheritOk && !first && !inherited.empty())
553 {
554 auto& nodeRef = refinementTrace[node];
555 for (const auto& [id, val] : inherited)
556 {
557 auto rit = nodeRef.find(id);
558 if (rit == nodeRef.end())
559 {
560 nodeRef[id] = val;
561 }
562 else
563 {
564 rit->second.meet_with(val);
565 }
566 }
567 }
568 // e.g.
569 // if (x > 0) {
570 // use(x); // use 1
571 // use(x); // use 2
572 // }
573 // Step 2: at use1, recordBranchRefinement captures the predState's narrowed
574 // constraint into refinementTrace[use1]. At use2, we find the inherited
575 // refinement from use1 and MEET it into the base value so the use observes
576 // the narrowed constraint.
577 auto nit = refinementTrace.find(node);
578 if (nit != refinementTrace.end())
579 {
581 for (const auto& [id, constraint] : nit->second)
582 {
583 if (trace.inAddrToValTable(id))
584 {
586 trace.load(addr).getInterval().meet_with(constraint);
587 }
588 }
589 }
590}
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 (void)dstICFG; // Suppress warning of unused variable under release build
172 assert(srcICFG && "SVFG source node must have an ICFG node");
173 assert(dstICFG &&
174 "SVFG destination node must have an ICFG node");
175
177 continue;
178
180 {
181 for (NodeID id : indEdge->getPointsTo())
182 {
183 SVFVar* gn = svfir->getGNode(id);
185
186 if (SVFUtil::isa<GepObjVar>(gn))
187 {
188 idsToPull.set(id);
189 }
190 else if (auto* base = SVFUtil::dyn_cast<BaseObjVar>(gn))
191 {
193 }
194 else
195 {
196 idsToPull.set(id);
197 }
198
199 for (NodeID fid : idsToPull)
200 {
201 const ObjVar* obj =
202 SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(fid));
203 // Dense Gep propagation has already carried the
204 // current value to this node.
205 if (denseLocalObjs.test(fid))
206 {
207 continue;
208 }
209 if (obj &&
211 obj, srcICFG))
212 {
213 AbstractValue cur;
215 hasAbsValue(obj, node))
216 {
218 getAbsValue(obj, node);
219 }
223 updateAbsValue(obj, cur, node);
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231
232 // Step 2 (boundary pull) intentionally removed: with GepObjVar dense
233 // propagation in joinStates above, Gep field values arrive at use
234 // sites along ICFG edges without needing the boundary pull.
235}
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 484 of file SparseAbstractInterpretation.cpp.

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

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