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 (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}
236
237// =====================================================================
238// Full-sparse — refinement trace machinery.
239// =====================================================================
240
241static bool hasRedefineToSameObj(const ICFGNode* node,
242 const IndirectSVFGEdge* edge)
243{
244 for (const VFGNode* vfgNode : node->getVFGNodes())
245 {
246 if (SVFUtil::isa<StoreVFGNode>(vfgNode) &&
247 vfgNode->getDefSVFVars().intersects(edge->getPointsTo()))
248 return true;
249 }
250
251 return false;
252}
253
255 const IndirectSVFGEdge* edge, const VFGNode* dst)
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}
363
365 const ICFGNode* dst)
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}
462
464 const IntraCFGEdge* edge, const ICFGNode* src)
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}
483
486 const ICFGNode*, const ICFGNode* succ)
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}
502
504 const ICFGNode* node)
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}
591
593 const ICFGCycleWTO* cycle)
594{
595 // Start from the dense snapshot (ObjVars + any ValVars that happen to
596 // be cached at cycle_head's trace entry).
598
600 if (valVars.empty())
601 return snap; // no cycle ValVars known: nothing to pull
602
603 // Drop stale ValVar entries and pull each cycle ValVar from its
604 // def-site. ValVars without a genuine stored value are skipped to
605 // avoid getAbsValue's top-fallback contaminating body def-sites on
606 // the subsequent widen/narrow scatter.
607 snap.clearValVars();
608 for (const ValVar* v : valVars)
609 {
610 const ICFGNode* defSite = v->getICFGNode();
611 if (!defSite || !hasAbsValue(v, defSite))
612 continue;
613 snap[v->getId()] = getAbsValue(v, defSite);
614 }
615 return snap;
616}
617
619 const AbstractState& prev, const AbstractState& cur, const ICFGCycleWTO* cycle)
620{
621 // Base widens, writes trace[cycle_head], and returns fixpoint bool.
623
624 // Scatter the widened ValVars back to their def-sites so body nodes
625 // observe the widened values on the next iteration. Matches the
626 // pre-refactor semantics: scatter unconditionally, including at
627 // widening fixpoint (see the narrowing-starts-with-stale-body issue
628 // fixed by always writing widened state back).
629 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
631 for (const auto& [id, val] : next.getVarToVal())
633 return fixpoint;
634}
635
637 const AbstractState& prev, const AbstractState& cur, const ICFGCycleWTO* cycle)
638{
639 // Delegate to base. It returns true on the two non-scatter cases
640 // (narrowing disabled, or narrow fixpoint); we preserve the original
641 // "skip scatter at fixpoint" semantics by bailing early here.
643 if (fixpoint)
644 return true;
645
646 // Non-fixpoint: base wrote the narrowed state to trace. Scatter the
647 // narrowed ValVars back to def-sites.
648 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
650 for (const auto& [id, val] : next.getVarToVal())
652 return false;
653}
654
655// =====================================================================
656// Semi-sparse state-access overrides (used by both SemiSparse and
657// FullSparse subclasses; the latter further restricts ValVar reads).
658// =====================================================================
659
661 const ICFGNode* node, const AbstractState& state)
662{
663 // Only replace ObjVar state. ValVars live at their def-sites and
664 // must not be overwritten when the predecessor's state is merged in.
666}
667
669 const AbstractState& src)
670{
671 // ValVars live at def-sites in semi-sparse mode; they don't flow
672 // through state merges. Iterate src's ObjVar (_addrToAbsVal) entries
673 // directly and join into dst, leaving dst's ValVar map untouched.
674 // _freedAddrs (used by the null-deref detector) also rides along
675 // ICFG edges — there is no SVFG-level encoding of free events.
676 for (const auto& [id, val] : src.getLocToVal())
677 {
679 if (dst.getLocToVal().count(id))
680 dst.load(addr).join_with(val);
681 else
682 dst.store(addr, val);
683 }
684 for (NodeID a : src.getFreedAddrs())
685 dst.addToFreedAddrs(a);
686}
687
689 const ValVar* var) const
690{
691 // const ValVars are all defined in global node
692 if (!var->getICFGNode())
693 {
694 return svfir->getICFG()->getGlobalICFGNode();
695 }
696 // for return value of callsite, use the ret-site as def-site
697 else if (SVFUtil::isa<CallICFGNode>(var->getICFGNode()) &&
698 SVFUtil::isa<RetValPN>(var))
699 {
700 return SVFUtil::dyn_cast<CallICFGNode>(var->getICFGNode())
701 ->getRetICFGNode();
702 }
703 // for other ValVars, use their def-site as the node to query abstract
704 // value.
705 else
706 {
707 return var->getICFGNode();
708 }
709}
710
712 const AbstractValue& val,
713 const ICFGNode* node)
714{
715 // Write to the var's def-site so getAbsValue stays consistent.
716 const ICFGNode* defNode = var->getICFGNode();
717 abstractTrace[defNode ? defNode : node][var->getId()] = val;
718}
719
721 const ValVar* var, const ICFGNode* node)
722{
723 // Read from the var's def-site (where updateAbsValue wrote it).
725}
726
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