Static Value-Flow Analysis
Loading...
Searching...
No Matches
SparseAbstractInterpretation.cpp
Go to the documentation of this file.
1//===- SparseAbstractInterpretation.cpp -- Sparse Abstract Execution----//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===---------------------------------------------------------------------===//
22
24#include "AE/Svfexe/AEWTO.h"
25#include "SVFIR/SVFIR.h"
26#include "Graphs/SVFG.h"
27#include "MSSA/SVFGBuilder.h"
28#include "WPA/Andersen.h"
29
30using namespace SVF;
31
32// SemiSparse state-access overrides (get/has/updateAbsValue,
33// updateAbsState, joinStates) live in AbstractStateManager.cpp; the
34// FullSparse-specific overrides — including the SVFG-backed def/use
35// queries and the ValVar stubs — live below alongside the rest of
36// FullSparse so the whole subclass stays in one file.
37
38// =====================================================================
39// Full-sparse — class lifecycle + SVFG construction.
40// =====================================================================
41
43
45{
46 svfgBuilder = std::make_unique<SVFGBuilder>(true);
48}
49
50// =====================================================================
51// Full-sparse — merge.
52//
53// mergeStatesFromPredecessors is a thin wrapper: defer to base for
54// ICFG-edge bookkeeping (predecessor iteration, branch feasibility,
55// joinStates, updateAbsState, reachability return). If the node is
56// reachable, run pullObjValueFlows to populate trace[node] with obj values
57// pulled along SVFG indirect in-edges.
58//
59// joinStates carries only state that is not represented as MemorySSA
60// def-use flow: GepObjVar field snapshots and _freedAddrs. Base/Dummy
61// ObjVars are handled by pullObjValueFlows, not by ICFG-edge joins.
62// =====================================================================
63
65 const AbstractState& src)
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}
89
91 const AbstractValue& val,
92 const ICFGNode* node)
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}
111
113 const ICFGNode* node)
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}
127
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}
235
236// =====================================================================
237// Full-sparse — refinement trace machinery.
238// =====================================================================
239
240static bool hasRedefineToSameObj(const ICFGNode* node,
241 const IndirectSVFGEdge* edge)
242{
243 for (const VFGNode* vfgNode : node->getVFGNodes())
244 {
245 if (SVFUtil::isa<StoreVFGNode>(vfgNode) &&
246 vfgNode->getDefSVFVars().intersects(edge->getPointsTo()))
247 return true;
248 }
249
250 return false;
251}
252
254 const IndirectSVFGEdge* edge, const VFGNode* dst)
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}
362
364 const ICFGNode* dst)
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}
461
463 const IntraCFGEdge* edge, const ICFGNode* src)
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}
482
485 const ICFGNode*, const ICFGNode* succ)
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}
501
503 const ICFGNode* node)
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}
590
592 const ICFGCycleWTO* cycle)
593{
594 // Start from the dense snapshot (ObjVars + any ValVars that happen to
595 // be cached at cycle_head's trace entry).
597
599 if (valVars.empty())
600 return snap; // no cycle ValVars known: nothing to pull
601
602 // Drop stale ValVar entries and pull each cycle ValVar from its
603 // def-site. ValVars without a genuine stored value are skipped to
604 // avoid getAbsValue's top-fallback contaminating body def-sites on
605 // the subsequent widen/narrow scatter.
606 snap.clearValVars();
607 for (const ValVar* v : valVars)
608 {
609 const ICFGNode* defSite = v->getICFGNode();
610 if (!defSite || !hasAbsValue(v, defSite))
611 continue;
612 snap[v->getId()] = getAbsValue(v, defSite);
613 }
614 return snap;
615}
616
618 const AbstractState& prev, const AbstractState& cur, const ICFGCycleWTO* cycle)
619{
620 // Base widens, writes trace[cycle_head], and returns fixpoint bool.
622
623 // Scatter the widened ValVars back to their def-sites so body nodes
624 // observe the widened values on the next iteration. Matches the
625 // pre-refactor semantics: scatter unconditionally, including at
626 // widening fixpoint (see the narrowing-starts-with-stale-body issue
627 // fixed by always writing widened state back).
628 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
630 for (const auto& [id, val] : next.getVarToVal())
632 return fixpoint;
633}
634
636 const AbstractState& prev, const AbstractState& cur, const ICFGCycleWTO* cycle)
637{
638 // Delegate to base. It returns true on the two non-scatter cases
639 // (narrowing disabled, or narrow fixpoint); we preserve the original
640 // "skip scatter at fixpoint" semantics by bailing early here.
642 if (fixpoint)
643 return true;
644
645 // Non-fixpoint: base wrote the narrowed state to trace. Scatter the
646 // narrowed ValVars back to def-sites.
647 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
649 for (const auto& [id, val] : next.getVarToVal())
651 return false;
652}
653
654// =====================================================================
655// Semi-sparse state-access overrides (used by both SemiSparse and
656// FullSparse subclasses; the latter further restricts ValVar reads).
657// =====================================================================
658
660 const ICFGNode* node, const AbstractState& state)
661{
662 // Only replace ObjVar state. ValVars live at their def-sites and
663 // must not be overwritten when the predecessor's state is merged in.
665}
666
668 const AbstractState& src)
669{
670 // ValVars live at def-sites in semi-sparse mode; they don't flow
671 // through state merges. Iterate src's ObjVar (_addrToAbsVal) entries
672 // directly and join into dst, leaving dst's ValVar map untouched.
673 // _freedAddrs (used by the null-deref detector) also rides along
674 // ICFG edges — there is no SVFG-level encoding of free events.
675 for (const auto& [id, val] : src.getLocToVal())
676 {
678 if (dst.getLocToVal().count(id))
679 dst.load(addr).join_with(val);
680 else
681 dst.store(addr, val);
682 }
683 for (NodeID a : src.getFreedAddrs())
684 dst.addToFreedAddrs(a);
685}
686
688 const ValVar* var) const
689{
690 // const ValVars are all defined in global node
691 if (!var->getICFGNode())
692 {
693 return svfir->getICFG()->getGlobalICFGNode();
694 }
695 // for return value of callsite, use the ret-site as def-site
696 else if (SVFUtil::isa<CallICFGNode>(var->getICFGNode()) &&
697 SVFUtil::isa<RetValPN>(var))
698 {
699 return SVFUtil::dyn_cast<CallICFGNode>(var->getICFGNode())
700 ->getRetICFGNode();
701 }
702 // for other ValVars, use their def-site as the node to query abstract
703 // value.
704 else
705 {
706 return var->getICFGNode();
707 }
708}
709
711 const AbstractValue& val,
712 const ICFGNode* node)
713{
714 // Write to the var's def-site so getAbsValue stays consistent.
715 const ICFGNode* defNode = var->getICFGNode();
716 abstractTrace[defNode ? defNode : node][var->getId()] = val;
717}
718
720 const ValVar* var, const ICFGNode* node)
721{
722 // Read from the var's def-site (where updateAbsValue wrote it).
724}
725
static bool hasRedefineToSameObj(const ICFGNode *node, const IndirectSVFGEdge *edge)
item next
Definition cJSON.cpp:2224
cJSON * a
Definition cJSON.cpp:2560
newitem prev
Definition cJSON.cpp:2285
cJSON * item
Definition cJSON.h:222
AndersenWaveDiff * getPointerAnalysis() const
Accessors for Andersen's results.
Definition AEWTO.h:56
const Set< const ValVar * > getCycleValVars(const ICFGCycleWTO *cycle) const
Definition AEWTO.h:83
AbstractState & getAbsState(const ICFGNode *node)
virtual bool narrowCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
virtual bool hasAbsValue(const ValVar *var, const ICFGNode *node) const
Side-effect-free existence check.
virtual AbstractState getFullCycleHeadState(const ICFGCycleWTO *cycle)
bool isBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
virtual bool widenCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
virtual bool mergeStatesFromPredecessors(const ICFGNode *node)
SVFIR * svfir
Data and helpers reachable from SparseAbstractInterpretation.
virtual const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node)
bool hasAbsState(const ICFGNode *node)
Map< const ICFGNode *, AbstractState > abstractTrace
per-node trace; owned here
virtual void storeValue(const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
const AddrToAbsValMap & getLocToVal() const
get loc2val map
void store(u32_t addr, const AbstractValue &val)
const Set< NodeID > & getFreedAddrs() const
virtual AbstractValue & load(u32_t addr)
static u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.
void addToFreedAddrs(NodeID addr)
void updateAddrStateOnly(const AbstractState &other)
Replace address-taken (ObjVar) state with other's, preserving ValVar state.
void join_with(const AbstractValue &other)
Map< const ICFGNode *, Map< NodeID, IntervalValue > > refinementTrace
void joinStates(AbstractState &dst, const AbstractState &src) override
bool isIntraEdgeBranchFeasible(const IntraCFGEdge *edge, const ICFGNode *src)
Return whether this intra edge is allowed by the current branch state.
bool mergeStatesFromPredecessors(const ICFGNode *node) override
bool isICFGPathFeasible(const ICFGNode *src, const ICFGNode *dst)
void storeValue(const ValVar *pointer, const AbstractValue &val, const ICFGNode *node) override
bool isIndirectSVFGEdgeFeasible(const IndirectSVFGEdge *edge, const VFGNode *dst)
void recordBranchRefinement(NodeID objId, const IntervalValue &narrowed, AbstractState &as, const ICFGNode *loadIcfg, const ICFGNode *succ) override
void buildSVFG()
Build the SVFG on top of the semi-sparse precompute.
SVFG * svfg
View pointer into svfgBuilder's graph; non-null after buildSVFG().
NodeType * getGNode(NodeID id) const
Get a node.
const GEdgeSetTy & getOutEdges() const
const GEdgeSetTy & getInEdges() const
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
Definition ICFGNode.h:74
const VFGNodeList & getVFGNodes() const
Definition ICFGNode.h:102
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244
ICFG * getICFG() const
Definition SVFIR.h:229
NodeBS & getAllFieldsObjVars(const BaseObjVar *obj)
Get all fields of an object.
Definition SVFIR.cpp:572
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:133
bool narrowCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle) override
const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node) override
AbstractState getFullCycleHeadState(const ICFGCycleWTO *cycle) override
void joinStates(AbstractState &dst, const AbstractState &src) override
bool widenCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle) 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 updateAbsState(const ICFGNode *node, const AbstractState &state) override
const ICFGNode * getICFGNode(const ValVar *var) const
void set(unsigned Idx)
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
Definition VFGNode.h:67
for isBitcode
Definition BasicTypes.h:70
u32_t NodeID
Definition GeneralType.h:56
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:47