60 std::unique_ptr<SlicedTCT> tct(
97 std::vector<const CallGraphEdge*> outEdges;
98 tcgView.getOutEdgesOf(node, outEdges);
101 std::vector<const CallICFGNode*> directCalls;
102 std::vector<const CallICFGNode*> indirectCalls;
103 tcgView.getDirectCallsOf(edge, directCalls);
104 tcgView.getIndirectCallsOf(edge, indirectCalls);
124 std::vector<const ICFGNode*> keptForkSites;
127 for (
const ICFGNode* forkSite : keptForkSites)
130 const FunObjVar* svfun = forkSite->getFun();
134 std::vector<const CallGraphEdge*> forkEdges;
136 &
tcgView, callNode, forkEdges);
144 std::vector<const ICFGNode*> keptJoinSites;
147 for (
const ICFGNode* joinSite : keptJoinSites)
149 const FunObjVar* svfun = joinSite->getFun();
165 worklist.
push(start);
166 visited.insert(start);
167 while (!worklist.
empty())
171 std::vector<const CallGraphEdge*> inEdges;
172 tcgView.getInEdgesOf(node, inEdges);
176 if (visited.insert(caller).second)
177 worklist.
push(caller);
185 std::vector<const ICFGNode*> keptJoinSites;
188 for(
const ICFGNode* join : keptJoinSites)
190 const FunObjVar* svffun = join->getFun();
221 if (!node->hasIncomingEdge())
227 assert(!
getEntryProcs().empty() &&
"Can't find any function in module!");
246 return tcgView.isKeptNode(node);
251 return tcgView.isKeptEdge(edge);
260 for (ThreadCallGraph::CallSiteSet::const_iterator it =
tcg->forksitesBegin(), eit =
tcg->forksitesEnd(); it != eit; ++it)
264 if (callNode ==
nullptr)
267 std::vector<const CallGraphEdge*> forkEdges;
269 &
tcgView, callNode, forkEdges);
270 if (!forkEdges.empty())
271 out.push_back(forkSite);
281 for (ThreadCallGraph::CallSiteSet::const_iterator it =
tcg->joinsitesBegin(), eit =
tcg->joinsitesEnd(); it != eit; ++it)
285 if (callNode ==
nullptr)
288 std::vector<const CallGraphEdge*> joinEdges;
290 &
tcgView, callNode, joinEdges);
291 if (!joinEdges.empty())
292 out.push_back(joinSite);
318 for (
const ICFGNode* lockSite : intraLocks)
320 allLockSites.insert(lockSite);
327 for (
const ICFGNode* lockSite : conditionalLocks)
329 allLockSites.insert(lockSite);
337 for (
const CxtStmt& cxtStmt : cxtStmts)
345 allLockSites.insert(cxtLock.getStmt());
360 if (
mhp->hasThreadStmtSet(node))
364 if (
mhp->getTCT()->hasGNode(cts.getTid()))
366 tctNodeSet.insert(
mhp->getTCT()->getTCTNode(cts.getTid()));
380 ThreadAPI* threadAPI =
mhp->getThreadCallGraph()->getThreadAPI();
383 for (
const TCTNode* tctNode : tctNodeSet)
386 dependentThreads.
set(tctNode->getId());
387 for (
NodeID tid : dependentThreads)
393 if (forkCall !=
nullptr && threadAPI->
isTDFork(forkCall))
394 forkSites.insert(forkCall);
409 assert(
svfg !=
nullptr &&
"data-dependence slice requires the thread-aware VFG_pre");
412 std::deque<const SVFGNode*> worklist;
423 for (
const SVFStmt* stmt : seeds)
425 if (
svfg->hasStmtVFGNode(stmt))
430 addrPtr = load->getRHSVarID();
432 addrPtr = store->getLHSVarID();
438 if (ptrNode !=
nullptr &&
svfg->hasDefSVFGNode(ptrNode))
444 while (!worklist.empty())
446 const SVFGNode* node = worklist.front();
447 worklist.pop_front();
457 std::deque<const SVFGNode*>& worklist)
459 if (node !=
nullptr && visited.insert(node).second)
460 worklist.push_back(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());
493 for (
const ICFGNode* sourceNode : sourceNodes)
499 pthreadCallNodes.insert(forkCallNode);
500 pthreadCreateNodes.insert(forkCallNode);
511 if (callNode !=
nullptr && threadAPI->
isTDJoin(callNode))
514 if (joinThread !=
nullptr)
516 for (
const CallICFGNode* createCallNode : pthreadCreateNodes)
519 if (forkedThread !=
nullptr &&
521 pta, forkedThread, joinThread))
523 pthreadCallNodes.insert(callNode);
530 return pthreadCallNodes;
546 for (
const ICFGNode* sourceNode : sourceNodes)
549 for (
const ICFGNode* lockNode : lockSet)
553 if (lockCallNode !=
nullptr &&
556 mutexCallNodes.insert(lockCallNode);
557 mutexLockCallNodes.insert(lockCallNode);
569 if (callNode !=
nullptr && threadAPI->
isTDRelease(callNode))
572 if (unlockVar !=
nullptr)
574 for (
const CallICFGNode* lockCallNode : mutexLockCallNodes)
576 if (lockCallNode !=
nullptr)
579 if (lockVar !=
nullptr &&
582 mutexCallNodes.insert(callNode);
590 return mutexCallNodes;
606 return std::make_pair(pthreadCallNodes, mutexCallNodes);
632 sliceResult.insert(callNode);
633 if (callNode->getRetICFGNode() !=
nullptr)
634 sliceResult.insert(callNode->getRetICFGNode());
638 sliceResult.insert(callNode);
639 if (callNode->getRetICFGNode() !=
nullptr)
640 sliceResult.insert(callNode->getRetICFGNode());
643 for (
const CallICFGNode* mutexCallNode : mutexCallNodes)
645 const FunObjVar* fun = mutexCallNode->getFun();
650 sliceResult.insert(entry->front());
651 sliceResult.insert(entry->back());
654 sliceResult.insert(exit->back());
657 ThreadAPI* threadAPI =
mhp->getThreadCallGraph()->getThreadAPI();
660 if (!threadAPI->
isTDJoin(callNode) || callNode->getBB() ==
nullptr)
662 std::vector<const SVFBasicBlock*> exitBlocks;
663 callNode->getFun()->getExitBlocksOfLoop(callNode->getBB(), exitBlocks);
665 if (!exitBlock->getICFGNodeList().empty())
666 sliceResult.insert(exitBlock->front());
679 if (node !=
nullptr && node->getFun() !=
nullptr)
681 keptFunctions.insert(node->getFun());
686 std::queue<const FunObjVar*> functionWorklist;
687 for (
const FunObjVar* fun : keptFunctions)
688 functionWorklist.push(fun);
695 if (node !=
nullptr && node->
getFunction() !=
nullptr)
700 while (!functionWorklist.empty())
703 functionWorklist.pop();
704 const auto nodeIt = functionToNode.find(target);
705 if (nodeIt == functionToNode.end())
711 if (inEdge ==
nullptr)
714 if (callerNode !=
nullptr && callerNode->
getFunction() !=
nullptr)
717 if (visitedFunctions.find(callerFun) == visitedFunctions.end())
719 keptFunctions.insert(callerFun);
720 visitedFunctions.insert(callerFun);
721 functionWorklist.push(callerFun);
730 for (
const FunObjVar* fun : keptFunctions)
736 if (fun->hasBasicBlock())
739 expandedNodes.insert(entry);
741 expandedNodes.insert(exit);
745 const auto funNodeIt = functionToNode.find(fun);
746 if (funNodeIt != functionToNode.end())
753 if (inEdge ==
nullptr)
757 inEdge->getDirectCalls();
759 inEdge->getIndirectCalls();
763 if (callNode !=
nullptr)
765 expandedNodes.insert(callNode);
766 const RetICFGNode* retNode = callNode->getRetICFGNode();
767 if (retNode !=
nullptr)
768 expandedNodes.insert(retNode);
774 if (callNode !=
nullptr)
776 expandedNodes.insert(callNode);
777 const RetICFGNode* retNode = callNode->getRetICFGNode();
778 if (retNode !=
nullptr)
779 expandedNodes.insert(retNode);
786 return expandedNodes;
810 for (
const SVFStmt* stmt : vulnerableStatements)
811 ilaSourceNodes.insert(stmt->getICFGNode());
822 pthreadCallNodes, mutexCallNodes, initialSliceResult);
823 for (
const SVFStmt* stmt : vulnerableStatements)
825 initialSliceResult.insert(stmt->getICFGNode());
827 initialSliceResult.insert(threadVFSources.begin(), threadVFSources.end());
838 assert(finalSlice.count(callNode) && finalSlice.count(callNode->getRetICFGNode()) &&
839 "ILA slice dropped a fork/join synchronization dependence");
844 assert(finalSlice.count(callNode) && finalSlice.count(callNode->getRetICFGNode()) &&
845 "ILA slice dropped a lock/unlock synchronization dependence");
878 SVFG* refinedMainVFG)
906 for (
const SVFStmt* stmt : vulnerableStatements)
907 if (stmt !=
nullptr && stmt->getICFGNode() !=
nullptr)
908 sourceNodes.insert(stmt->getICFGNode());
922 commonStmts.first, commonStmts.second, currentNodes);
925 for (
const ICFGNode* node : currentNodes)
928 currentStatements.insert(stmts.begin(), stmts.end());
935 currentNodes.insert(dataDepNodes.begin(), dataDepNodes.end());
939 if (currentNodes == previousNodes)
943 result.
svfgNodes = std::move(dataSliceNodes);
944 result.
icfgNodes = std::move(currentNodes);
Set< const CallICFGNode * > CallInstSet
const FunObjVar * getFunction() const
Get function of this call node.
const FunObjVar * getProc() const
Return current procedure.
const ICFGNode * getThread() const
Return forksite.
bool push(const Data &data)
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
const LoopBBs & getLoopInfo(const SVFBasicBlock *bb) const
const SVFBasicBlock * getEntryBlock() const
const SVFBasicBlock * front() const
const SVFBasicBlock * getExitBB() const
bool hasLoopInfo(const SVFBasicBlock *bb) const
NodeType * getDstNode() const
iterator begin()
Iterators.
const GEdgeSetTy & getInEdges() const
std::list< const SVFStmt * > SVFStmtList
ICFGNodeIDToNodeMapTy::iterator iterator
FunExitICFGNode * getFunExitICFGNode(const FunObjVar *fun)
Add a function exit node.
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Set< CxtLock > CxtLockSet
Set< CxtStmt > CxtStmtSet
Set< const ICFGNode * > InstSet
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)
OrderedSet< const ICFGNode * > getLockSet(const ICFGNode *node)
OrderedSet< const TCTNode * > getTCTNodeSetFromNode(const ICFGNode *node)
LockAnalysis * lockAnalysis
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)
MTASlicerBase(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, SVFG *svfg=nullptr)
SVFG * svfg
thread-aware VFG_pre (PTA/Single slicers; null for MTA)
void addSynchronizationDependencies(const OrderedSet< const CallICFGNode * > &pthreadCallNodes, const OrderedSet< const CallICFGNode * > &mutexCallNodes, OrderedSet< const ICFGNode * > &retainedNodes)
OrderedSet< const CallICFGNode * > getDependentThreadCreate(const ICFGNode *node)
bool preCandidateComputed
ValueFlowSlice preCandidateSlice
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
NodeID getId() const
Get ID.
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
static std::unique_ptr< SlicedTCT > create(PointerAnalysis &pointerAnalysis, const SlicedSVFIRView &slicedView, u32_t contextLimit)
void build() override
Build TCT.
void markRelProcs() override
Mark relevant procedures that are backward reachable from any fork/join site.
SlicedTCT(PointerAnalysis &pointerAnalysis, const SlicedSVFIRView &slicedView, u32_t contextLimit)
const CxtThread & getCxtThread() const
Get thread creation context, <fork site, call string context>.
bool pushToCTPWorkList(const CxtThreadProc &ctp)
WorkList helper functions.
const FunSet & getMakredProcs() const
Get marked candidate functions.
const NodeBS getAncestorThreads(NodeID tid) const
Get all ancestor threads.
bool isInRecursion(const ICFGNode *inst) const
Whether an instruction is in a recursion.
TCTNode * getTCTNode(NodeID id) const
Get TCT node.
TCTNode * getOrCreateTCTNode(const CallStrCxt &cxt, const ICFGNode *fork, const CxtThreadProc &forkSiteCtp, const FunObjVar *routine)
Get or create a tct node based on CxtThread.
Set< const CallGraphNode * > PTACGNodeSet
ICFGNode * createDummyForkSite()
Create and get a new dummy fork site for starter routines.
ThreadCallGraph * getThreadCallGraph() const
Get TCG.
InstToLoopMap joinSiteToLoopMap
Map a CxtThread to its start routine function.
void dump(const std::string &filename)
Dump the graph.
FunSet candidateFuncSet
Procedures that are neither called by other functions nor extern functions.
bool isCandidateFun(const CallGraph::FunctionSet &callees) const
Whether it is a candidate function for indirect call.
CxtThreadProcVec ctpList
Thread call graph SCC.
bool isJoinMustExecutedInLoop(const LoopBBs &lp, const ICFGNode *join)
Return true if a join instruction must be executed inside a loop.
Set< const ICFGNode * > inRecurJoinSites
Fork or Join sites in recursions.
TCT(PointerAnalysis *p, u32_t contextLimit)
const FunSet & getEntryProcs() const
Get marked candidate functions.
void print() const
Print TCT information.
virtual void handleCallRelation(CxtThreadProc &ctp, const CallGraphEdge *cgEdge, const CallICFGNode *call)
Handle call relations.
void collectMultiForkedThreads()
CxtThreadProc popFromCTPWorkList()
SVFLoopAndDomInfo::LoopBBs LoopBBs
bool isTDFork(const CallICFGNode *inst) const
Return true if this call create a new thread.
const ValVar * getForkedThread(const CallICFGNode *inst) const
Return arguments/attributes of pthread_create / hare_parallel_for.
bool isTDJoin(const CallICFGNode *inst) const
Return true if this call wait for a worker thread.
bool isTDRelease(const CallICFGNode *inst) const
Return true if this call release a lock.
const SVFVar * getLockVal(const ICFGNode *inst) const
Return lock value.
const SVFVar * getJoinedThread(const CallICFGNode *inst) const
Return arguments/attributes of pthread_join.
bool isAliasedForkJoin(PointerAnalysis *pta, const SVFVar *forkArg, const SVFVar *joinArg) const
bool isTDAcquire(const CallICFGNode *inst) const
Return true if this call acquire a lock.
ThreadAPI * getThreadAPI() const
Thread API.
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
bool isExtCall(const FunObjVar *fun)
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
std::set< Key, Compare, Allocator > OrderedSet
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
iter_range< typename GenericGraphTraits< GraphType >::nodes_iterator > nodes(const GraphType &G)
std::vector< u32_t > CallStrCxt
OrderedSet< const SVFGNode * > svfgNodes
OrderedSet< const ICFGNode * > icfgNodes