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
 
void mergeFreedAddrs (AbstractState &dst, const AbstractState &src)
 
- 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 SVFVar * getSVFVar (NodeID varId) const
 Retrieve SVFVar given its ID; asserts if no such variable exists.
 
AbstractState & getAbsState (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)
 Read memory through the pointer's address targets.
 
virtual void storeValue (const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
 
const SVFType * getPointeeElement (const ObjVar *var, const ICFGNode *node)
 
AllocationSizeBounds getAllocaInstByteSize (const AddrStmt *addr)
 
Map< const ICFGNode *, AbstractState > & getTrace ()
 
AbstractState & operator[] (const ICFGNode *node)
 

Protected Member Functions

void joinStates (AbstractState &dst, const AbstractState &src, const NodeBS &objs)
 
bool mergeStatesFromPredecessors (const ICFGNode *node) override
 
void joinStates (AbstractState &dst, const AbstractState &src) 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 AbstractValue & getAbsValue (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 ICFGNode * getICFGNode (const ValVar *var) const
 
virtual const AbstractValue & getAbsValue (const ValVar *var, const ICFGNode *node)
 
virtual const AbstractValue & getAbsValue (const ObjVar *var, const ICFGNode *node)
 
virtual const AbstractValue & getAbsValue (const SVFVar *var, const ICFGNode *node)
 
virtual bool hasAbsValue (const ValVar *var, const ICFGNode *node) const
 Side-effect-free existence check.
 
virtual bool hasAbsValue (const ObjVar *var, const ICFGNode *node) const
 
virtual bool hasAbsValue (const SVFVar *var, const ICFGNode *node) const
 
virtual void updateAbsValue (const ValVar *var, const AbstractValue &val, const ICFGNode *node)
 
virtual void updateAbsValue (const ObjVar *var, const AbstractValue &val, const ICFGNode *node)
 
virtual void updateAbsValue (const SVFVar *var, const AbstractValue &val, const ICFGNode *node)
 
- Protected Member Functions inherited from SVF::AbstractInterpretation
 AbstractInterpretation ()
 
bool isStrongUpdate (const AddressValue &targets, const AbstractState &state) const
 
bool isBranchEdgeFeasible (const IntraCFGEdge *edge, AbstractState &as)
 
bool applyBranchRefinement (const IntraCFGEdge *edge, AbstractState &as)
 
bool shouldApplyNarrowing (const FunObjVar *fun)
 Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.
 

Private Member Functions

AbstractState CollectObjValueFlowInput (const VFGEdge *edge, NodeBS &objs)
 
AbstractState filterValueFlowInputByPath (const VFGEdge *edge, const AbstractState &input)
 
void buildSVFG ()
 

Private Attributes

std::unique_ptr< SVFGBuilder > svfgBuilder
 

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 AbstractInterpretation & getAEInstance ()
 
- Protected Attributes inherited from SVF::AbstractInterpretation
SVFIR * svfir {nullptr}
 Data and helpers reachable from SparseAbstractInterpretation.
 
AEWTO * preAnalysis {nullptr}
 
Map< const ICFGNode *, AbstractState > abstractTrace
 per-node trace; owned here
 

Detailed Description

Definition at line 77 of file SparseAbstractInterpretation.h.

Constructor & Destructor Documentation

◆ FullSparseAbstractInterpretation()

SVF::FullSparseAbstractInterpretation::FullSparseAbstractInterpretation ( )
inline

◆ ~FullSparseAbstractInterpretation()

FullSparseAbstractInterpretation::~FullSparseAbstractInterpretation ( )
overridedefault

Member Function Documentation

◆ buildSVFG()

void FullSparseAbstractInterpretation::buildSVFG ( )
private

Definition at line 41 of file SparseAbstractInterpretation.cpp.

42{
43 svfgBuilder = std::make_unique<SVFGBuilder>(true);
45}
AndersenWaveDiff * getPointerAnalysis() const
Accessors for Andersen's results.
Definition AEWTO.h:56

◆ CollectObjValueFlowInput()

AbstractState FullSparseAbstractInterpretation::CollectObjValueFlowInput ( const VFGEdge *  edge,
NodeBS &  objs 
)
private

Step 1: collect only the indirect edge's base/sub Obj values. store i32 7, ptr a2; ...; load i32, ptr a2: an edge naming a or a.2 selects its base/sub Objs from State[store]. The caller checks that the source state is available. Return the selected IDs in objs, even if their values are not available yet. Direct ValVar edges contribute no Obj values or IDs.

Definition at line 113 of file SparseAbstractInterpretation.cpp.

115{
117 objs.clear();
118 if (const auto* indirect = SVFUtil::dyn_cast<IndirectSVFGEdge>(edge))
119 {
120 for (NodeID obj : indirect->getPointsTo())
121 objs |= svfir->getAllFieldsObjVars(svfir->getBaseObject(obj));
122 const ICFGNode* source = edge->getSrcNode()->getICFGNode();
124 }
125 return input;
126}
AbstractState & getAbsState(const ICFGNode *node)
SVFIR * svfir
Data and helpers reachable from SparseAbstractInterpretation.
void joinStates(AbstractState &dst, const AbstractState &src, const NodeBS &objs)
u32_t NodeID
Definition GeneralType.h:76
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ filterValueFlowInputByPath()

AbstractState FullSparseAbstractInterpretation::filterValueFlowInputByPath ( const VFGEdge *  edge,
const AbstractState &  input 
)
private

Filter one SVFG input using branch-feasible ICFG paths. int x = input(); // D: x=[0,10] if (x > 5) { // B use(x); // N: this path contributes x=[6,10] } See the implementation for D/B/N patterns at each decision branch, including conservative call/global handling and path/loop merges. A local worklist JOINs inputs at visited ICFG nodes, not whole paths. It does not execute arithmetic or cache results across WTO iterations. Along the path, reuse computed Store results only for carried Objs; shared isStrongUpdate selects replacement versus conservative JOIN.

Definition at line 133 of file SparseAbstractInterpretation.cpp.

135{
136 const ICFGNode* source = edge->getSrcNode()->getICFGNode();
137 const ICFGNode* target = edge->getDstNode()->getICFGNode();
138 NodeBS objs;
139 if (const auto* indirect = SVFUtil::dyn_cast<IndirectSVFGEdge>(edge))
140 {
141 for (NodeID obj : indirect->getPointsTo())
142 objs |= svfir->getAllFieldsObjVars(svfir->getBaseObject(obj));
143 }
145 if (input.getLocToVal().empty() && objs.empty())
146 {
147 // No values or queried Objs. An indirect edge still identifies its
148 // base/sub Objs even when D has not produced their values yet.
149 // this branch will return empty result
150 }
151 else if (!edge->isIntraVFGEdge() || source->getFun() != target->getFun() ||
152 !source->getFun())
153 {
154 // Call input:
155 // f(&x); // D: ActualIn in caller
156 // void f(int *p) { ... } // N: FormalIn at callee entry
157 // Call output:
158 // void f(int *p) { *p = 7; } // D: FormalOut at callee exit
159 // f(&x); // N: ActualOut at caller return point
160 // Recursive input (same function, but a non-intra SVFG edge):
161 // void f(int *p) { f(p); } // D: call ActualIn -> N: entry FormalIn
162 // Global initialization:
163 // int g = 7; // D: global node, no owning function
164 // void f() { use(g); } // N
165 // All retain D's input; no cross-procedural feasibility is proved.
166 // In one word, if edge is interprocedural, we reckon it feasible, no filter applies.
167 result = input;
168 }
169 else
170 {
171 // int x = input(); // D: x=[0,10]
172 // ...
173 // if (x > 5) { // B
174 // ...
175 // use(x); // N
176 // }
177 // Same function: search D -> B -> ... -> N, carrying x=[6,10]
178 // on B's true edge. More branches give D -> B1 -> ... -> Bk -> N.
179 // incoming's key is the iterated ICFGNode in worklist
180 // incoming's value is initialized as AbstractState pulled from SVFG predecessor
181 // the AbstractState only change some interval values at branches (branch refinement)
185 worklist.push(source);
186 while (!worklist.empty())
187 {
188 const ICFGNode* current = worklist.pop();
189 if (current == target)
190 {
191 // int x = read_int(); // D: x=[-10,10]
192 // if (x > 0) { // B: true edge carries x=[1,10]
193 // use(x); // N: current == target
194 // }
195 // JOIN incoming[N] into this D -> N query's result. Stop at
196 // N: do not inspect or follow any of N's outgoing edges.
197 result.joinWith(incoming[current]);
198 }
199 else
200 {
201 // int a[2] = {0,1} // D: a[0] = [0,0], a[1] = [1,1]
202 // a[1] = 2 // S: a[1] = [2,2]
203 // use(a[1]) // N: if an input carries D's old a[1],
204 // its D -> S -> N path reuses S's result when strongly updated.
205 // An input from S already has a[1]=2; S itself is not replayed.
206
207 AbstractState output = incoming[current];
208 if (current != source && hasAbsState(current))
209 {
210 const AbstractState& state = getAbsState(current);
211 for (const SVFStmt* stmt : current->getSVFStmts())
212 {
213 if (const auto* store = SVFUtil::dyn_cast<StoreStmt>(stmt))
214 {
215 const AddressValue& targets =
216 getAbsValue(store->getLHSVar(), current).getAddrs();
218 for (NodeID obj : objs)
219 {
221 if (targets.contains(addr) &&
222 state.getIDFromAddr(addr) == obj && state.getLocToVal().count(obj))
223 {
224 // D: a[9]=9; p=a+9; S: *p=10; N: use(a[9]).
225 // Static GEP mapping may leave D -> N, not S -> N.
226 // At S, AE identifies the carried sub-Obj a[9].
227 // Reuse S's computed value; do not execute S again.
228 if (strongUpdate)
229 output.store(addr, state.load(addr));
230 else
231 output.load(addr).join_with(state.load(addr));
232 }
233 }
234 }
235 }
236 }
237 std::vector<std::pair<const ICFGNode*, const IntraCFGEdge*>> successors;
238 if (const auto* call = SVFUtil::dyn_cast<CallICFGNode>(current))
239 {
240 const RetICFGNode* retNode = call->getRetICFGNode();
241 if (call->getCalledFunction() &&
242 SVFUtil::isExtCall(call->getCalledFunction()))
243 {
244 // D: x=0; C: a model writes x=5; N: use(x).
245 // Read the queried Objs from C's already computed
246 // output, including x=5 even when input contains x=0.
247 // C may also be D, e.g. memset(a, 7, 1) -> use(a[0]);
248 // read its model output rather than skipping the call.
249 // This is a projection of C's output, not proof that
250 // C wrote every present Obj. A joined output may be
251 // less precise than this query's path-specific values.
252 if (hasAbsState(current))
253 {
254 const AbstractState& state = getAbsState(current);
255 for (NodeID obj : objs)
256 {
258 if (state.getIDFromAddr(addr) == obj && state.getLocToVal().count(obj))
259 {
260 output.store(addr, state.load(addr));
261 }
262 }
263 }
264 }
265 else
266 {
267 // Ordinary and recursive calls use the same Obj return
268 // inputs. void f(int *p) { *p=7; } f(&x); returns x=7
269 // as an Obj value. Do not execute the callee again.
270 // INTERVAL_test_16-0.c: main starts i in [0,5].
271 // void foo(int* i) {
272 // *i = *i + 1; // D: i=[1,10] at fixpoint
273 // if (*i < 10) {
274 // foo(i); // C: carried i=[1,9]
275 // // R: callee output i=[10,10]
276 // }
277 // } // N: merge both branches and return
278 // Unlike a loop exit, C -> R does not test i again.
279 // The callee's exit condition is already reflected in
280 // its Obj output. Read that output before continuing
281 // at R, without searching or executing the callee body.
284 // R may still contain a copy of C's pre-call state.
285 // Read R's indirect SVFG predecessors, not State[R].
286 for (const VFGNode* retSVFGNode : retNode->getVFGNodes())
287 {
288 for (const VFGEdge* retEdge : retSVFGNode->getInEdges())
289 {
290 if (const auto* indirect = SVFUtil::dyn_cast<IndirectSVFGEdge>(retEdge))
291 {
293 for (NodeID obj : indirect->getPointsTo())
294 retObjs |= svfir->getAllFieldsObjVars(svfir->getBaseObject(obj));
296 const ICFGNode* calleeOutputNode = retEdge->getSrcNode()->getICFGNode();
299 }
300 }
301 }
302 // Change only queried Objs identified by the return
303 // edges; all other carried values stay unchanged.
304 for (NodeID obj : objs)
305 {
306 if (calleeOutputObjs.test(obj))
307 {
309 if (calleeOutput.getLocToVal().count(obj))
310 {
311 // Replace pre-call [1,9] with returned 10.
312 // Do not JOIN or intersect with the old value:
313 // the call may have changed this Obj.
314 output.store(addr, calleeOutput.load(addr));
315 }
316 else
317 {
318 // The return edge exists, but no Obj value
319 // is available yet. Contribute bottom until
320 // a later WTO iteration supplies the output,
321 // not the pre-call value as a guessed return.
322 output.store(addr, AbstractValue());
323 }
324 }
325 }
326 }
327 // Continue the caller-side D -> C -> R -> ... -> N path
328 // with the Obj outputs collected above. Do not enter or
329 // execute the callee again in this path query.
330 // Whether f can return is not proved here (also conservative
331 // for abort()).
332 successors.emplace_back(retNode, nullptr);
333 }
334 else
335 {
336 // int x = 1; // D
337 // int y = 2; // ordinary node: keep carried x=1
338 // x = 9; // S: still keep D's carried x=1
339 // use(x); // N: may also receive x=9 from S
340 // Follow intra edges only. Do not execute y=2 or x=9;
341 // do not infer that S kills D's contribution.
342 for (const ICFGEdge* out : current->getOutEdges())
343 {
344 if (const auto* intra = SVFUtil::dyn_cast<IntraCFGEdge>(out))
345 successors.emplace_back(intra->getDstNode(), intra);
346 }
347 }
348
349 for (const auto& [next, branch] : successors)
350 {
352 bool feasible = true;
353 if (!next || next->getFun() != source->getFun())
354 {
355 // Structural boundary (not a C-level branch test):
356 // D -> call f -> [missing caller return point]
357 // D[in f] -> next[in g] -> ... -> N[in f]
358 // next is missing or outside D's function. Do not
359 // extend this intra-procedural search through that hop.
360 feasible = false;
361 }
362 else if (!branch || !branch->getCondition() || !hasAbsState(current))
363 {
364 // Unconditional edge:
365 // int x = input(); // D
366 // int y = 2; // M: no branch condition
367 // use(x); // N
368 // Caller-side hop:
369 // D: ...; f(); ...; use(x); // N
370 // Branch state not available yet:
371 // D: ...; if (c) { ...; use(x); } // B -> N
372 // State[B] is absent in this iteration.
373 // Keep the input unchanged: none proves the hop false.
374 }
375 else
376 {
377 // int x = input(); // D
378 // if (x > 5) { // B: an AE state already exists
379 // use(x); // N
380 // }
381 // Read B's existing Boolean result to check its edge;
382 // narrow only this path's copy of D's input below.
385 // int x = 0; // D
386 // if (x > 5) { // B: condition=[0,0]
387 // use(x); // N: true edge requires 1
388 // }
389 // [0,0] cannot take the true edge: reject this hop.
390 feasible = false;
391 else
392 // int x = input(); // D: x=[0,10]
393 // if (x > 5) { // B: condition=[0,1]
394 // use(x); // N: keep true, carry x=[6,10]
395 // }
396 // Nested constraints can reject a carried input:
397 // if (x <= 5) { // B1: candidate x=[0,5]
398 // if (x > 5) { use(x); } // B2 -> N
399 // }
400 // Even if State[B2] still admits true, intersecting
401 // candidate [0,5] with [6,10] gives bottom. Other
402 // unsupported constraints conservatively keep input.
404 }
405
406 // The two feasible-arrival cases below use one diamond:
407 // int x = read_int(); // D: x=[-10,10]
408 // if (x > 0) { then_work(); } // B: true carries [1,10]
409 // else { else_work(); } // false carries [-10,0]
410 // work(); // M (= next), merge point
411 // use(x); // N
412 //
413 // D -> B
414 // true / \ false
415 // [1,10] [-10,0]
416 // \ /
417 // M -> N
418 // "First" means search arrival order, not program order.
419 // Either route can arrive first; the final JOIN is the same.
420 if (!feasible)
421 {
422 // int x = 0; // D
423 // if (x > 5) { ...; }
424 // use(x); // N is after the if
425 // Drop the true route only; the false route can still
426 // reach N. Other SVFG predecessors are not rejected.
427 }
428 else if (!incoming.count(next))
429 {
430 // Diamond above, assuming the true route arrives first:
431 // incoming[M] absent, candidate=[1,10]
432 // -> save incoming[M]=[1,10] and queue M.
433 // The false route has not contributed yet. This is
434 // the same initialization used for any first visit.
436 worklist.push(next);
437 }
438 else
439 {
440 // Same diamond, now the false route arrives at M:
441 // incoming[M]=[1,10], candidate=[-10,0]
442 // -> JOIN gives [-10,10]. M need not have been
443 // processed yet; its first input is already saved.
444 // Both routes started at D, not two different SVFG defs.
447 // Another repeated-arrival pattern is a loop back edge:
448 // int x = read_int(); // D: x=[-10,10]
449 // while (again()) {} // M: head / back edge
450 // use(x); // N
451 // Existing [-10,10] JOIN back-edge [-10,10] is unchanged:
452 // skip the if below and do not queue M again.
453 if (joined != incoming[next])
454 {
455 // Diamond: [1,10] -> [-10,10] enlarged M's input.
456 // Queue M so the added values can also reach N.
457 incoming[next] = std::move(joined);
458 worklist.push(next);
459 }
460 }
461 }
462 }
463 }
464 }
465 return result;
466}
unsigned u32_t
Definition CommandLine.h:18
item next
Definition cJSON.cpp:2224
bool isStrongUpdate(const AddressValue &targets, const AbstractState &state) const
bool isBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
bool applyBranchRefinement(const IntraCFGEdge *edge, AbstractState &as)
bool hasAbsState(const ICFGNode *node)
void joinWith(const AbstractState &other)
domain join with other, important! other widen this.
static u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.
AddressValue & getAddrs()
bool push(const Data &data)
Definition WorkList.h:180
bool empty() const
Definition WorkList.h:161
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
Definition ICFGNode.h:75
const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node) override
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:526

◆ joinStates() [1/2]

void SemiSparseAbstractInterpretation::joinStates ( AbstractState &  dst,
const AbstractState &  src 
)
overrideprotectedvirtual

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

Reimplemented from SVF::AbstractInterpretation.

Definition at line 71 of file SparseAbstractInterpretation.cpp.

546{
547 // ValVars live at def-sites in semi-sparse mode; they don't flow
548 // through state merges. Iterate src's ObjVar (_addrToAbsVal) entries
549 // directly and join into dst, leaving dst's ValVar map untouched.
550 // _freedAddrs (used by the null-deref detector) also rides along
551 // ICFG edges — there is no SVFG-level encoding of free events.
552 for (const auto& [id, val] : src.getLocToVal())
553 {
555 if (dst.getLocToVal().count(id))
556 dst.load(addr).join_with(val);
557 else
558 dst.store(addr, val);
559 }
560 for (NodeID a : src.getFreedAddrs())
561 dst.addToFreedAddrs(a);
562}
cJSON * a
Definition cJSON.cpp:2560
const AddrToAbsValMap & getLocToVal() const
get loc2val map
void store(u32_t addr, const AbstractValue &val)
virtual AbstractValue & load(u32_t addr)
void join_with(const AbstractValue &other)

◆ joinStates() [2/2]

void FullSparseAbstractInterpretation::joinStates ( AbstractState &  dst,
const AbstractState &  src,
const NodeBS &  objs 
)
protected

JOIN only the selected Obj IDs from src into dst; missing values contribute nothing. The caller selects base/sub Objs and handles path constraints and strong/weak updates. ValVars and freed addresses are not copied here. Memory lookups use AbstractState's existing address resolution, including its freed-address handling.

Definition at line 54 of file SparseAbstractInterpretation.cpp.

56{
57 for (NodeID obj : objs)
58 {
60 const auto value = src.getLocToVal().find(src.getIDFromAddr(addr));
61 if (value != src.getLocToVal().end())
62 {
63 if (dst.getLocToVal().count(dst.getIDFromAddr(addr)))
64 dst.load(addr).join_with(value->second);
65 else
66 dst.store(addr, value->second);
67 }
68 }
69}
u32_t getIDFromAddr(u32_t addr) const
Return the internal index if addr is an address otherwise return the value of idx.

◆ mergeFreedAddrs()

void FullSparseAbstractInterpretation::mergeFreedAddrs ( AbstractState &  dst,
const AbstractState &  src 
)

Merge only freed addresses from a feasible ICFG predecessor. Obj values are collected separately through SVFG inputs.

Definition at line 47 of file SparseAbstractInterpretation.cpp.

49{
50 for (NodeID addr : src.getFreedAddrs())
51 dst.addToFreedAddrs(addr);
52}

◆ mergeStatesFromPredecessors()

bool FullSparseAbstractInterpretation::mergeStatesFromPredecessors ( const ICFGNode *  node)
overrideprotectedvirtual
  1. Read Obj values from incoming indirect SVFG edges.
  2. Filter/refine that contribution along feasible ICFG paths.
  3. JOIN it into this ICFGNode's state, then execute normally.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 71 of file SparseAbstractInterpretation.cpp.

73{
74 // An empty SVFG input is not proof of unreachability. Reuse the existing
75 // control gate and mergeFreedAddrs, not a new solver.
76 const bool reachable =
78 if (reachable)
79 {
81 for (const VFGNode* target : node->getVFGNodes())
82 {
83 for (auto it = target->InEdgeBegin(); it != target->InEdgeEnd(); ++it)
84 {
85 const VFGEdge* edge = *it;
86 const ICFGNode* source = edge->getSrcNode()->getICFGNode();
87 if (source == node)
88 {
89 // Dependencies inside one ICFG node are handled by its
90 // statement execution, not by reading its old output.
91 }
92 else if (!source || !hasAbsState(source))
93 {
94 // This direct predecessor has no available output yet.
95 }
96 else
97 {
98 // Step 1. Read this predecessor's current edge values.
101 // Step 2. JOIN the contributions of feasible, refined paths.
103 // Step 3. Merge this contribution, never the whole source state.
105 }
106 }
107 }
108 updateAbsState(node, merged);
109 }
110 return reachable;
111}
virtual bool mergeStatesFromPredecessors(const ICFGNode *node)
AbstractState filterValueFlowInputByPath(const VFGEdge *edge, const AbstractState &input)
AbstractState CollectObjValueFlowInput(const VFGEdge *edge, NodeBS &objs)
void updateAbsState(const ICFGNode *node, const AbstractState &state) override

Member Data Documentation

◆ svfgBuilder

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

Definition at line 131 of file SparseAbstractInterpretation.h.


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