Static Value-Flow Analysis
Loading...
Searching...
No Matches
SVF::SparseObjGraph Class Reference

#include <SparseObjGraph.h>

Inheritance diagram for SVF::SparseObjGraph:
SVF::GenericGraph< SparseObjNode, SparseObjEdge >

Public Types

typedef SparseObjNode Node
typedef SparseObjEdge Edge
Public Types inherited from SVF::GenericGraph< SparseObjNode, SparseObjEdge >
typedef SparseObjNode NodeType
typedef SparseObjEdge EdgeType
typedef OrderedMap< NodeID, NodeType * > IDToNodeMapTy
 NodeID to GenericNode map.
typedef IDToNodeMapTy::iterator iterator
 Node Iterators.
typedef IDToNodeMapTy::const_iterator const_iterator

Public Member Functions

 SparseObjGraph (const SVFG &svfg, ICFG &icfg, PointerAnalysis &pta, const SVFIR &svfir)
 Construction uses static graphs and points-to results, not AE state.
 SparseObjGraph (const SparseObjGraph &)=delete
SparseObjGraph & operator= (const SparseObjGraph &)=delete
const std::vector< const Edge * > & getInputs (const ICFGNode *node) const
 Return incoming edges at this ICFG location for client-side value flow.
std::string toString () const
 Describe the static nodes and edges as text, without AE values.
void dump (const std::string &file)
 Write a DOT graph to <file>.dot through GraphPrinter.
Public Member Functions inherited from SVF::GenericGraph< SparseObjNode, SparseObjEdge >
 GenericGraph ()
 Constructor.
virtual ~GenericGraph ()
 Destructor.
void destroy ()
 Release memory.
iterator begin ()
 Iterators.
iterator end ()
const_iterator begin () const
const_iterator end () const
void addGNode (NodeID id, NodeType *node)
 Add a Node.
NodeType * getGNode (NodeID id) const
 Get a node.
bool hasGNode (NodeID id) const
 Has a node.
void removeGNode (NodeType *node)
 Delete a node.
u32_t getTotalNodeNum () const
 Get total number of node/edge.
u32_t getTotalEdgeNum () const
void incNodeNum ()
 Increase number of node/edge.
void incEdgeNum ()

Private Member Functions

bool isBranch (const ICFGNode *node) const
Node * getOrCreateBaseObjNode (NodeID baseObjId, const ICFGNode *location)
Node * getBranchNode (NodeID base, const IntraCFGEdge *branch)
void addRouteEdge (Node *source, Node *target)
void addEdge (NodeID base, const ICFGNode *source, const ICFGNode *target, const IntraCFGEdge *branch)
void connectFrom (NodeID base, const ICFGNode *source, const Set< const ICFGNode * > &events, Set< const ICFGNode * > &newSources)

Private Attributes

ICFG & icfg
Map< NodeID, Map< const ICFGNode *, Node * > > groupNodes
 Normal nodes are unique by (base, ICFG location); branch nodes by edge.
Map< NodeID, Map< const IntraCFGEdge *, Node * > > branchNodes
Map< const ICFGNode *, std::vector< const Edge * > > inputs
Map< const ICFGNode *, Set< NodeID > > returnedGroups
Map< const ICFGNode *, Map< const FunObjVar *, Set< NodeID > > > returnedGroupsByCallee

Additional Inherited Members

Public Attributes inherited from SVF::GenericGraph< SparseObjNode, SparseObjEdge >
u32_t edgeNum
 total num of node
u32_t nodeNum
 total num of edge
Protected Attributes inherited from SVF::GenericGraph< SparseObjNode, SparseObjEdge >
IDToNodeMapTy IDToNodeMap
 node map

Detailed Description

Prebuild Obj routes from SVFG object information and ICFG order. Fields and array elements of the same base are packed on one route: D: a[0] = 1; S: a[1] = 7; N: use(a[0]); Program order gives D -> S -> N, rather than two independent packed inputs from D and S. A branch edge gets a synthetic node, but the graph neither computes nor stores intervals; clients check feasibility and refine values.

Definition at line 60 of file SparseObjGraph.h.

Member Typedef Documentation

◆ Edge

Definition at line 64 of file SparseObjGraph.h.

◆ Node

Definition at line 63 of file SparseObjGraph.h.

Constructor & Destructor Documentation

◆ SparseObjGraph() [1/2]

