Static Value-Flow Analysis
Loading...
Searching...
No Matches
SlicedGraphs.cpp
Go to the documentation of this file.
1//===- SlicedGraphs.cpp -- General sliced graph views ----------------------===//
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
23/*
24 * SlicedGraphs.cpp
25 *
26 * Author: Jiawei Yang
27 */
28
29#include "Graphs/SlicedGraphs.h"
30#include "Graphs/SVFGNode.h"
31#include "Graphs/GraphPrinter.h"
33#include "Util/SVFUtil.h"
34#include "Util/ThreadAPI.h"
35#include "SVFIR/SVFIR.h"
36#include <cassert>
37#include <cstdlib>
38
39using namespace SVF;
40
41namespace SVF
42{
43
44//===----------------------------------------------------------------------===//
45// DOTGraphTraits for the sliced ICFG view (used by GraphWriter). Mirrors the
46// placement of DOTGraphTraits<ICFG*> in ICFG.cpp.
47//===----------------------------------------------------------------------===//
48template <>
50{
51 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple)
52 {
53 }
54
55 static std::string getGraphName(const SlicedICFGView*)
56 {
57 return "SlicedICFG";
58 }
59
60 // Value NodeRef: identity is the underlying kept node.
62 {
63 return n.raw;
64 }
65
67 {
68 return n.raw != nullptr ? n.raw->toString() : "";
69 }
70
72 {
73 std::string str = "shape=record";
74 const ICFGNode* node = n.raw;
75 if (SVFUtil::isa<FunEntryICFGNode>(node))
76 str += ",color=yellow";
77 else if (SVFUtil::isa<FunExitICFGNode>(node))
78 str += ",color=green";
79 else if (SVFUtil::isa<CallICFGNode>(node))
80 str += ",color=red";
81 else if (SVFUtil::isa<RetICFGNode>(node))
82 str += ",color=blue";
83 else if (SVFUtil::isa<GlobalICFGNode>(node))
84 str += ",color=purple";
85 else
86 str += ",color=black";
87 return str;
88 }
89
90 // Bridged edges are drawn dashed; kept original call/ret edges keep their colour.
91 template <class EdgeIter>
93 {
94 const SlicedICFGEdgeRef& e = EI.currentEdge();
95 if (e.bridged)
96 return "style=dashed,color=gray";
97 if (e.underlying != nullptr && SVFUtil::isa<CallCFGEdge>(e.underlying))
98 return "style=solid,color=red";
99 if (e.underlying != nullptr && SVFUtil::isa<RetCFGEdge>(e.underlying))
100 return "style=solid,color=blue";
101 return "style=solid";
102 }
103};
104
105//===----------------------------------------------------------------------===//
106// DOTGraphTraits for the sliced ThreadCallGraph view.
107//===----------------------------------------------------------------------===//
108template <>
110{
111 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple)
112 {
113 }
114
115 static std::string getGraphName(const SlicedThreadCallGraphView*)
116 {
117 return "SlicedThreadCallGraph";
118 }
119
121 {
122 return n.raw;
123 }
124
126 {
127 return n.raw != nullptr ? n.raw->getName() : "";
128 }
129
131 {
132 return "shape=record,color=black";
133 }
134
135 template <class EdgeIter>
137 {
138 const CallGraphEdge* e = EI.currentEdge().underlying;
139 if (e != nullptr && e->getEdgeKind() == CallGraphEdge::TDForkEdge)
140 return "color=green";
141 if (e != nullptr && e->getEdgeKind() == CallGraphEdge::CallRetEdge)
142 return "color=blue";
143 return "color=black";
144 }
145};
146
147//===----------------------------------------------------------------------===//
148// DOTGraphTraits for the sliced PAG view.
149//===----------------------------------------------------------------------===//
150template <>
152{
153 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple)
154 {
155 }
156
157 static std::string getGraphName(const SlicedPAGView*)
158 {
159 return "SlicedPAG";
160 }
161
163 {
164 return n.raw;
165 }
166
168 {
169 return n.raw != nullptr ? n.raw->toString() : "";
170 }
171
173 {
174 return "shape=record,color=black";
175 }
176
177 template <class EdgeIter>
179 {
180 const SVFStmt* s = EI.currentEdge().underlying;
181 if (SVFUtil::isa<LoadStmt>(s))
182 return "color=blue";
183 if (SVFUtil::isa<StoreStmt>(s))
184 return "color=red";
185 if (SVFUtil::isa<GepStmt>(s))
186 return "color=purple";
187 if (SVFUtil::isa<AddrStmt>(s))
188 return "color=green";
189 if (SVFUtil::isa<CallPE>(s))
190 return "color=orange";
191 if (SVFUtil::isa<RetPE>(s))
192 return "color=cyan";
193 return "color=black";
194 }
195};
196
197//===----------------------------------------------------------------------===//
198// DOTGraphTraits for the sliced SVFG view.
199//===----------------------------------------------------------------------===//
200template <>
202{
203 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple)
204 {
205 }
206
207 static std::string getGraphName(const SlicedSVFGView*)
208 {
209 return "SlicedSVFG";
210 }
211
213 {
214 return n.raw;
215 }
216
218 {
219 return n.raw != nullptr ? n.raw->toString() : "";
220 }
221
223 {
224 if (SVFUtil::isa<StoreSVFGNode>(n.raw))
225 return "shape=record,color=red";
226 if (SVFUtil::isa<LoadSVFGNode>(n.raw))
227 return "shape=record,color=blue";
228 return "shape=record,color=black";
229 }
230
231 template <class EdgeIter>
233 {
234 const SVFGEdge* e = EI.currentEdge().underlying;
235 if (e != nullptr && SVFUtil::isa<IndirectSVFGEdge>(e))
236 return "style=dashed";
237 return "style=solid";
238 }
239};
240
241//===----------------------------------------------------------------------===//
242// SlicedSVFGView
243//===----------------------------------------------------------------------===//
244
246{
247 if (n == nullptr)
248 return false;
249 return retainedNodeIds.test(n->getId());
250}
251
253{
254 return retainedNodeIds.count();
255}
256
257void SlicedSVFGView::dump(const std::string& filename) const
258{
259 assert(svfg != nullptr && "SlicedSVFGView: bind the SVFG before dumping");
261}
262
263//===----------------------------------------------------------------------===//
264// SlicedICFGView
265//===----------------------------------------------------------------------===//
266
274
275// getSuccNodes/getPredNodes and the GenericGraphTraits iterators must agree on the
276// slice topology, so both go through the one traits definition (kept original
277// edges + bridged edges). The sliced MHP/Lock analyses reach the slice here.
279 const ICFGNode* node, std::vector<const ICFGNode*>& out) const
280{
281 out.clear();
282 if (!isKeptNode(node))
283 {
284 return;
285 }
287 const SlicedICFGNodeRef n{this, node};
288 for (auto it = GT::child_begin(n), e = GT::child_end(n); it != e; ++it)
289 out.push_back((*it).raw);
290}
291
293 const ICFGNode* node, std::vector<const ICFGNode*>& out) const
294{
295 out.clear();
296 if (!isKeptNode(node))
297 {
298 return;
299 }
301 const SlicedICFGNodeRef n{this, node};
302 for (auto it = GT::child_begin(n), e = GT::child_end(n); it != e; ++it)
303 out.push_back((*it).raw);
304}
305
307{
308 return keptNodesSet.count(node) > 0;
309}
310
311void SlicedICFGView::dump(const std::string& filename) const
312{
313 // Kept nodes + kept original edges + bridged edges are all produced by the
314 // GenericGraphTraits<const SlicedICFGView*> iterators; GraphWriter styles
315 // bridged edges dashed via DOTGraphTraits::getEdgeAttributes.
317}
318
321{
322 keptNodes.clear();
323 keptNodes.insert(keepNodes.begin(), keepNodes.end());
324
325 // Build keptNodesSet for fast lookup
326 keptNodesSet.clear();
327 keptNodesSet.insert(keptNodes.begin(), keptNodes.end());
328}
329
331{
332 // bridgedEdges[u] (u kept) = kept nodes reachable from u through removed-only
333 // paths = U reachKept(s) over removed successors s of u, where reachKept(r) is
334 // computed by SCC-condensing the removed subgraph (cyclic) and propagating
335 // kept-reachability over the condensation -- linear, vs. node contraction whose
336 // cross-products blow up when the removed region is large (small slices).
337
338 // Index the removed nodes and their removed-only adjacency + kept successors.
339 std::vector<const ICFGNode*> removed;
341 for (ICFG::iterator it = icfg->begin(), eit = icfg->end();
342 it != eit; ++it)
343 {
344 const ICFGNode* node = it->second;
345 if (node == nullptr || keptNodesSet.count(node))
346 continue;
347 removedNodeIndex[node] = static_cast<int>(removed.size());
348 removed.push_back(node);
349 }
350 const int removedNodeCount = static_cast<int>(removed.size());
351
352 // call_i -> ret_i summary for call sites with an omitted callee (some resolved
353 // callee entry not retained), for every call site so paths can compose through
354 // removed ones. ret_i is in the same caller, so the seed stays intra-procedural.
356 for (ICFG::iterator it = icfg->begin(), eit = icfg->end();
357 it != eit; ++it)
358 {
359 const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(it->second);
360 if (call == nullptr || call->getRetICFGNode() == nullptr)
361 continue;
362 for (const ICFGEdge* edge : call->getOutEdges())
363 if (edge != nullptr && SVFUtil::isa<CallCFGEdge>(edge) &&
364 keptNodesSet.count(edge->getDstNode()) == 0)
365 {
366 seedRet[call] = call->getRetICFGNode();
367 break;
368 }
369 }
370 // Local successors = intra edges + matched call->ret seeds; the only edges
371 // contraction may traverse. Original call/ret edges are excluded.
372 std::vector<std::vector<int>> removedSuccessors(removedNodeCount);
373 std::vector<std::vector<const ICFGNode*>>
375 std::vector<const ICFGNode*> successors;
377 {
379 for (const ICFGNode* successor : successors)
380 {
381 if (keptNodesSet.count(successor))
383 else
384 {
385 const auto found = removedNodeIndex.find(successor);
386 if (found != removedNodeIndex.end())
388 }
389 }
390 }
391
392 // Iterative Tarjan SCC over the removed subgraph. Components are produced in
393 // reverse-topological order, so comp ids of a node's successors are < its own.
394 std::vector<int> discoveryIndex(removedNodeCount, -1);
395 std::vector<int> lowLink(removedNodeCount, 0);
396 std::vector<int> component(removedNodeCount, -1);
397 std::vector<char> onStack(removedNodeCount, 0);
398 std::vector<int> tarjanStack;
399 int nextDiscoveryIndex = 0;
400 int componentCount = 0;
401 for (int root = 0; root < removedNodeCount; ++root)
402 {
403 if (discoveryIndex[root] != -1)
404 continue;
405 std::vector<std::pair<int, size_t>> work;
406 work.emplace_back(root, 0);
407 while (!work.empty())
408 {
409 const int nodeIndex = work.back().first;
410 size_t& successorPosition = work.back().second;
411 if (successorPosition == 0)
412 {
415 tarjanStack.push_back(nodeIndex);
416 onStack[nodeIndex] = 1;
417 }
418 bool descend = false;
420 {
421 const int successorIndex =
424 {
425 work.emplace_back(successorIndex, 0);
426 descend = true;
427 break;
428 }
429 if (onStack[successorIndex] &&
432 }
433 if (descend)
434 continue;
436 {
437 while (true)
438 {
439 const int componentNode = tarjanStack.back();
440 tarjanStack.pop_back();
441 onStack[componentNode] = 0;
442 component[componentNode] = componentCount;
444 break;
445 }
447 }
448 work.pop_back();
449 if (!work.empty())
450 {
451 const int parentIndex = work.back().first;
454 }
455 }
456 }
457
458 // Condensation: base kept-successors and DAG successors per component.
459 std::vector<OrderedSet<const ICFGNode*>> baseKept(componentCount);
460 std::vector<OrderedSet<int>> componentSuccessors(componentCount);
462 {
463 const int componentIndex = component[nodeIndex];
467 if (component[successorIndex] != componentIndex)
469 component[successorIndex]);
470 }
471
472 // Propagate reachKept in ascending comp order (successors have smaller ids).
473 std::vector<OrderedSet<const ICFGNode*>>
477 {
482 reachable.insert(
485 }
486
487 // bridgedEdges[u] = kept nodes reached from kept u through removed local paths,
488 // plus a matched call->ret summary when u is a seeded call site (kept ret).
489 for (const ICFGNode* source : keptNodesSet)
490 {
491 getLocalSuccessors(source, seedRet, successors);
492 const auto seedReturn = seedRet.find(source);
493 for (const ICFGNode* successor : successors)
494 {
495 if (keptNodesSet.count(successor))
496 {
497 // Kept seed target: no real edge exists, so record the bridge; a
498 // kept intra target is a real edge handled by getSuccNodes.
499 if (seedReturn != seedRet.end() &&
500 seedReturn->second == successor)
501 {
504 }
505 continue;
506 }
507 const auto removedIndex = removedNodeIndex.find(successor);
508 if (removedIndex == removedNodeIndex.end())
509 {
511 << "[ERROR] Local ICFG successor is neither kept nor indexed\n";
512 std::abort();
513 }
514 for (const ICFGNode* target :
515 reachableKeptNodes[component[removedIndex->second]])
516 {
517 bridgedEdges[source].insert(target);
518 bridgedPreds[target].insert(source);
519 }
520 }
521 }
522
523 size_t totalBridgedEdges = 0;
524 for (const auto& pair : bridgedEdges)
525 totalBridgedEdges += pair.second.size();
526 SVFUtil::outs() << "[SlicedICFGView] Built " << totalBridgedEdges
527 << " bridged edges across " << bridgedEdges.size()
528 << " source nodes\n";
529}
530
532 const ICFGNode* node,
534 std::vector<const ICFGNode*>& successors)
535{
536 successors.clear();
537 for (const ICFGEdge* edge : node->getOutEdges())
538 if (edge != nullptr && SVFUtil::isa<IntraCFGEdge>(edge) &&
539 edge->getDstNode() != nullptr)
540 successors.push_back(edge->getDstNode());
541
542 const auto returnNode = callsiteReturnNodes.find(node);
543 if (returnNode != callsiteReturnNodes.end())
544 successors.push_back(returnNode->second);
545}
546
547//===----------------------------------------------------------------------===//
548// SlicedPAGView
549//===----------------------------------------------------------------------===//
550
552 : pag(pag), keptStmts(keptStmts)
553{
555}
556
558{
559 for (const SVFStmt* stmt : keptStmts)
560 {
561 // Handle the two SVF statement abstractions directly so new concrete
562 // statement subclasses cannot silently disappear from the PAG view.
563 if (const AssignStmt* assignStmt = SVFUtil::dyn_cast<AssignStmt>(stmt))
564 {
565 keptNodeIds.insert(assignStmt->getLHSVarID());
566 keptNodeIds.insert(assignStmt->getRHSVarID());
567 continue;
568 }
569 if (const MultiOpndStmt* multi =
570 SVFUtil::dyn_cast<MultiOpndStmt>(stmt))
571 {
572 keptNodeIds.insert(multi->getResID());
573 for (u32_t i = 0; i < multi->getOpVarNum(); ++i)
574 keptNodeIds.insert(multi->getOpVarID(i));
575 }
576 }
577}
578
579void SlicedPAGView::dump(const std::string& filename) const
580{
581 // Nodes = SVFVars of kept statements; edges = kept SVFStmts via
582 // GenericGraphTraits<const SlicedPAGView*>. MultiOpndStmts use the
583 // underlying src/dst (no operand fan-out).
585}
586
587//===----------------------------------------------------------------------===//
588// SlicedThreadCallGraphView
589//===----------------------------------------------------------------------===//
590
593 const OrderedSet<const ICFGNode*>& extendedKeptNodes)
594 : tcg(tcg)
595{
596 for (const FunObjVar* fun : keptFunctions)
597 {
598 keptFunctionsSet.insert(fun);
599 }
600 this->extendedKeptNodes = extendedKeptNodes;
602 // The input already contains the slicing targets and control-flow anchors;
603 // buildCallGraphSets filters edges whose callsites were pruned.
605}
606
608{
609 for (CallGraph::iterator it = tcg->begin(), eit = tcg->end();
610 it != eit; ++it)
611 {
612 const CallGraphNode* node = it->second;
613 if (node != nullptr && node->getFunction() != nullptr &&
614 keptFunctionsSet.count(node->getFunction()))
615 {
616 keptNodes.insert(node);
617 }
618 }
619}
620
622 const CallGraphNode* node, std::vector<const CallGraphEdge*>& out) const
623{
624 out.clear();
625 if (!isKeptNode(node))
626 {
627 return;
628 }
629
631 const SlicedCallGraphNodeRef n{this, node};
632 for (auto it = GT::child_edge_begin(n), e = GT::child_edge_end(n); it != e; ++it)
633 out.push_back((*it).underlying);
634}
635
637 const CallGraphNode* node, std::vector<const CallGraphEdge*>& out) const
638{
639 out.clear();
640 if (!isKeptNode(node))
641 {
642 return;
643 }
645 const SlicedCallGraphNodeRef n{this, node};
646 for (auto it = GT::child_edge_begin(n), e = GT::child_edge_end(n); it != e; ++it)
647 out.push_back((*it).underlying);
648}
649
651 const CallGraphEdge* edge, std::vector<const CallICFGNode*>& out) const
652{
653 out.clear();
654 const auto found = keptDirectCalls.find(edge);
655 if (found != keptDirectCalls.end())
656 out.insert(out.end(), found->second.begin(), found->second.end());
657}
658
660 const CallGraphEdge* edge, std::vector<const CallICFGNode*>& out) const
661{
662 out.clear();
663 const auto found = keptIndirectCalls.find(edge);
664 if (found != keptIndirectCalls.end())
665 out.insert(out.end(), found->second.begin(), found->second.end());
666}
667
669 const CallGraphEdge* edge, const CallICFGNode* callSite) const
670{
671 const auto direct = keptDirectCalls.find(edge);
672 if (direct != keptDirectCalls.end() && direct->second.count(callSite))
673 return true;
674 const auto indirect = keptIndirectCalls.find(edge);
675 return indirect != keptIndirectCalls.end() &&
676 indirect->second.count(callSite);
677}
678
681{
682 callees.clear();
683 const CallGraphNode* caller = tcg->getCallGraphNode(callSite->getFun());
684 if (!isKeptNode(caller))
685 {
686 return;
687 }
688 std::vector<const CallGraphEdge*> outEdges;
690 for (const CallGraphEdge* edge : outEdges)
691 {
693 {
694 callees.insert(edge->getDstNode()->getFunction());
695 }
696 }
697}
698
700 const CallICFGNode* callSite,
701 std::vector<const CallGraphEdge*>& out) const
702{
703 out.clear();
704 if (!extendedKeptNodes.count(callSite) ||
706 return;
707 for (auto it = tcg->getForkEdgeBegin(callSite),
708 end = tcg->getForkEdgeEnd(callSite); it != end; ++it)
709 {
710 const CallGraphEdge* edge = *it;
711 if (isKeptNode(edge->getSrcNode()) &&
712 isKeptNode(edge->getDstNode()) &&
714 out.push_back(edge);
715 }
716}
717
719 const CallICFGNode* callSite,
720 std::vector<const CallGraphEdge*>& out) const
721{
722 out.clear();
723 if (!extendedKeptNodes.count(callSite) ||
725 return;
726 for (auto it = tcg->getJoinEdgeBegin(callSite),
727 end = tcg->getJoinEdgeEnd(callSite); it != end; ++it)
728 {
729 const CallGraphEdge* edge = *it;
730 if (isKeptNode(edge->getSrcNode()) &&
731 isKeptNode(edge->getDstNode()))
732 out.push_back(edge);
733 }
734}
735
737{
738 return keptNodes.count(node) > 0;
739}
740
742{
743 // rebuild kept edges, accounting for whether the call site is kept
744 keptEdges.clear();
745 keptDirectCalls.clear();
746 keptIndirectCalls.clear();
748
749 // CallGraph edge: src/dst both in kept functions and the call site still in the kept ICFG node set
750 for (const CallGraphNode* srcNode : keptNodes)
751 {
752 for (const CallGraphEdge* edge : srcNode->getOutEdges())
753 {
754 const CallGraphNode* dstNode = edge ? edge->getDstNode() : nullptr;
755 if (dstNode == nullptr || !keptNodes.count(dstNode))
756 {
757 continue;
758 }
759
761 for (const CallICFGNode* callSite : edge->getDirectCalls())
762 if (extendedKeptNodes.count(callSite))
763 retainedDirect.insert(callSite);
764
766 for (const CallICFGNode* callSite : edge->getIndirectCalls())
767 if (extendedKeptNodes.count(callSite))
769
770 const bool hasOriginalCallSites =
771 !edge->getDirectCalls().empty() || !edge->getIndirectCalls().empty();
772 if (hasOriginalCallSites && retainedDirect.empty() && retainedIndirect.empty())
773 {
774 keptDirectCalls.erase(edge);
775 keptIndirectCalls.erase(edge);
776 continue;
777 }
778
779 keptEdges.insert(edge);
780 }
781 }
782
783 // An indirect callsite is empty only when none of its original targets is
784 // represented by a retained callsite-to-callee relation.
785 for (const ICFGNode* node : extendedKeptNodes)
786 {
787 const CallICFGNode* callSite = SVFUtil::dyn_cast<CallICFGNode>(node);
788 if (callSite == nullptr || !tcg->hasIndCSCallees(callSite))
789 continue;
792 if (callees.empty())
794 }
795}
796
797void SlicedThreadCallGraphView::dump(const std::string& filename) const
798{
799 // Kept nodes + canonical kept edges via GenericGraphTraits; join edges are
800 // not in the normal adjacency, so they are not drawn here.
802}
803
804//===----------------------------------------------------------------------===//
805// SlicedSVFIRView
806//===----------------------------------------------------------------------===//
807
809 ThreadCallGraph& callGraph,
810 ICFG* icfg,
812 : svfir(svfir)
813{
814 // A retained function is represented by explicit synthetic entry/exit
815 // nodes. Graph-generic MHP and lock propagation can therefore never seed or
816 // rendezvous at a node outside the view.
818
819 // Derive keptFunctions from keepNodes.
821 for (const ICFGNode* node : keepNodes)
822 {
823 if (node != nullptr && node->getFun() != nullptr)
824 {
825 keptFunctions.insert(node->getFun());
826 }
827 }
828 for (const FunObjVar* fun : keptFunctions)
829 {
830 extendedKeepNodes.insert(icfg->getFunEntryICFGNode(fun));
831 extendedKeepNodes.insert(icfg->getFunExitICFGNode(fun));
832 }
833
834 tcgView = std::make_unique<SlicedThreadCallGraphView>(
835 &callGraph, keptFunctions, extendedKeepNodes);
836
837 // Create ICFG view (based on keepNodes and keptFunctions)
838 icfgView = std::make_unique<SlicedICFGView>(
839 icfg, extendedKeepNodes);
840}
841
843{
844 if (pagView != nullptr)
845 return;
846
847 // Most analyses consume only the sliced ICFG and call graph. Materialize
848 // the PAG membership only for clients that explicitly request that view.
850 for (const ICFGNode* node : icfgView->getKeptNodes())
851 {
852 const ICFGNode::SVFStmtList& stmts = node->getSVFStmts();
853 keptStmts.insert(stmts.begin(), stmts.end());
854 }
855 pagView = std::make_unique<SlicedPAGView>(svfir, keptStmts);
856}
857
858void SlicedSVFIRView::dumpAll(const std::string& prefix) const
859{
860 icfgView->dump(prefix + "_icfg");
861 tcgView->dump(prefix + "_threadcallgraph");
862 getPAG()->dump(prefix + "_pag");
863}
864
865void SlicedSVFIRView::dumpStats(const std::string& prefix) const
866{
867 std::string label = prefix.empty() ? "[SlicedSVFIRView]" : "[" + prefix + "]";
868 SVFUtil::outs() << label << " Statistics:\n";
869 SVFUtil::outs() << " ICFG nodes: " << icfgView->getKeptNodes().size() << "\n";
870 SVFUtil::outs() << " Functions: " << getKeptFunctions().size() << "\n";
871 SVFUtil::outs() << " PAG statements: " << getKeptStatements().size() << "\n";
873 {
874 SVFUtil::outs() << " Indirect callsites that lost all targets: "
875 << getIndirectSitesWithEmptyTargets().size() << "\n";
876 }
877}
878
879//===----------------------------------------------------------------------===//
880// SlicedICFGView traversal helpers used by the sliced analyses.
881//===----------------------------------------------------------------------===//
882
884{
885 // Prefer the kept FunEntryICFGNode: MultiStageSlicer::expandCallDependence keeps it
886 // for every kept function and buildBridgedEdges links it to the kept body, so
887 // the MHP interleaving fixpoint can flow from it to every kept statement.
888 // The entry basic block's first instruction, by contrast, may be sliced out;
889 // returning it (a removed node) would strand the root/thread seed there --
890 // getSuccNodes() yields nothing for a non-kept node -- so the function body
891 // would never receive the thread's interleaving (a soundness bug).
892 if (const ICFGNode* fe = icfg->getFunEntryICFGNode(fun))
893 {
894 if (isKeptNode(fe))
895 return fe;
896 }
897 // A view constructor always retains the synthetic entry. Keep the fallback
898 // for defensive compatibility with directly constructed SlicedICFGViews,
899 // but never return a node outside this view.
900 const ICFGNode* entry = fun->getEntryBlock()->front();
901 if (isKeptNode(entry))
902 return entry;
903 for (const ICFGNode* node : fun->getEntryBlock()->getICFGNodeList())
904 {
905 if (isKeptNode(node))
906 return node;
907 }
908 return nullptr;
909}
910
912{
913 const ICFGNode* exit = icfg->getFunExitICFGNode(fun);
914 return isKeptNode(exit) ? exit : nullptr;
915}
916
918 std::vector<const ICFGNode*>& out) const
919{
920 out.clear();
921 for (auto it : *fun)
922 {
923 const SVFBasicBlock* svfbb = it.second;
924 for (const ICFGNode* node : svfbb->getICFGNodeList())
925 if (isKeptNode(node))
926 out.push_back(node);
927 }
928}
929
930} // End namespace SVF
cJSON * n
Definition cJSON.cpp:2558
Set< const CallICFGNode * > CallInstSet
Definition CallGraph.h:55
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
bool hasIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:335
const CallGraphNode * getCallGraphNode(const std::string &name) const
Get call graph node.
Set< const FunObjVar * > FunctionSet
Definition CallGraph.h:247
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:440
const SVFBasicBlock * getEntryBlock() const
GEdgeKind getEdgeKind() const
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
const GEdgeSetTy & getOutEdges() const
static void WriteGraphToFile(SVF::OutStream &O, const std::string &GraphName, const GraphType &GT, bool simple=false)
std::list< const SVFStmt * > SVFStmtList
Definition ICFGNode.h:65
ICFGNodeIDToNodeMapTy::iterator iterator
Definition ICFG.h:58
FunExitICFGNode * getFunExitICFGNode(const FunObjVar *fun)
Add a function exit node.
Definition ICFG.cpp:250
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:243
const std::vector< const ICFGNode * > & getICFGNodeList() const
const ICFGNode * front() const
static void getLocalSuccessors(const ICFGNode *node, const Map< const ICFGNode *, const ICFGNode * > &callsiteReturnNodes, std::vector< const ICFGNode * > &successors)
const ICFGNode * getFunExit(const FunObjVar *fun) const
Kept synthetic exit node of fun, or null when fun is outside the view.
Set< const ICFGNode * > keptNodesSet
void getPredNodes(const ICFGNode *node, std::vector< const ICFGNode * > &out) const
Get predecessor nodes (including bridged edges)
Map< const ICFGNode *, OrderedSet< const ICFGNode * > > bridgedPreds
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
bool isKeptNode(const ICFGNode *node) const
Check if a node is in the sliced view.
SlicedICFGView(ICFG *icfg, const OrderedSet< const ICFGNode * > &keepNodes)
Build an ICFG view from its explicit node membership.
void getSuccNodes(const ICFGNode *node, std::vector< const ICFGNode * > &out) const
Get successor nodes (including bridged edges)
Map< const ICFGNode *, OrderedSet< const ICFGNode * > > bridgedEdges
const ICFGNode * getFunEntry(const FunObjVar *fun) const
First kept node of fun's entry, or null when fun is outside the view.
void buildICFGSets(const OrderedSet< const ICFGNode * > &keepNodes)
void getFunICFGNodes(const FunObjVar *fun, std::vector< const ICFGNode * > &out) const
Kept ICFG nodes of fun.
OrderedSet< const ICFGNode * > keptNodes
SlicedPAGView(SVFIR *pag, const OrderedSet< const SVFStmt * > &keptStmts)
Set< NodeID > keptNodeIds
void dump(const std::string &filename) const
Dump the sliced PAG to a dot file.
OrderedSet< const SVFStmt * > keptStmts
size_t getKeptNodeCount() const
bool isKeptNode(const SVFGNode *n) const
Whether the node is retained (see the class comment for the rule).
void dump(const std::string &filename) const
Dump the sliced SVFG (retained nodes/edges only) via GraphWriter.
const Set< const FunObjVar * > & getKeptFunctions() const
Get all kept functions.
std::unique_ptr< SlicedPAGView > pagView
std::unique_ptr< SlicedThreadCallGraphView > tcgView
void dumpAll(const std::string &prefix) const
Dump all views to files.
std::unique_ptr< SlicedICFGView > icfgView
const SlicedPAGView * getPAG() const
Get SlicedPAGView.
void dumpStats(const std::string &prefix="") const
Output statistics.
SlicedSVFIRView(SVFIR *svfir, ThreadCallGraph &callGraph, ICFG *icfg, const OrderedSet< const ICFGNode * > &keepNodes)
const OrderedSet< const SVFStmt * > & getKeptStatements() const
Get all kept statements.
void ensurePAGView() const
const Set< const CallICFGNode * > & getIndirectSitesWithEmptyTargets() const
Get indirect call sites that lost all targets after filtering.
void getCalleesOf(const CallICFGNode *callSite, CallGraph::FunctionSet &callees) const
Retained callees of a callsite.
void getDirectCallsOf(const CallGraphEdge *edge, std::vector< const CallICFGNode * > &out) const
Retained callsites carried by an aggregated call-graph edge.
bool isKeptNode(const CallGraphNode *node) const
Check if a node is in the sliced view.
void dump(const std::string &filename) const
Dump sliced ThreadCallGraph to dot file.
OrderedSet< const CallGraphNode * > keptNodes
Set< const CallGraphEdge * > keptEdges
bool containsCallSite(const CallGraphEdge *edge, const CallICFGNode *callSite) const
Whether this precise callsite-to-callee relation is retained.
void getIndirectCallsOf(const CallGraphEdge *edge, std::vector< const CallICFGNode * > &out) const
Set< const FunObjVar * > keptFunctionsSet
Map< const CallGraphEdge *, CallGraphEdge::CallInstSet > keptDirectCalls
void getForkEdgesOf(const CallICFGNode *callSite, std::vector< const CallGraphEdge * > &out) const
void getOutEdgesOf(const CallGraphNode *node, std::vector< const CallGraphEdge * > &out) const
Get out edges of a node (only returns kept edges and target nodes)
Set< const CallICFGNode * > indirectSitesWithEmptyTargets
void getInEdgesOf(const CallGraphNode *node, std::vector< const CallGraphEdge * > &out) const
Get in edges of a node (only returns kept edges and source nodes)
void getJoinEdgesOf(const CallICFGNode *callSite, std::vector< const CallGraphEdge * > &out) const
Map< const CallGraphEdge *, CallGraphEdge::CallInstSet > keptIndirectCalls
OrderedSet< const ICFGNode * > extendedKeptNodes
SlicedThreadCallGraphView(ThreadCallGraph *tcg, const OrderedSet< const FunObjVar * > &keptFunctions, const OrderedSet< const ICFGNode * > &extendedKeptNodes)
bool test(unsigned Idx) const
unsigned count() const
bool hasThreadJoinEdge(const CallICFGNode *cs) const
Get call graph edge via call instruction.
JoinEdgeSet::const_iterator getJoinEdgeEnd(const CallICFGNode *cs) const
ForkEdgeSet::const_iterator getForkEdgeEnd(const CallICFGNode *cs) const
ForkEdgeSet::const_iterator getForkEdgeBegin(const CallICFGNode *cs) const
bool hasThreadForkEdge(const CallICFGNode *cs) const
Get call graph edge via call instruction.
JoinEdgeSet::const_iterator getJoinEdgeBegin(const CallICFGNode *cs) const
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:67
std::string getNodeLabel(SlicedICFGNodeRef n, const SlicedICFGView *)
static std::string getNodeAttributes(SlicedICFGNodeRef n, const SlicedICFGView *)
static std::string getEdgeAttributes(SlicedICFGNodeRef, EdgeIter EI, const SlicedICFGView *)
static std::string getGraphName(const SlicedICFGView *)
static const void * getNodeIdentifier(SlicedICFGNodeRef n)
std::string getNodeLabel(SlicedPAGNodeRef n, const SlicedPAGView *)
static std::string getEdgeAttributes(SlicedPAGNodeRef, EdgeIter EI, const SlicedPAGView *)
static std::string getNodeAttributes(SlicedPAGNodeRef, const SlicedPAGView *)
static const void * getNodeIdentifier(SlicedPAGNodeRef n)
static std::string getGraphName(const SlicedPAGView *)
static const void * getNodeIdentifier(SlicedSVFGNodeRef n)
static std::string getNodeAttributes(SlicedSVFGNodeRef n, const SlicedSVFGView *)
static std::string getEdgeAttributes(SlicedSVFGNodeRef, EdgeIter EI, const SlicedSVFGView *)
std::string getNodeLabel(SlicedSVFGNodeRef n, const SlicedSVFGView *)
static std::string getGraphName(const SlicedSVFGView *)
static std::string getNodeAttributes(SlicedCallGraphNodeRef, const SlicedThreadCallGraphView *)
std::string getNodeLabel(SlicedCallGraphNodeRef n, const SlicedThreadCallGraphView *)
static const void * getNodeIdentifier(SlicedCallGraphNodeRef n)
static std::string getGraphName(const SlicedThreadCallGraphView *)
static std::string getEdgeAttributes(SlicedCallGraphNodeRef, EdgeIter EI, const SlicedThreadCallGraphView *)
const ICFGEdge * underlying