Static Value-Flow Analysis
Loading...
Searching...
No Matches
MTASlicer.cpp
Go to the documentation of this file.
1//===- MTASlicer.cpp -- Multi-stage on-demand program slicers -------------===//
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 * MTASlicer.cpp
25 *
26 * Author: Jiawei Yang
27 */
28
29#include "MTA/MTASlicer.h"
30#include "MTA/TCT.h"
31#include "SVFIR/SVFIR.h"
32#include "Util/SVFUtil.h"
33#include "Util/CxtStmt.h"
34#include "Util/ThreadAPI.h"
35#include <deque>
36#include <cassert>
37#include "Graphs/ICFGEdge.h"
38#include "Graphs/ICFGNode.h"
39#include "Graphs/CallGraph.h"
40#include "SVFIR/SVFStatements.h"
41#include "SVFIR/SVFVariables.h"
42#include <queue>
43#include "Graphs/SVFG.h"
44#include "Graphs/VFGNode.h"
45#include "Graphs/VFGEdge.h"
46
47using namespace SVF;
48
49namespace SVF
50{
51
52//===----------------------------------------------------------------------===//
53// SlicedTCT - TCT rebuilt over the sliced ThreadCallGraph view.
54//===----------------------------------------------------------------------===//
55
56std::unique_ptr<SlicedTCT> SlicedTCT::create(
58 u32_t contextLimit)
59{
60 std::unique_ptr<SlicedTCT> tct(
62 tct->build();
63 return tct;
64}
65
67 const SlicedSVFIRView& slicedView, u32_t contextLimit)
68 : TCT(&pointerAnalysis, contextLimit),
69 tcgView(*slicedView.getThreadCallGraph())
70{
71}
72
74{
78
79 for (const FunObjVar* entry : entryFuncSet)
80 {
81 if (!isCandidateFun(entry))
82 continue;
83 CallStrCxt context;
84 CxtThreadProc parent(-1, context, nullptr);
86 context, createDummyForkSite(), parent, entry);
87 pushToCTPWorkList(CxtThreadProc(root->getId(), context, entry));
88 }
89
90 while (!ctpList.empty())
91 {
93 CallGraphNode* node = tcg->getCallGraphNode(process.getProc());
94 if (!isCandidateFun(node->getFunction()) || !isKeptNode(node))
95 continue;
96
97 std::vector<const CallGraphEdge*> outEdges;
99 for (const CallGraphEdge* edge : outEdges)
100 {
101 std::vector<const CallICFGNode*> directCalls;
102 std::vector<const CallICFGNode*> indirectCalls;
103 tcgView.getDirectCallsOf(edge, directCalls);
104 tcgView.getIndirectCallsOf(edge, indirectCalls);
105 for (const CallICFGNode* call : directCalls)
107 for (const CallICFGNode* call : indirectCalls)
109 }
110 }
111
113
115 {
116 print();
117 dump("tct");
118 }
119}
120
122{
123 // Get kept fork sites from sliced view
124 std::vector<const ICFGNode*> keptForkSites;
126
127 for (const ICFGNode* forkSite : keptForkSites)
128 {
129 // Get function from fork site
130 const FunObjVar* svfun = forkSite->getFun();
132
133 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(forkSite);
134 std::vector<const CallGraphEdge*> forkEdges;
137 for (const CallGraphEdge* edge : forkEdges)
138 {
139 candidateFuncSet.insert(edge->getDstNode()->getFunction());
140 }
141 }
142
143 // Get kept join sites from sliced view
144 std::vector<const ICFGNode*> keptJoinSites;
146
147 for (const ICFGNode* joinSite : keptJoinSites)
148 {
149 const FunObjVar* svfun = joinSite->getFun();
151 }
152
153 if(getMakredProcs().empty())
154 SVFUtil::writeWrnMsg("We didn't recognize any fork site, this is single thread program?");
155}
156
158{
159 const CallGraphNode* start = tcg->getCallGraphNode(fun);
160 if (!isKeptNode(start))
161 return;
162
164 PTACGNodeSet visited;
165 worklist.push(start);
166 visited.insert(start);
167 while (!worklist.empty())
168 {
169 const CallGraphNode* node = worklist.pop();
170 candidateFuncSet.insert(node->getFunction());
171 std::vector<const CallGraphEdge*> inEdges;
173 for (const CallGraphEdge* edge : inEdges)
174 {
175 const CallGraphNode* caller = edge->getSrcNode();
176 if (visited.insert(caller).second)
177 worklist.push(caller);
178 }
179 }
180}
181
183{
184 // Get kept join sites from sliced view
185 std::vector<const ICFGNode*> keptJoinSites;
187
188 for(const ICFGNode* join : keptJoinSites)
189 {
190 const FunObjVar* svffun = join->getFun();
191 const SVFBasicBlock* svfbb = join->getBB();
192
193 if(svffun->hasLoopInfo(svfbb))
194 {
195 const LoopBBs& lp = svffun->getLoopInfo(svfbb);
196 if(!lp.empty() && isJoinMustExecutedInLoop(lp,join))
197 {
199 }
200 }
201
203 {
204 inRecurJoinSites.insert(join);
205 }
206 }
207}
208
210{
211 // A removed caller must not turn its callee into a new program root.
212 // Start only from original roots that remain in the sliced view.
214
215 for (const CallGraphNode* node : keptNodes)
216 {
217 const FunObjVar* fun = node->getFunction();
218 if (SVFUtil::isExtCall(fun))
219 continue;
220
221 if (!node->hasIncomingEdge())
222 {
223 entryFuncSet.insert(fun);
224 }
225 }
226
227 assert(!getEntryProcs().empty() && "Can't find any function in module!");
228}
229
231{
232 // Check if the call site and callee are kept in sliced view
233 if (!isKeptEdge(cgEdge))
234 return;
235
236 const CallGraphNode* dstNode = cgEdge->getDstNode();
237 if (!isKeptNode(dstNode))
238 return;
239
240 // Call base class implementation
242}
243
245{
246 return tcgView.isKeptNode(node);
247}
248
250{
251 return tcgView.isKeptEdge(edge);
252}
253
254void SlicedTCT::getKeptForkSites(std::vector<const ICFGNode*>& out) const
255{
256 out.clear();
257 // Get all fork sites from original ThreadCallGraph, but filter by:
258 // 1. The function containing the fork site is kept
259 // 2. There exists a kept fork edge from this fork site
260 for (ThreadCallGraph::CallSiteSet::const_iterator it = tcg->forksitesBegin(), eit = tcg->forksitesEnd(); it != eit; ++it)
261 {
262 const ICFGNode* forkSite = *it;
263 const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(forkSite);
264 if (callNode == nullptr)
265 continue;
266
267 std::vector<const CallGraphEdge*> forkEdges;
270 if (!forkEdges.empty())
271 out.push_back(forkSite);
272 }
273}
274
275void SlicedTCT::getKeptJoinSites(std::vector<const ICFGNode*>& out) const
276{
277 out.clear();
278 // Get all join sites from original ThreadCallGraph, but filter by:
279 // 1. The function containing the join site is kept
280 // 2. There exists a kept join edge to this join site
281 for (ThreadCallGraph::CallSiteSet::const_iterator it = tcg->joinsitesBegin(), eit = tcg->joinsitesEnd(); it != eit; ++it)
282 {
283 const ICFGNode* joinSite = *it;
284 const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(joinSite);
285 if (callNode == nullptr)
286 continue;
287
288 std::vector<const CallGraphEdge*> joinEdges;
291 if (!joinEdges.empty())
292 out.push_back(joinSite);
293 }
294}
295
296//===----------------------------------------------------------------------===//
297// MTASlicerBase
298//===----------------------------------------------------------------------===//
299
301 LockAnalysis* lockAnalysis, SVFG* svfg)
302 : svfir(svfir), pta(pta), mhp(mhp), lockAnalysis(lockAnalysis), svfg(svfg)
303{
305}
306
307// Helper: Get lock set for an ICFG node
309{
311
312 // Synchronization dependence is based on may-lock spans. Retain both the
313 // unconditional locks used to prove mutual exclusion and conditional locks
314 // whose spans can affect the sliced lock analysis' classification.
315 if (lockAnalysis->hasIntraLockSet(node))
316 {
318 for (const ICFGNode* lockSite : intraLocks)
319 {
320 allLockSites.insert(lockSite);
321 }
322 }
324 {
327 for (const ICFGNode* lockSite : conditionalLocks)
328 {
329 allLockSites.insert(lockSite);
330 }
331 }
332
333 // Get context-sensitive locks
335 {
337 for (const CxtStmt& cxtStmt : cxtStmts)
338 {
340 {
344 {
345 allLockSites.insert(cxtLock.getStmt());
346 }
347 }
348 }
349 }
350
351 return allLockSites;
352}
353
354// Helper: Get TCTNode set from ICFGNode
356 const ICFGNode* node)
357{
359
360 if (mhp->hasThreadStmtSet(node))
361 {
362 for (const CxtThreadStmt& cts : mhp->getThreadStmtSet(node))
363 {
364 if (mhp->getTCT()->hasGNode(cts.getTid()))
365 {
366 tctNodeSet.insert(mhp->getTCT()->getTCTNode(cts.getTid()));
367 }
368 }
369 }
370
371 return tctNodeSet;
372}
373
374// Helper: Get dependent thread-create sites for an ICFG source node.
376 const ICFGNode* node)
377{
381
382 TCT* tct = mhp->getTCT();
383 for (const TCTNode* tctNode : tctNodeSet)
384 {
386 dependentThreads.set(tctNode->getId());
387 for (NodeID tid : dependentThreads)
388 {
389 const ICFGNode* forkSite =
390 tct->getTCTNode(tid)->getCxtThread().getThread();
391 const CallICFGNode* forkCall =
392 SVFUtil::dyn_cast<CallICFGNode>(forkSite);
393 if (forkCall != nullptr && threadAPI->isTDFork(forkCall))
394 forkSites.insert(forkCall);
395 }
396 }
397
398 return forkSites;
399}
400
401// Data-dependence slice over the thread-aware SVFG (VFG_pre), at SVFG-node
402// granularity: the value-flow nodes reachable backward from the seeds. The
403// value-flow edges already capture direct (top-level), indirect (address-taken
404// / MemSSA), and thread-aware (interference) data dependence.
407{
408
409 assert(svfg != nullptr && "data-dependence slice requires the thread-aware VFG_pre");
410
412 std::deque<const SVFGNode*> worklist;
413
414 // Seed from the value-flow nodes of the given (e.g. race target) statements.
415 // VFG_pre is a pointer-only SVFG, so a load/store of a NON-pointer value (the
416 // usual case -- a race on an int/float field) has no statement node. For those
417 // we must still preserve the points-to of the dereferenced address pointer, or
418 // the sliced flow-sensitive solve sees an empty slice for it, computes empty
419 // points-to, and drops the race (a soundness bug). So additionally seed from the
420 // definition of each load/store's address pointer (always a pointer, hence
421 // always in the pointer-only SVFG); its backward closure keeps the pointer's
422 // def chain regardless of the value type.
423 for (const SVFStmt* stmt : seeds)
424 {
425 if (svfg->hasStmtVFGNode(stmt))
426 enqueueSVFGNode(svfg->getStmtVFGNode(stmt), visited, worklist);
427
428 NodeID addrPtr = 0;
429 if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
430 addrPtr = load->getRHSVarID();
431 else if (const StoreStmt* store = SVFUtil::dyn_cast<StoreStmt>(stmt))
432 addrPtr = store->getLHSVarID();
433 if (addrPtr != 0)
434 {
435 // getDefSVFGNode takes a ValVar (the address pointer is a top-level
436 // value variable).
437 const ValVar* ptrNode = SVFUtil::dyn_cast<ValVar>(svfir->getGNode(addrPtr));
438 if (ptrNode != nullptr && svfg->hasDefSVFGNode(ptrNode))
439 enqueueSVFGNode(svfg->getDefSVFGNode(ptrNode), visited, worklist);
440 }
441 }
442
443 // Backward over every value-flow edge.
444 while (!worklist.empty())
445 {
446 const SVFGNode* node = worklist.front();
447 worklist.pop_front();
448 for (const VFGEdge* edge : node->getInEdges())
449 enqueueSVFGNode(edge->getSrcNode(), visited, worklist);
450 }
451
452 return visited;
453}
454
456 const SVFGNode* node, OrderedSet<const SVFGNode*>& visited,
457 std::deque<const SVFGNode*>& worklist)
458{
459 if (node != nullptr && visited.insert(node).second)
460 worklist.push_back(node);
461}
462
463// Project retained VFG nodes (plus the seeds) onto their ICFG nodes.
467{
469 for (const SVFGNode* node : nodes)
470 if (const StmtVFGNode* statementNode =
471 SVFUtil::dyn_cast<StmtVFGNode>(node))
472 if (statementNode->getICFGNode() != nullptr)
473 result.insert(statementNode->getICFGNode());
474 for (const SVFStmt* stmt : seeds)
475 if (stmt != nullptr && stmt->getICFGNode() != nullptr)
476 result.insert(stmt->getICFGNode());
477 return result;
478}
479
480// Helper: Collect pthread-related statements (create and join)
483{
485
488
489 // Map pthread_create nodes to their corresponding pthread_join nodes
491
492 // First pass: collect all pthread_create nodes
493 for (const ICFGNode* sourceNode : sourceNodes)
494 {
497 for (const CallICFGNode* forkCallNode : forkSites)
498 {
501 }
502 }
503
504 // Second pass: find corresponding pthread_join nodes
505 ICFG* icfg = svfir->getICFG();
506 for (ICFG::iterator it = icfg->begin(), eit = icfg->end();
507 it != eit; ++it)
508 {
509 const ICFGNode* node = it->second;
510 const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node);
511 if (callNode != nullptr && threadAPI->isTDJoin(callNode))
512 {
513 const SVFVar* joinThread = threadAPI->getJoinedThread(callNode);
514 if (joinThread != nullptr)
515 {
517 {
518 const SVFVar* forkedThread = threadAPI->getForkedThread(createCallNode);
519 if (forkedThread != nullptr &&
520 threadAPI->isAliasedForkJoin(
522 {
524 }
525 }
526 }
527 }
528 }
529
530 return pthreadCallNodes;
531}
532
533// Helper: Collect mutex-related statements (lock and unlock)
536{
538
541
542 // Map mutex_lock nodes to their corresponding mutex_unlock nodes
544
545 // First pass: collect all mutex_lock nodes from lock sets
546 for (const ICFGNode* sourceNode : sourceNodes)
547 {
549 for (const ICFGNode* lockNode : lockSet)
550 {
552 SVFUtil::dyn_cast<CallICFGNode>(lockNode);
553 if (lockCallNode != nullptr &&
554 threadAPI->isTDAcquire(lockCallNode))
555 {
558 }
559 }
560 }
561
562 // Second pass: find corresponding mutex_unlock nodes
563 ICFG* icfg = svfir->getICFG();
564 for (ICFG::iterator it = icfg->begin(), eit = icfg->end();
565 it != eit; ++it)
566 {
567 const ICFGNode* node = it->second;
568 const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node);
569 if (callNode != nullptr && threadAPI->isTDRelease(callNode))
570 {
571 const SVFVar* unlockVar = threadAPI->getLockVal(callNode);
572 if (unlockVar != nullptr)
573 {
575 {
576 if (lockCallNode != nullptr)
577 {
578 const SVFVar* lockVar = threadAPI->getLockVal(lockCallNode);
579 if (lockVar != nullptr &&
580 pta->alias(unlockVar->getId(), lockVar->getId()))
581 {
582 mutexCallNodes.insert(callNode);
583 }
584 }
585 }
586 }
587 }
588 }
589
590 return mutexCallNodes;
591}
592
593// Helper: Collect common pthread and mutex statements (shared by PTA and MTA slicing)
594std::pair<OrderedSet<const CallICFGNode*>, OrderedSet<const CallICFGNode*>>
597{
598 // Step 1: Collect pthread-related statements, i.e., pthread_create and pthread_join
601
602 // Step 2: Collect mutex-related statements
605
606 return std::make_pair(pthreadCallNodes, mutexCallNodes);
607}
608
609// Keep the control-flow marker nodes the (sliced) lock analysis depends on:
610// every lock/unlock-bearing function's entry and exit nodes.
611//
612// LockAnalysis classifies an intra lock as *partial* (conditional) by reaching
613// the function entry node from the unlock along a lock-free backward path
614// (intraBackwardTraverse: `entryInst == I` -> return false), and bails the
615// forward span at the function exit node (`exitInst == I`). These checks are
616// node-identity tests against the entry/exit markers. The data-dependence slice
617// does not otherwise retain those markers, so on the sliced view the backward
618// walk can never match the entry node and the lock is mis-classified as total --
619// which makes isProtectedByCommonCILock report a spurious common lock and drops
620// a real race (a query-preservation violation). Bridging preserves reachability
621// *to* the kept markers, so once they are retained the sliced lock analysis
622// reproduces the whole-program classification. Markers used: entry block
623// front (cxt-lock start) and back (intra backward marker), and exit block back
624// (intra forward marker).
629{
631 {
632 sliceResult.insert(callNode);
633 if (callNode->getRetICFGNode() != nullptr)
634 sliceResult.insert(callNode->getRetICFGNode());
635 }
637 {
638 sliceResult.insert(callNode);
639 if (callNode->getRetICFGNode() != nullptr)
640 sliceResult.insert(callNode->getRetICFGNode());
641 }
642
644 {
645 const FunObjVar* fun = mutexCallNode->getFun();
646 if (fun == nullptr)
647 continue;
648 if (const SVFBasicBlock* entry = fun->getEntryBlock())
649 {
650 sliceResult.insert(entry->front());
651 sliceResult.insert(entry->back());
652 }
653 if (const SVFBasicBlock* exit = fun->getExitBB())
654 sliceResult.insert(exit->back());
655 }
656
659 {
660 if (!threadAPI->isTDJoin(callNode) || callNode->getBB() == nullptr)
661 continue;
662 std::vector<const SVFBasicBlock*> exitBlocks;
663 callNode->getFun()->getExitBlocksOfLoop(callNode->getBB(), exitBlocks);
664 for (const SVFBasicBlock* exitBlock : exitBlocks)
665 if (!exitBlock->getICFGNodeList().empty())
666 sliceResult.insert(exitBlock->front());
667 }
668}
669
670// Call-dependence expansion (used by MultiStageSlicer).
673{
674
675 // Determine keptFunctions from the given nodes
677 for (const ICFGNode* node : nodes)
678 {
679 if (node != nullptr && node->getFun() != nullptr)
680 {
681 keptFunctions.insert(node->getFun());
682 }
683 }
684
685 // Build ancestor closure (upward traversal in call graph)
686 std::queue<const FunObjVar*> functionWorklist;
687 for (const FunObjVar* fun : keptFunctions)
688 functionWorklist.push(fun);
689
691 for (auto it = callGraph->begin(), eit = callGraph->end();
692 it != eit; ++it)
693 {
694 const CallGraphNode* node = it->second;
695 if (node != nullptr && node->getFunction() != nullptr)
696 functionToNode[node->getFunction()] = node;
697 }
698
700 while (!functionWorklist.empty())
701 {
702 const FunObjVar* target = functionWorklist.front();
703 functionWorklist.pop();
704 const auto nodeIt = functionToNode.find(target);
705 if (nodeIt == functionToNode.end())
706 continue;
707
708 const CallGraphNode* node = nodeIt->second;
709 for (const CallGraphEdge* inEdge : node->getInEdges())
710 {
711 if (inEdge == nullptr)
712 continue;
713 const CallGraphNode* callerNode = inEdge->getSrcNode();
714 if (callerNode != nullptr && callerNode->getFunction() != nullptr)
715 {
718 {
719 keptFunctions.insert(callerFun);
722 }
723 }
724 }
725 }
726
727 // For each keptFunction, add call/ret nodes and entry/exit nodes
728 ICFG* icfg = svfir->getICFG();
730 for (const FunObjVar* fun : keptFunctions)
731 {
732 if (fun == nullptr)
733 continue;
734
735 // Add function entry/exit nodes
736 if (fun->hasBasicBlock())
737 {
738 if (FunEntryICFGNode* entry = icfg->getFunEntryICFGNode(fun))
739 expandedNodes.insert(entry);
740 if (FunExitICFGNode* exit = icfg->getFunExitICFGNode(fun))
741 expandedNodes.insert(exit);
742 }
743
744 // Find all call/ret nodes that call this function
745 const auto funNodeIt = functionToNode.find(fun);
746 if (funNodeIt != functionToNode.end())
747 {
748 const CallGraphNode* calleeNode = funNodeIt->second;
749
750 // Traverse all edges that call this function
751 for (const CallGraphEdge* inEdge : calleeNode->getInEdges())
752 {
753 if (inEdge == nullptr)
754 continue;
755
756 const CallGraphEdge::CallInstSet& directCalls =
757 inEdge->getDirectCalls();
758 const CallGraphEdge::CallInstSet& indirectCalls =
759 inEdge->getIndirectCalls();
760
761 for (const CallICFGNode* callNode : directCalls)
762 {
763 if (callNode != nullptr)
764 {
765 expandedNodes.insert(callNode);
766 const RetICFGNode* retNode = callNode->getRetICFGNode();
767 if (retNode != nullptr)
768 expandedNodes.insert(retNode);
769 }
770 }
771
772 for (const CallICFGNode* callNode : indirectCalls)
773 {
774 if (callNode != nullptr)
775 {
776 expandedNodes.insert(callNode);
777 const RetICFGNode* retNode = callNode->getRetICFGNode();
778 if (retNode != nullptr)
779 expandedNodes.insert(retNode);
780 }
781 }
782 }
783 }
784 }
785
786 return expandedNodes;
787}
788
789//===----------------------------------------------------------------------===//
790// MultiStageSlicer
791//===----------------------------------------------------------------------===//
792
794 LockAnalysis* lockAnalysis, SVFG* svfg)
795 : MTASlicerBase(svfir, pta, mhp, lockAnalysis, svfg)
796{
797}
798
799// Perform slicing for MTA (includes function expansion for IRView)
803{
804
805 // Step 1: Form the complete ILA source set first. MSli section 4.2 defines
806 // V_ILA as [INIT] union [THREAD-VF], then closes every source over its
807 // synchronization dependences. Keep this set at ICFG granularity: some
808 // THREAD-VF call/marker nodes have no attached SVF statement.
810 for (const SVFStmt* stmt : vulnerableStatements)
811 ilaSourceNodes.insert(stmt->getICFGNode());
812
813 // Step 2: synchronization-dependence closure of the complete source set.
817
818 // Form V_ILA_sync before function expansion: all [INIT] and [THREAD-VF]
819 // sources plus the synchronization primitives on which they depend.
823 for (const SVFStmt* stmt : vulnerableStatements)
824 {
825 initialSliceResult.insert(stmt->getICFGNode());
826 }
828
829 // Step 3: Expand keptNodes to include call/ret nodes and function entry/exit
830 // nodes (call dependence).
832
833 // Slicing invariant: no relevant synchronization primitive may be contracted
834 // into a bridge edge. Return nodes are retained because the sliced ICFG
835 // represents external synchronization calls as paired call/return nodes.
837 {
838 assert(finalSlice.count(callNode) && finalSlice.count(callNode->getRetICFGNode()) &&
839 "ILA slice dropped a fork/join synchronization dependence");
840 (void)callNode;
841 }
843 {
844 assert(finalSlice.count(callNode) && finalSlice.count(callNode->getRetICFGNode()) &&
845 "ILA slice dropped a lock/unlock synchronization dependence");
846 (void)callNode;
847 }
848 return finalSlice;
849}
850
851//===----------------------------------------------------------------------===//
852// MultiStageSlicer -- stage 2 (FSPTA data-dependence slice)
853//===----------------------------------------------------------------------===//
854
855// Candidate value-flow slice over VFG_pre. It is used only to select the
856// THREAD-VF queries and to scope the refined main overlay; it is not reused as
857// the final FSPTA slice.
868
870{
871 assert(preCandidateComputed && "pre-candidate slice has not been computed");
872 return preCandidateSlice;
873}
874
875// Final FSPTA data-dependence slice over the refined main value-flow graph.
887
888//===----------------------------------------------------------------------===//
889// SingleSlicer
890//===----------------------------------------------------------------------===//
891
893 LockAnalysis* lockAnalysis, SVFG* svfg)
894 : MTASlicerBase(svfir, pta, mhp, lockAnalysis, svfg)
895{
896}
897
898// Single-pass slice (the baseline of MSli §3/§5.4): the transitive closure of
899// the target statements under the COMBINED dependence graph -- synchronization,
900// data, and call dependence -- yielding one slice shared by ILA and FSPTA.
903{
904
906 for (const SVFStmt* stmt : vulnerableStatements)
907 if (stmt != nullptr && stmt->getICFGNode() != nullptr)
908 sourceNodes.insert(stmt->getICFGNode());
909
912
913 // Step 3: Close over data dependence (the thread-aware VFG_pre value flow --
914 // direct + indirect + interference, the same model the FSPTA stage uses) and call
915 // dependence (function expansion), alternately, until the node set converges.
916 while (true)
917 {
919
922 commonStmts.first, commonStmts.second, currentNodes);
923
925 for (const ICFGNode* node : currentNodes)
926 {
927 const ICFGNode::SVFStmtList& stmts = node->getSVFStmts();
928 currentStatements.insert(stmts.begin(), stmts.end());
929 }
930
935 currentNodes.insert(dataDepNodes.begin(), dataDepNodes.end());
936
938
940 break;
941 }
943 result.svfgNodes = std::move(dataSliceNodes);
944 result.icfgNodes = std::move(currentNodes);
945 return result;
946}
947
948} // End namespace SVF
AliasResult alias(const SVFVar *V1, const SVFVar *V2) override
Interface expose to users of our pointer analysis, given Value infos.
Set< const CallICFGNode * > CallInstSet
Definition CallGraph.h:55
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
const CallGraphNode * getCallGraphNode(const std::string &name) const
Get call graph node.
const ICFGNode * getThread() const
Return forksite.
Definition CxtStmt.h:209
bool push(const Data &data)
Definition WorkList.h:180
bool empty() const
Definition WorkList.h:161
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
const SVFBasicBlock * getEntryBlock() const
const SVFBasicBlock * front() const
const SVFBasicBlock * getExitBB() const
iterator begin()
Iterators.
bool hasGNode(NodeID id) const
Has a node.
NodeType * getGNode(NodeID id) const
Get a node.
const GEdgeSetTy & getInEdges() const
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
Set< CxtLock > CxtLockSet
bool hasIntraLockSet(const ICFGNode *stmt) const
Set< CxtStmt > CxtStmtSet
bool isInsideCondIntraLock(const ICFGNode *stmt) const
Return true if a statement is inside a partial lock/unlock pair (conditional lock with unconditional ...
const InstSet & getIntraLockSet(const ICFGNode *stmt) const
const CxtLockSet & getCxtLockFromCxtStmt(const CxtStmt &cts) const
bool hasCxtStmtFromInst(const ICFGNode *inst) const
Context-sensitive statement and lock spans.
Set< const ICFGNode * > InstSet
const CxtStmtSet & getCxtStmtsFromInst(const ICFGNode *inst) const
bool hasCxtLockFromCxtStmt(const CxtStmt &cts) const
const InstSet & getCondIntraLockSet(const ICFGNode *stmt) const
Definition MHP.h:52
ThreadCallGraph * getThreadCallGraph() const
Get ThreadCallGraph.
Definition MHP.h:104
const CxtThreadStmtSet & getThreadStmtSet(const ICFGNode *inst) const
Get/has ThreadStmt.
Definition MHP.h:142
bool hasThreadStmtSet(const ICFGNode *inst) const
Definition MHP.h:148
TCT * getTCT() const
Get Thread Creation Tree.
Definition MHP.h:110
OrderedSet< const CallICFGNode * > collectMutexStatements(const OrderedSet< const ICFGNode * > &sourceNodes)
std::pair< OrderedSet< const CallICFGNode * >, OrderedSet< const CallICFGNode * > > collectCommonThreadStatements(const OrderedSet< const ICFGNode * > &sourceNodes)
OrderedSet< const CallICFGNode * > collectPthreadStatements(const OrderedSet< const ICFGNode * > &sourceNodes)
OrderedSet< const VFGNode * > computeDataDependenceSVFGNodes(const OrderedSet< const SVFStmt * > &seeds, SVFG *svfg)
OrderedSet< const ICFGNode * > expandCallDependence(const OrderedSet< const ICFGNode * > &nodes)
AndersenBase * pta
Definition MTASlicer.h:129
OrderedSet< const ICFGNode * > getLockSet(const ICFGNode *node)
OrderedSet< const TCTNode * > getTCTNodeSetFromNode(const ICFGNode *node)
LockAnalysis * lockAnalysis
Definition MTASlicer.h:131
OrderedSet< const ICFGNode * > svfgNodesToICFGNodes(const OrderedSet< const VFGNode * > &nodes, const OrderedSet< const SVFStmt * > &seeds)
Project the retained VFG nodes (plus the seeds) onto their ICFG nodes.
static void enqueueSVFGNode(const SVFGNode *node, OrderedSet< const SVFGNode * > &visited, std::deque< const SVFGNode * > &worklist)
CallGraph * callGraph
Definition MTASlicer.h:132
MTASlicerBase(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, SVFG *svfg=nullptr)
SVFG * svfg
thread-aware VFG_pre (PTA/Single slicers; null for MTA)
Definition MTASlicer.h:133
void addSynchronizationDependencies(const OrderedSet< const CallICFGNode * > &pthreadCallNodes, const OrderedSet< const CallICFGNode * > &mutexCallNodes, OrderedSet< const ICFGNode * > &retainedNodes)
OrderedSet< const CallICFGNode * > getDependentThreadCreate(const ICFGNode *node)
ValueFlowSlice preCandidateSlice
Definition MTASlicer.h:238
MultiStageSlicer(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, SVFG *svfg=nullptr)
OrderedSet< const ICFGNode * > runILASlicing(const OrderedSet< const SVFStmt * > &vulnerableStatements, const OrderedSet< const ICFGNode * > &threadVFSources={})
const ValueFlowSlice & getPreCandidateSlice() const
Return the pre-candidate slice after computePreCandidateSlice().
void computePreCandidateSlice(const OrderedSet< const SVFStmt * > &vulnerableStatements)
ValueFlowSlice runPTASlicing(const OrderedSet< const SVFStmt * > &vulnerableStatements, SVFG *refinedMainVFG)
static const Option< bool > TCTDotGraph
Definition Options.h:159
CallGraph * getCallGraph() const
Return call graph.
bool hasDefSVFGNode(const ValVar *valVar) const
Given a valVar, return whether it has definition site.
Definition SVFG.h:177
const SVFGNode * getDefSVFGNode(const ValVar *valVar) const
Given a valVar, return its definition site.
Definition SVFG.h:171
ICFG * getICFG() const
Definition SVFIR.h:231
NodeID getId() const
Get ID.
Definition SVFValue.h:158
SingleSlicer(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, SVFG *svfg=nullptr)
ValueFlowSlice runSlicing(const OrderedSet< const SVFStmt * > &vulnerableStatements)
void getKeptForkSites(std::vector< const ICFGNode * > &out) const
void collectEntryFunInCallGraph() override
Get entry functions that are neither called by other functions nor extern functions.
void collectLoopInfoForJoin() override
Handle join site in loop.
void handleCallRelation(CxtThreadProc &ctp, const CallGraphEdge *cgEdge, const CallICFGNode *cs) override
Handle call relations.
bool isKeptEdge(const CallGraphEdge *edge) const
void getKeptJoinSites(std::vector< const ICFGNode * > &out) const
bool isKeptNode(const CallGraphNode *node) const
const SlicedThreadCallGraphView & tcgView
Definition MTASlicer.h:107
static std::unique_ptr< SlicedTCT > create(PointerAnalysis &pointerAnalysis, const SlicedSVFIRView &slicedView, u32_t contextLimit)
Definition MTASlicer.cpp:56
void build() override
Build TCT.
Definition MTASlicer.cpp:73
void markRelProcs() override
Mark relevant procedures that are backward reachable from any fork/join site.
SlicedTCT(PointerAnalysis &pointerAnalysis, const SlicedSVFIRView &slicedView, u32_t contextLimit)
Definition MTASlicer.cpp:66
const OrderedSet< const CallGraphNode * > & getKeptNodes() const
Get all kept nodes.
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 getIndirectCallsOf(const CallGraphEdge *edge, std::vector< const CallICFGNode * > &out) const
bool isKeptEdge(const CallGraphEdge *e) 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)
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 set(unsigned Idx)
const CxtThread & getCxtThread() const
Get thread creation context, <fork site, call string context>
Definition TCT.h:103
bool pushToCTPWorkList(const CxtThreadProc &ctp)
WorkList helper functions.
Definition TCT.h:595
const FunSet & getMakredProcs() const
Get marked candidate functions.
Definition TCT.h:239
const NodeBS getAncestorThreads(NodeID tid) const
Get all ancestor threads.
Definition TCT.h:336
bool isInRecursion(const ICFGNode *inst) const
Whether an instruction is in a recursion.
Definition TCT.cpp:123
TCTNode * getTCTNode(NodeID id) const
Get TCT node.
Definition TCT.h:209
FunSet entryFuncSet
Definition TCT.h:615
TCTNode * getOrCreateTCTNode(const CallStrCxt &cxt, const ICFGNode *fork, const CxtThreadProc &forkSiteCtp, const FunObjVar *routine)
Get or create a tct node based on CxtThread.
Definition TCT.h:528
Set< const CallGraphNode * > PTACGNodeSet
Definition TCT.h:176
ICFGNode * createDummyForkSite()
Create and get a new dummy fork site for starter routines.
Definition TCT.h:586
InstToLoopMap joinSiteToLoopMap
Map a CxtThread to its start routine function.
Definition TCT.h:623
void dump(const std::string &filename)
Dump the graph.
Definition TCT.cpp:569
FunSet candidateFuncSet
Procedures that are neither called by other functions nor extern functions.
Definition TCT.h:616
bool isCandidateFun(const CallGraph::FunctionSet &callees) const
Whether it is a candidate function for indirect call.
Definition TCT.h:294
CxtThreadProcVec ctpList
Thread call graph SCC.
Definition TCT.h:618
const u32_t contextLimit
Definition TCT.h:459
bool isJoinMustExecutedInLoop(const LoopBBs &lp, const ICFGNode *join)
Return true if a join instruction must be executed inside a loop.
Definition TCT.cpp:326
Set< const ICFGNode * > inRecurJoinSites
Fork or Join sites in recursions.
Definition TCT.h:624
const FunSet & getEntryProcs() const
Get marked candidate functions.
Definition TCT.h:245
void print() const
Print TCT information.
Definition TCT.cpp:577
virtual void handleCallRelation(CxtThreadProc &ctp, const CallGraphEdge *cgEdge, const CallICFGNode *call)
Handle call relations.
Definition TCT.cpp:277
ThreadCallGraph * tcg
Definition TCT.h:457
void collectMultiForkedThreads()
Definition TCT.cpp:239
CxtThreadProc popFromCTPWorkList()
Definition TCT.h:604
SVFLoopAndDomInfo::LoopBBs LoopBBs
Definition TCT.h:159
CallSiteSet::const_iterator forksitesEnd() const
CallSiteSet::const_iterator forksitesBegin() const
Fork sites iterators.
CallSiteSet::const_iterator joinsitesEnd() const
CallSiteSet::const_iterator joinsitesBegin() const
Join sites iterators.
ThreadAPI * getThreadAPI() const
Thread API.
bool hasStmtVFGNode(const SVFStmt *svfStmt) const
Existence checks for VFGNodes.
Definition VFG.h:217
StmtVFGNode * getStmtVFGNode(const SVFStmt *svfStmt) const
Get an VFGNode.
Definition VFG.h:261
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:441
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition SVFUtil.cpp:72
for isBitcode
Definition BasicTypes.h:70
u32_t NodeID
Definition GeneralType.h:76
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
iter_range< typename GenericGraphTraits< GraphType >::nodes_iterator > nodes(const GraphType &G)
std::vector< u32_t > CallStrCxt
Definition GeneralType.h:96
unsigned u32_t
Definition GeneralType.h:67
OrderedSet< const SVFGNode * > svfgNodes
Definition MTASlicer.h:61
OrderedSet< const ICFGNode * > icfgNodes
Definition MTASlicer.h:62