SparseObjGraph::SparseObjGraph ( const SVFG & svfg,
ICFG & icfg,
PointerAnalysis & pta,
const SVFIR & svfir )

Construction uses static graphs and points-to results, not AE state.

Definition at line 30 of file SparseObjGraph.cpp.

31 : icfg(graph)
32{
33 //Step 1 collect key: All base Obj ID, value: all def-use sites related to the base id
35 for (auto it = svfg.begin(); it != svfg.end(); ++it)
36 {
37 const VFGNode* vfg = it->second;
38 const ICFGNode* location = vfg->getICFGNode();
39 // Only in-function SVFG nodes participate here; global entry routes
40 // are connected below.
41 if (location && location->getFun())
42 {
43 // An indirect call edge identifies the packed Obj passed to the
44 // callee: C: f(&x) -> P: callee entry. Register both C and P as
45 // events for x so intra-function routing stops and resumes there;
46 // addEdge connects the interprocedural C -> P edge separately.
47 for (const VFGEdge* edge : vfg->getInEdges())
48 {
49 if (const auto* call = SVFUtil::dyn_cast<CallIndSVFGEdge>(edge))
50 {
51 const ICFGNode* caller = call->getSrcNode()->getICFGNode();
52 if (caller)
53 {
54 for (NodeID obj : call->getPointsTo())
55 {
56 if (!svfir.isNullOrBlkObj(obj))
57 {
58 const NodeID base = svfir.getBaseObject(obj)->getId();
59 eventsByBase[base].insert(caller);
60 eventsByBase[base].insert(location);
61 addEdge(base, caller, location, nullptr);
62 }
63 }
64 }
65 }
66 }
67
68 // MRSVFGNode already supplies points-to objects. Group each by
69 // base without modifying the SVFG or strong/weak update rules.
70 const ValVar* pointer = nullptr;
71 if (const auto* memory = SVFUtil::dyn_cast<MRSVFGNode>(vfg))
72 {
73 for (NodeID obj : memory->getPointsTo())
74 {
75 if (!svfir.isNullOrBlkObj(obj))
76 {
77 const NodeID base = svfir.getBaseObject(obj)->getId();
78 eventsByBase[base].insert(location);
79 getOrCreateBaseObjNode(base, location);
80 }
81 }
82 }
83 else if (const auto* store = SVFUtil::dyn_cast<StoreVFGNode>(vfg))
84 pointer = store->getLHSVar();
85 else if (const auto* load = SVFUtil::dyn_cast<LoadVFGNode>(vfg))
86 pointer = load->getRHSVar();
87
88 // Resolve ordinary load/store targets with points-to analysis.
89 // If p points to a[1], record a's base so a[0] and a[1] travel
90 // through this location as one packed Obj.
91 if (pointer)
92 {
93 for (NodeID obj : pta.getPts(pointer->getId()))
94 {
95 if (!svfir.isNullOrBlkObj(obj))
96 {
97 const NodeID base = svfir.getBaseObject(obj)->getId();
98 eventsByBase[base].insert(location);
99 getOrCreateBaseObjNode(base, location);
100 }
101 }
102 }
103 }
104 }
105
106 // Step 2: connect callee Obj outputs to the caller return location.
107 // For C: f(&x); R: return from the call, a RetIndSVFGEdge for x gives
108 // callee-output -> R, where AE can read the computed Obj value.
109 for (auto it = icfg.begin(); it != icfg.end(); ++it)
110 {
111 if (const auto* ret = SVFUtil::dyn_cast<RetICFGNode>(it->second))
112 {
113 for (const VFGNode* target : ret->getVFGNodes())
114 {
115 for (const VFGEdge* edge : target->getInEdges())
116 {
117 if (const auto* output = SVFUtil::dyn_cast<RetIndSVFGEdge>(edge))
118 {
119 const ICFGNode* source = output->getSrcNode()->getICFGNode();
120 if (source)
121 {
122 for (NodeID obj : output->getPointsTo())
123 {
124 if (!svfir.isNullOrBlkObj(obj))
125 {
126 const NodeID base = svfir.getBaseObject(obj)->getId();
127 returnedGroups[ret].insert(base);
128 if (source->getFun())
129 returnedGroupsByCallee[ret][source->getFun()].insert(base);
130 eventsByBase[base].insert(ret);
131 if (source->getFun())
132 eventsByBase[base].insert(source);
133 addEdge(base, source, ret, nullptr);
134 }
135 }
136 }
137 }
138 }
139 }
140 }
141 }
142
143 // Step 3: connect consecutive Obj events in ICFG order within each function.
144 // D: a[0]=1; S: a[1]=7; N: use(a[0]) becomes D -> S -> N.
145 // Branches, calls, and returns also stop a route, even if they were not
146 // among the initial SVFG events.
147 for (const auto& [base, events] : eventsByBase)
148 {
149 Set<const ICFGNode*> sources = events;
150 for (const ICFGNode* event : events)
151 sources.insert(icfg.getFunEntryICFGNode(event->getFun()));
152
153 // Connect global objects from global initialization to function entries.
154 if (svfir.getBaseObject(base)->isGlobalObj())
155 {
156 const ICFGNode* global = icfg.getGlobalICFGNode();
157 for (const ICFGEdge* edge : global->getOutEdges())
158 {
159 const ICFGNode* entry = edge->getDstNode();
160 if (SVFUtil::isa<FunEntryICFGNode>(entry) && sources.count(entry))
161 addEdge(base, global, entry, nullptr);
162 }
163 }
164
165 // Branch/call/return sites found by connectFrom become sources for
166 // the next segment. This queue is used only during graph construction.
167 std::vector<const ICFGNode*> pending(sources.begin(), sources.end());
168 for (size_t i = 0; i < pending.size(); ++i)
169 {
170 Set<const ICFGNode*> newSources;
171 connectFrom(base, pending[i], events, newSources);
172 for (const ICFGNode* event : newSources)
173 {
174 if (sources.insert(event).second)
175 pending.push_back(event);
176 }
177 }
178 }
179
180}
bool isGlobalObj() const
NodeID getId() const
Get the memory object id.
iterator begin()
Iterators.
const GEdgeSetTy & getOutEdges() const
const GEdgeSetTy & getInEdges() const
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
Definition ICFGNode.h:75
static bool isNullOrBlkObj(NodeID id)
Check a decoded NodeID, not an AE virtual memory address.
Definition IRGraph.h:169
virtual const PointsTo & getPts(NodeID ptr)=0
Get points-to targets of a pointer. It needs to be implemented in child class.
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:499
NodeID getId() const
Get ID.
Definition SVFValue.h:158
Node * getOrCreateBaseObjNode(NodeID baseObjId, const ICFGNode *location)
Map< const ICFGNode *, Set< NodeID > > returnedGroups
void connectFrom(NodeID base, const ICFGNode *source, const Set< const ICFGNode * > &events, Set< const ICFGNode * > &newSources)
Map< const ICFGNode *, Map< const FunObjVar *, Set< NodeID > > > returnedGroupsByCallee
void addEdge(NodeID base, const ICFGNode *source, const ICFGNode *target, const IntraCFGEdge *branch)
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
Definition VFGNode.h:67
LLVM_NODISCARD bool isa(const Y &Val)
Definition Casting.h:241
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
Definition Casting.h:405
u32_t NodeID
Definition GeneralType.h:76
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition GeneralType.h:51
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition GeneralType.h:56

◆ SparseObjGraph() [2/2]

SVF::SparseObjGraph::SparseObjGraph ( const SparseObjGraph & )
delete

Member Function Documentation

◆ addEdge()

void SparseObjGraph::addEdge ( NodeID base,
const ICFGNode * source,
const ICFGNode * target,
const IntraCFGEdge * branch )
private

Definition at line 238 of file SparseObjGraph.cpp.

241{
242 // B: if (z > 0) { use(x); use(z); }, with ordinary loads and no aliasing.
243 // For base=z, connectFrom passes source=B, target=N (the z use), and
244 // B's true edge. The intervening use(x) adds no z edge. The same route
245 // applies when N immediately follows B. inputs[N] records the branch
246 // node -> N; AE checks feasibility and refines z when reading that edge.
247 Node* from = getOrCreateBaseObjNode(base, source);
248 Node* to = getOrCreateBaseObjNode(base, target);
249 Node* input = branch ? getBranchNode(base, branch) : from;
250 if (branch)
251 addRouteEdge(from, input);
252 addRouteEdge(input, to);
253}
Node * getBranchNode(NodeID base, const IntraCFGEdge *branch)
void addRouteEdge(Node *source, Node *target)

◆ addRouteEdge()

void SparseObjGraph::addRouteEdge ( Node * source,
Node * target )
private

Definition at line 221 of file SparseObjGraph.cpp.

222{
223 Edge candidate(source, target);
224 if (source->hasOutgoingEdge(&candidate))
225 return;
226
227 Edge* edge = new Edge(source, target);
228 const bool addedOut = source->addOutgoingEdge(edge);
229 const bool addedIn = target->addIncomingEdge(edge);
230 assert(addedOut && addedIn);
231 (void)addedOut;
232 (void)addedIn;
233 incEdgeNum();
234 if (!target->branch)
235 inputs[target->location].push_back(edge);
236}
Map< const ICFGNode *, std::vector< const Edge * > > inputs

◆ connectFrom()

void SparseObjGraph::connectFrom ( NodeID base,
const ICFGNode * source,
const Set< const ICFGNode * > & events,
Set< const ICFGNode * > & newSources )
private

Definition at line 255 of file SparseObjGraph.cpp.

259{
260 // From one Obj event, find the next event or control boundary in this
261 // function. Feasibility is not checked here, so AE states share the route.
262 const FunObjVar* fun = source->getFun();
263 if (!fun)
264 return;
265
266 std::vector<std::pair<const ICFGNode*, const IntraCFGEdge*>> first;
267 // inter-procedure
268 if (const auto* call = SVFUtil::dyn_cast<CallICFGNode>(source))
269 {
270 const RetICFGNode* ret = call->getRetICFGNode();
271 bool needsCallerToRetEdge = !returnedGroups[ret].count(base);
272 for (const ICFGEdge* out : call->getOutEdges())
273 {
274 const auto* callEdge = SVFUtil::dyn_cast<CallCFGEdge>(out);
275 if (callEdge && !returnedGroupsByCallee[ret][out->getDstNode()->getFun()].count(base))
276 needsCallerToRetEdge = true;
277 }
278 // C may call f_write(&x) or f_noop(&x). If a callee has no return
279 // edge for x, retain C -> R so that candidate carries the pre-call
280 // value; a candidate with a return edge uses callee-output -> R.
281 if (needsCallerToRetEdge)
282 first.emplace_back(call->getRetICFGNode(), nullptr);
283 }
284 else
285 // intra-procedure
286 {
287 for (const ICFGEdge* out : source->getOutEdges())
288 {
289 if (const auto* intra = SVFUtil::dyn_cast<IntraCFGEdge>(out))
290 first.emplace_back(intra->getDstNode(),
291 intra->getCondition() ? intra : nullptr);
292 }
293 }
294
295 for (const auto& [start, branch] : first)
296 {
297 // Cross ordinary ICFG nodes between events; stop at a branch, call,
298 // return, or the next Obj event, which starts another route segment.
299 // For base=z: B: if (z > 0) { Ux: use(x); Uz: use(z); }.
300 // With ordinary non-aliasing loads, Ux is not a z event; traverse
301 // past Ux and call addEdge(z, B, Uz, true edge) at Uz.
302 Set<const ICFGNode*> visited;
303 std::deque<const ICFGNode*> pending{start};
304 while (!pending.empty())
305 {
306 const ICFGNode* current = pending.front();
307 pending.pop_front();
308 if (current && current->getFun() == fun &&
309 visited.insert(current).second)
310 {
311 const bool objSite = events.count(current);
312 const bool controlBoundary = isBranch(current) ||
315 if (objSite || controlBoundary)
316 {
317 addEdge(base, source, current, branch);
318 if (!objSite)
319 newSources.insert(current);
320 }
321 else
322 {
323 for (const ICFGEdge* out : current->getOutEdges())
324 {
325 if (const auto* intra = SVFUtil::dyn_cast<IntraCFGEdge>(out))
326 pending.push_back(intra->getDstNode());
327 }
328 }
329 }
330 }
331 }
332}
bool isBranch(const ICFGNode *node) const

◆ dump()

void SparseObjGraph::dump ( const std::string & file)

Write a DOT graph to <file>.dot through GraphPrinter.

Definition at line 380 of file SparseObjGraph.cpp.

381{
383}
static void WriteGraphToFile(SVF::OutStream &O, const std::string &GraphName, const GraphType &GT, bool simple=false)
std::ostream & outs()
Overwrite llvm::outs().
Definition SVFUtil.h:58

◆ getBranchNode()

SparseObjGraph::Node * SparseObjGraph::getBranchNode ( NodeID base,
const IntraCFGEdge * branch )
private

Definition at line 207 of file SparseObjGraph.cpp.

209{
210 // B: if (x > 0) -> N: use(x). B's true and false edges have distinct
211 // nodes; the nodes store edge identity, not AE's refined interval.
212 Node*& node = branchNodes[base][branch];
213 if (!node)
214 {
215 node = new Node(getTotalNodeNum(), base, branch->getSrcNode(), branch);
216 addGNode(node->getId(), node);
217 }
218 return node;
219}
NodeType * getSrcNode() const
Map< NodeID, Map< const IntraCFGEdge *, Node * > > branchNodes

◆ getInputs()

const std::vector< const SparseObjGraph::Edge * > & SparseObjGraph::getInputs ( const ICFGNode * node) const

Return incoming edges at this ICFG location for client-side value flow.

Definition at line 335 of file SparseObjGraph.cpp.

336{
337 static const std::vector<const Edge*> empty;
338 const auto it = inputs.find(node);
339 return it == inputs.end() ? empty : it->second;
340}

◆ getOrCreateBaseObjNode()

SparseObjGraph::Node * SparseObjGraph::getOrCreateBaseObjNode ( NodeID baseObjId,
const ICFGNode * location )
private

Definition at line 194 of file SparseObjGraph.cpp.

196{
197 // One node per (base, ICFG location) may group several SVFG nodes.
198 Node*& node = groupNodes[baseObjId][location];
199 if (!node)
200 {
201 node = new Node(getTotalNodeNum(), baseObjId, location, nullptr);
202 addGNode(node->getId(), node);
203 }
204 return node;
205}
Map< NodeID, Map< const ICFGNode *, Node * > > groupNodes
Normal nodes are unique by (base, ICFG location); branch nodes by edge.

◆ isBranch()

bool SparseObjGraph::isBranch ( const ICFGNode * node) const
private

Definition at line 182 of file SparseObjGraph.cpp.

183{
184 // Only conditional intra-function ICFG edges count as branches.
185 for (const ICFGEdge* out : node->getOutEdges())
186 {
187 const auto* intra = SVFUtil::dyn_cast<IntraCFGEdge>(out);
188 if (intra && intra->getCondition())
189 return true;
190 }
191 return false;
192}

◆ operator=()

SparseObjGraph & SVF::SparseObjGraph::operator= ( const SparseObjGraph & )
delete

◆ toString()

std::string SparseObjGraph::toString ( ) const

Describe the static nodes and edges as text, without AE values.

Definition at line 342 of file SparseObjGraph.cpp.

343{
344 std::ostringstream out;
345 for (const auto& entry : *this)
346 out << entry.second->toString() << '\n';
347 for (const auto& entry : *this)
348 for (const Edge* edge : entry.second->getOutEdges())
349 out << edge->toString() << '\n';
350 return out.str();
351}

Member Data Documentation

◆ branchNodes

Map<NodeID, Map<const IntraCFGEdge*, Node*> > SVF::SparseObjGraph::branchNodes
private

Definition at line 93 of file SparseObjGraph.h.

◆ groupNodes

Map<NodeID, Map<const ICFGNode*, Node*> > SVF::SparseObjGraph::groupNodes
private

Normal nodes are unique by (base, ICFG location); branch nodes by edge.

Definition at line 92 of file SparseObjGraph.h.

◆ icfg

ICFG& SVF::SparseObjGraph::icfg
private

Definition at line 90 of file SparseObjGraph.h.

◆ inputs

Map<const ICFGNode*, std::vector<const Edge*> > SVF::SparseObjGraph::inputs
private

Definition at line 94 of file SparseObjGraph.h.

◆ returnedGroups

Map<const ICFGNode*, Set<NodeID> > SVF::SparseObjGraph::returnedGroups
private

Bases with a callee-output to caller-return SVFG edge. The second map distinguishes callees when deciding whether a multi-target call bypasses.

Definition at line 97 of file SparseObjGraph.h.

◆ returnedGroupsByCallee

Map<const ICFGNode*, Map<const FunObjVar*, Set<NodeID> > > SVF::SparseObjGraph::returnedGroupsByCallee
private

Definition at line 98 of file SparseObjGraph.h.


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