Static Value-Flow Analysis
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Protected Member Functions | Private Member Functions | Private Attributes | List of all members
SVF::MTASVFGBuilder Class Reference

#include <MTASVFGBuilder.h>

Inheritance diagram for SVF::MTASVFGBuilder:
SVF::SVFGBuilder

Classes

class  ThreadVFBuildConfig
 
struct  ThreadVFCandidate
 

Public Types

enum class  InterferenceEdgeMode { Analysis , SlicingOnly }
 
typedef Set< const StmtSVFGNode * > SVFGNodeSet
 
typedef NodeBS SVFGNodeIDSet
 
typedef std::pair< const StmtSVFGNode *, const StmtSVFGNode * > ThreadVFEdge
 
using ThreadVFQueryMap = Map< ThreadVFEdge, Set< const ICFGNode * > >
 
using ThreadVFCandidateList = std::vector< ThreadVFCandidate >
 
- Public Types inherited from SVF::SVFGBuilder
typedef PointerAnalysis::CallSiteSet CallSiteSet
 
typedef PointerAnalysis::CallEdgeMap CallEdgeMap
 
typedef PointerAnalysis::FunctionSet FunctionSet
 
typedef SVFG::SVFGEdgeSetTy SVFGEdgeSet
 

Public Member Functions

 MTASVFGBuilder (MHP *mhp, LockAnalysis *lockAnalysis, InterferenceEdgeMode edgeMode=InterferenceEdgeMode::Analysis)
 Constructor: driven by the interleaving (MHP) and lock analyses.
 
 ~MTASVFGBuilder () override=default
 
const ThreadVFQueryMapgetThreadVFQueryMap () const
 
void replaceThreadAwareOverlay (MHP *mhp, LockAnalysis *lockAnalysis, const ThreadVFBuildConfig &config)
 
void clearThreadAwareOverlay ()
 Remove all currently attached thread-aware interference edges.
 
size_t getThreadAwareEdgeCount () const
 
- Public Member Functions inherited from SVF::SVFGBuilder
 SVFGBuilder (bool _SVFGWithIndCall=Options::SVFGWithIndirectCall(), bool _SVFGWithPostOpts=Options::OPTSVFG())
 Constructor.
 
virtual ~SVFGBuilder ()=default
 Destructor.
 
SVFGbuildPTROnlySVFG (BVDataPTAImpl *pta)
 
SVFGbuildFullSVFG (BVDataPTAImpl *pta)
 
SVFGgetSVFG () const
 Get SVFG instance.
 
void markValidVFEdge (SVFGEdgeSet &edges)
 Mark feasible VF edge by removing it from set vfEdgesAtIndCallSite.
 
bool isSpuriousVFEdgeAtIndCallSite (const SVFGEdge *edge)
 Return true if this is an VF Edge pre-connected by Andersen's analysis.
 
virtual std::unique_ptr< MemSSAbuildMSSA (BVDataPTAImpl *pta, bool ptrOnlyMSSA)
 Build Memory SSA.
 

Protected Member Functions

void buildSVFG () override
 Rewrite the SVFG build hook: build the stock SVFG, then add MHP edges.
 
std::unique_ptr< MRGeneratorcreateMRGenerator (BVDataPTAImpl *pta, bool ptrOnlyMSSA) override
 
- Protected Member Functions inherited from SVF::SVFGBuilder
SVFGbuild (BVDataPTAImpl *pta, VFG::VFGK kind)
 Create a DDA SVFG. By default actualOut and FormalIN are removed, unless withAOFI is set true.
 
virtual void releaseMemory ()
 Release global SVFG.
 

Private Member Functions

void collectLoadStoreSVFGNodes ()
 
bool isInOverlayScope (const SVFGNode *node) const
 
void connectThreadJoinEdges ()
 
void addJoinRetEdge (const FormalOUTSVFGNode *formalOut, const ActualOUTSVFGNode *actualOut, CallSiteID callSiteId)
 
void connectMHPEdges (PointerAnalysis *pta)
 Connect inter-thread (interference) value-flow edges for MHP pairs.
 
void handleStoreLoad (const StmtSVFGNode *store, const StmtSVFGNode *load, PointerAnalysis *pta)
 
void handleStoreStore (const StmtSVFGNode *firstStore, const StmtSVFGNode *secondStore, PointerAnalysis *pta)
 
void recordThreadVFSource (const StmtSVFGNode *source, const StmtSVFGNode *destination, bool commonLock)
 
SVFGEdgeaddTDEdge (NodeID srcId, NodeID dstId, const PointsTo &pts)
 Add a thread-MHP indirect value-flow edge srcId -> dstId carrying pts.
 
SVFGNodeIDSet getPredecessorNodes (const StmtSVFGNode *node)
 Lock-span head/tail tests (non-interference lock-pair pruning).
 
SVFGNodeIDSet getSuccessorNodes (const StmtSVFGNode *node)
 
bool isHeadOfSpan (const StmtSVFGNode *node)
 
bool isTailOfSpan (const StmtSVFGNode *node)
 

Private Attributes

const SlicedSVFGViewoverlayScope = nullptr
 Active overlay configuration; defaults suit VFG_pre.
 
const ThreadVFCandidateListoverlayCandidates = nullptr
 
bool recordThreadVFQueries = true
 false = skip [THREAD-VF] recording
 
bool labelInterferenceEdges = true
 false = VFG_pre (sliced-only): omit edge points-to labels
 
SVFGNodeSet storeNodes
 
SVFGNodeSet loadNodes
 
ThreadVFQueryMap threadVFQueryMap
 [THREAD-VF] per-edge query map (see getThreadVFQueryMap).
 
MHPmhp
 
LockAnalysislockAnalysis
 
Map< const StmtSVFGNode *, SVFGNodeIDSetpredecessorCache
 
Map< const StmtSVFGNode *, SVFGNodeIDSetsuccessorCache
 
Map< const StmtSVFGNode *, boolspanHeadCache
 
Map< const StmtSVFGNode *, boolspanTailCache
 
SVFGEdgeSet threadAwareEdges
 

Additional Inherited Members

- Protected Attributes inherited from SVF::SVFGBuilder
SVFGEdgeSet vfEdgesAtIndCallSite
 SVFG Edges connected at indirect call/ret sites.
 
std::unique_ptr< SVFGsvfg
 
bool SVFGWithIndCall
 SVFG with precomputed indirect call edges.
 
bool SVFGWithPostOpts
 Build optimised version of SVFG.
 

Detailed Description

Definition at line 46 of file MTASVFGBuilder.h.

Member Typedef Documentation

◆ SVFGNodeIDSet

Definition at line 50 of file MTASVFGBuilder.h.

◆ SVFGNodeSet

Definition at line 49 of file MTASVFGBuilder.h.

◆ ThreadVFCandidateList

Definition at line 116 of file MTASVFGBuilder.h.

◆ ThreadVFEdge

A candidate thread-aware value-flow edge s –o--> s' (src store, dst load/store), keyed by its endpoint SVFG nodes.

Definition at line 70 of file MTASVFGBuilder.h.

◆ ThreadVFQueryMap

[THREAD-VF] per-edge query map (MSli §4.2, Fig. 6 rule [THREAD-VF]).

While building VFG_pre we record, for every candidate thread-aware value-flow edge (s,s') the construction evaluates, its Query(s –o--> s') set: the endpoints {s,s'} plus — under a common lock — the in-span witnesses Succ_spl(s) / Pred_spl'(s') that decide TL/HD membership, i.e. whether the edge survives the non-interference test (Def. 2). The query is kept per edge (not pre-unioned) so ILA slicing can restrict the sources to the edges that survive the FSPTA slice — ThreadVF(VFG'_pre) — rather than every candidate pair. Feeding the retained edges' queries into ILA slicing makes the sliced MHP/lock reproduce the same value-flow decisions the main phase makes, while keeping the slice minimal.

The value stores only the additional lock-span witnesses; the endpoint ICFG nodes are implicit in the key and consumers must add them back.

Definition at line 87 of file MTASVFGBuilder.h.

Member Enumeration Documentation

◆ InterferenceEdgeMode

Enumerator
Analysis 

Build labelled edges for FSMPTA.

SlicingOnly 

Build unlabelled connectivity for VFG_pre slicing.

Definition at line 52 of file MTASVFGBuilder.h.

53 {
54 Analysis,
56 };
@ Analysis
Build labelled edges for FSMPTA.
@ SlicingOnly
Build unlabelled connectivity for VFG_pre slicing.

Constructor & Destructor Documentation

◆ MTASVFGBuilder()

SVF::MTASVFGBuilder::MTASVFGBuilder ( MHP mhp,
LockAnalysis lockAnalysis,
InterferenceEdgeMode  edgeMode = InterferenceEdgeMode::Analysis 
)
inline

Constructor: driven by the interleaving (MHP) and lock analyses.

Definition at line 59 of file MTASVFGBuilder.h.

61 : SVFGBuilder(),
64 {
65 }
LockAnalysis * lockAnalysis
bool labelInterferenceEdges
false = VFG_pre (sliced-only): omit edge points-to labels
SVFGBuilder(bool _SVFGWithIndCall=Options::SVFGWithIndirectCall(), bool _SVFGWithPostOpts=Options::OPTSVFG())
Constructor.
Definition SVFGBuilder.h:53
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ ~MTASVFGBuilder()

SVF::MTASVFGBuilder::~MTASVFGBuilder ( )
overridedefault

Member Function Documentation

◆ addJoinRetEdge()

void MTASVFGBuilder::addJoinRetEdge ( const FormalOUTSVFGNode formalOut,
const ActualOUTSVFGNode actualOut,
CallSiteID  callSiteId 
)
private

Add a FormalOUT -> ActualOUT inter-procedural indirect ret edge for a join, mirroring SVFG::addInterIndirectVFRetEdge using the public SVFG API (points-to intersection + dedup via hasInterVFGEdge + addSVFGEdge).

Mirror of SVFG::addInterIndirectVFRetEdge over the public SVFG API, so the join edges can be added from the builder without modifying core SVFG.

Definition at line 173 of file MTASVFGBuilder.cpp.

176{
177 NodeBS cpts = formalOut->getPointsTo();
178 const NodeBS& dpts = actualOut->getPointsTo();
179 if (!cpts.intersects(dpts))
180 return;
181 cpts &= dpts;
182
183 SVFGNode* src = svfg->getSVFGNode(formalOut->getId());
184 SVFGNode* dst = svfg->getSVFGNode(actualOut->getId());
185 if (SVFGEdge* edge = svfg->hasInterVFGEdge(
186 src, dst, SVFGEdge::RetIndVF, callSiteId))
187 {
188 SVFUtil::cast<RetIndSVFGEdge>(edge)->addPointsTo(cpts);
189 }
190 else
191 {
193 retEdge->addPointsTo(cpts);
194 svfg->addSVFGEdge(retEdge);
195 }
196}
std::unique_ptr< SVFG > svfg
bool intersects(const SparseBitVector< ElementSize > *RHS) const

◆ addTDEdge()

SVFGEdge * MTASVFGBuilder::addTDEdge ( NodeID  srcId,
NodeID  dstId,
const PointsTo pts 
)
private

Add a thread-MHP indirect value-flow edge srcId -> dstId carrying pts.

Add (or merge into) a thread-MHP indirect value-flow edge src -> dst.

Definition at line 270 of file MTASVFGBuilder.cpp.

271{
272 SVFGNode* srcNode = svfg->getSVFGNode(srcId);
273 SVFGNode* dstNode = svfg->getSVFGNode(dstId);
275 "thread-aware overlay edge escaped its construction scope");
276
277 // VFG_pre (sliced-only) mode: keep the edge for connectivity but omit its
278 // points-to label -- no slice consumer reads it.
280 {
281 if (SVFGEdge* edge = svfg->hasThreadVFGEdge(srcNode, dstNode, SVFGEdge::TheadMHPIndirectVF))
282 return edge;
284 if (svfg->addSVFGEdge(indirectEdge))
285 {
287 return indirectEdge;
288 }
289 return nullptr;
290 }
291
292 if (SVFGEdge* edge = svfg->hasThreadVFGEdge(srcNode, dstNode, SVFGEdge::TheadMHPIndirectVF))
293 {
294 assert(SVFUtil::isa<IndirectSVFGEdge>(edge) && "should be an indirect value-flow edge!");
295 return (SVFUtil::cast<IndirectSVFGEdge>(edge)->addPointsTo(pts.toNodeBS()) ? edge : nullptr);
296 }
297 else
298 {
300 indirectEdge->addPointsTo(pts.toNodeBS());
301 if (svfg->addSVFGEdge(indirectEdge))
302 {
304 return indirectEdge;
305 }
306 return nullptr;
307 }
308}
SVFGEdgeSet threadAwareEdges
bool isInOverlayScope(const SVFGNode *node) const
@ TheadMHPIndirectVF
Definition VFGEdge.h:59

◆ buildSVFG()

void MTASVFGBuilder::buildSVFG ( )
overrideprotectedvirtual

Rewrite the SVFG build hook: build the stock SVFG, then add MHP edges.

Build the stock (thread-oblivious) SVFG, add the FSAM join-related def-use edges (relocated out of core SVFG.cpp), then add thread-aware MHP edges.

Reimplemented from SVF::SVFGBuilder.

Definition at line 126 of file MTASVFGBuilder.cpp.

127{
128 svfg->buildSVFG();
130 connectMHPEdges(svfg->getMSSA()->getPTA());
131}
void connectMHPEdges(PointerAnalysis *pta)
Connect inter-thread (interference) value-flow edges for MHP pairs.

◆ clearThreadAwareOverlay()

void MTASVFGBuilder::clearThreadAwareOverlay ( )

Remove all currently attached thread-aware interference edges.

Definition at line 133 of file MTASVFGBuilder.cpp.

134{
136 svfg->removeSVFGEdge(edge);
137 threadAwareEdges.clear();
138}

◆ collectLoadStoreSVFGNodes()

void MTASVFGBuilder::collectLoadStoreSVFGNodes ( )
private

Collect the store/load SVFG nodes to pair for interference edges (all of them, or – when a slice is set – only the kept ones).

Collect all store/load SVFG nodes.

Definition at line 242 of file MTASVFGBuilder.cpp.

243{
244 for (SVFG::const_iterator it = svfg->begin(), eit = svfg->end(); it != eit; ++it)
245 {
246 const SVFGNode* svfgNode = it->second;
247 const bool isLoad = SVFUtil::isa<LoadSVFGNode>(svfgNode);
248 if (!isLoad && !SVFUtil::isa<StoreSVFGNode>(svfgNode))
249 continue;
250 const StmtSVFGNode* node = SVFUtil::cast<StmtSVFGNode>(svfgNode);
251 if (node->getICFGNode() == nullptr)
252 continue;
253 if (!isInOverlayScope(node))
254 continue;
255 if (isLoad)
256 loadNodes.insert(node);
257 else
258 storeNodes.insert(node);
259 }
260}
IDToNodeMapTy::const_iterator const_iterator
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
Definition VFGNode.h:67

◆ connectMHPEdges()

void MTASVFGBuilder::connectMHPEdges ( PointerAnalysis pta)
private

Connect inter-thread (interference) value-flow edges for MHP pairs.

For every MHP store/load and store/store pair, add the thread-aware (interference) value-flow edges.

Definition at line 600 of file MTASVFGBuilder.cpp.

601{
602 if (overlayCandidates != nullptr)
603 {
604 // The pre-analysis candidate set is a conservative directed universe.
605 // Traverse it directly so main overlay construction is proportional to
606 // retained candidates instead of re-enumerating every alias pair.
608 for (const ThreadVFCandidate& candidate : *overlayCandidates)
609 {
610 const StmtSVFGNode* src = SVFUtil::dyn_cast<StmtSVFGNode>(
611 svfg->getSVFGNode(
612 candidate.sourceNodeId));
613 const StmtSVFGNode* dst = SVFUtil::dyn_cast<StmtSVFGNode>(
614 svfg->getSVFGNode(
615 candidate.destinationNodeId));
616 assert(src != nullptr && dst != nullptr &&
617 "thread-aware candidates must reference statement nodes");
618 assert(SVFUtil::isa<StoreSVFGNode>(src) &&
619 "thread-aware candidate source must be a store");
621 "thread-aware candidate escaped its selected scope");
622
623 if (SVFUtil::isa<LoadSVFGNode>(dst))
624 handleStoreLoad(src, dst, pta);
625 else if (SVFUtil::isa<StoreSVFGNode>(dst))
626 {
627 const ThreadVFCandidate canonicalPair =
628 candidate.sourceNodeId < candidate.destinationNodeId
629 ? candidate
630 : ThreadVFCandidate(candidate.destinationNodeId,
631 candidate.sourceNodeId);
632 if (processedStorePairs.insert(canonicalPair).second)
633 // Main ILA re-decides the unordered pair once; the handler
634 // emits whichever directed edges pass the lock-span rules.
635 handleStoreStore(src, dst, pta);
636 }
637 }
638 return;
639 }
640
642
643 // Inverted access index (object -> access-node bitset): unioning the
644 // bitsets per store visits each may-alias pair exactly once, no dedup tables.
647 for (const StmtSVFGNode* store : storeNodes)
648 for (NodeID objectId : pta->getPts(store->getDstNodeID()))
649 objectToStoreIds[objectId].set(store->getId());
650 for (const StmtSVFGNode* load : loadNodes)
651 for (NodeID objectId : pta->getPts(load->getSrcNodeID()))
652 objectToLoadIds[objectId].set(load->getId());
653
654 for (const StmtSVFGNode* store : storeNodes)
655 {
658 for (NodeID objectId : pta->getPts(store->getDstNodeID()))
659 {
661 const auto loads = objectToLoadIds.find(objectId);
662 if (loads != objectToLoadIds.end())
663 candidateLoads |= loads->second;
664 }
665
667 {
668 const StmtSVFGNode* load =
669 SVFUtil::cast<StmtSVFGNode>(svfg->getSVFGNode(loadId));
670 handleStoreLoad(store, load, pta);
671 }
672
673 // Visit each unordered store pair once: only partners with a larger id.
674 const NodeID storeId = store->getId();
676 {
677 if (otherId <= storeId)
678 continue;
679 const StmtSVFGNode* other =
680 SVFUtil::cast<StmtSVFGNode>(svfg->getSVFGNode(otherId));
681 handleStoreStore(store, other, pta);
682 }
683 }
684}
for(i=0;a &&(i<(size_t) count);i++)
Definition cJSON.cpp:2569
void handleStoreStore(const StmtSVFGNode *firstStore, const StmtSVFGNode *secondStore, PointerAnalysis *pta)
const ThreadVFCandidateList * overlayCandidates
void handleStoreLoad(const StmtSVFGNode *store, const StmtSVFGNode *load, PointerAnalysis *pta)
u32_t NodeID
Definition GeneralType.h:76

◆ connectThreadJoinEdges()

void MTASVFGBuilder::connectThreadJoinEdges ( )
private

FSAM join-related thread-oblivious value flow (the "return" half of treating a join as a call without a forward): connect each start routine's exit defs (FormalOUT) to the ActualOUT at every site that joins it (FormalOUT -> ActualOUT ret edge). Done here as a post-pass over the stock SVFG, so core SVFG.cpp stays unmodified.

FSAM join-related def-use (the "return" half of treating a join as a call without a forward): for every FormalOUT (a start routine's exit def), connect it to the ActualOUT at each site that joins that routine. Relocated here from core SVFG::connectIndirectSVFGEdges so the stock SVFG stays unmodified.

Definition at line 204 of file MTASVFGBuilder.cpp.

205{
206 ThreadCallGraph* tcg =
207 SVFUtil::dyn_cast<ThreadCallGraph>(svfg->getMSSA()->getPTA()->getCallGraph());
208 if (tcg == nullptr)
209 return;
210
211 MemSSA* mssa = svfg->getMSSA();
212 for (SVFG::const_iterator it = svfg->begin(), eit = svfg->end(); it != eit; ++it)
213 {
214 const FormalOUTSVFGNode* formalOut = SVFUtil::dyn_cast<FormalOUTSVFGNode>(it->second);
215 if (formalOut == nullptr)
216 continue;
217
219 tcg->getJoinSites(tcg->getCallGraphNode(formalOut->getFun()), joinSites);
220 for (const CallICFGNode* callSite : joinSites)
221 {
222 if (!mssa->hasCHI(callSite))
223 continue;
225 svfg->getActualOUTSVFGNodes(callSite);
227 {
229 SVFUtil::cast<ActualOUTSVFGNode>(
230 svfg->getSVFGNode(actualOutId));
233 svfg->getCallSiteID(callSite, formalOut->getFun()));
234 }
235 }
236 }
237}
const CallGraphNode * getCallGraphNode(const std::string &name) const
Get call graph node.
void addJoinRetEdge(const FormalOUTSVFGNode *formalOut, const ActualOUTSVFGNode *actualOut, CallSiteID callSiteId)
bool hasCHI(const PAGEdge *inst) const
Definition MemSSA.h:338
OrderedSet< const CallICFGNode *, CallSiteIdCmp > InstSet
void getJoinSites(const CallGraphNode *routine, InstSet &csSet)

◆ createMRGenerator()

std::unique_ptr< MRGenerator > MTASVFGBuilder::createMRGenerator ( BVDataPTAImpl pta,
bool  ptrOnlyMSSA 
)
overrideprotectedvirtual

Inject a thread-aware MRGenerator so the MemSSA mod-ref carries the FSAM fork/join side effects (relocated here from core MemRegion).

Reimplemented from SVF::SVFGBuilder.

Definition at line 106 of file MTASVFGBuilder.cpp.

107{
108 switch (Options::MemPar())
109 {
111 return std::make_unique<ThreadMRG<DistinctMRG>>(pta, ptrOnlyMSSA);
113 return std::make_unique<ThreadMRG<IntraDisjointMRG>>(pta, ptrOnlyMSSA);
115 return std::make_unique<ThreadMRG<InterDisjointMRG>>(pta, ptrOnlyMSSA);
116 default:
117 assert(false && "unrecognised memory partition strategy");
118 return nullptr;
119 }
120}
@ InterDisjoint
Definition MemSSA.h:117
@ IntraDisjoint
Definition MemSSA.h:116
static const OptionMap< u32_t > MemPar
Definition Options.h:141

◆ getPredecessorNodes()

MTASVFGBuilder::SVFGNodeIDSet MTASVFGBuilder::getPredecessorNodes ( const StmtSVFGNode node)
private

Lock-span head/tail tests (non-interference lock-pair pruning).

Backward reachable store SVFG nodes via indirect value flow (lock-span head test).

Definition at line 313 of file MTASVFGBuilder.cpp.

315{
316 const auto found = predecessorCache.find(node);
317 if (found != predecessorCache.end())
318 return found->second;
319
321 Set<const SVFGNode*> worklist;
322 Set<const SVFGNode*> visited;
323
324 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->InEdgeBegin();
325 iter != node->InEdgeEnd(); ++iter)
326 {
327 SVFGEdge* edge = *iter;
328 if (edge->isIndirectVFGEdge() && !edge->isThreadMHPIndirectVFGEdge() &&
329 isInOverlayScope(edge->getSrcNode()))
330 worklist.insert(edge->getSrcNode());
331 }
332
333 while (!worklist.empty())
334 {
335 const SVFGNode* node = *worklist.begin();
336 worklist.erase(worklist.begin());
337 visited.insert(node);
338 if (SVFUtil::isa<StoreSVFGNode>(node))
339 predecessors.set(node->getId());
340 else
341 {
342 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->InEdgeBegin(); iter != node->InEdgeEnd(); ++iter)
343 {
344 SVFGEdge* edge = *iter;
345 if (edge->isIndirectVFGEdge() &&
346 !edge->isThreadMHPIndirectVFGEdge() &&
347 isInOverlayScope(edge->getSrcNode()) &&
348 visited.find(edge->getSrcNode()) == visited.end())
349 worklist.insert(edge->getSrcNode());
350 }
351 }
352 }
354 return predecessors;
355}
iterator InEdgeBegin()
iterator InEdgeEnd()
Map< const StmtSVFGNode *, SVFGNodeIDSet > predecessorCache
NodeID getId() const
Get ID.
Definition SVFValue.h:158

◆ getSuccessorNodes()

MTASVFGBuilder::SVFGNodeIDSet MTASVFGBuilder::getSuccessorNodes ( const StmtSVFGNode node)
private

Forward reachable store/load SVFG nodes via indirect value flow (lock-span tail test).

Definition at line 360 of file MTASVFGBuilder.cpp.

362{
363 const auto found = successorCache.find(node);
364 if (found != successorCache.end())
365 return found->second;
366
367 SVFGNodeIDSet successors;
368 Set<const SVFGNode*> worklist;
369 Set<const SVFGNode*> visited;
370
371 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->OutEdgeBegin();
372 iter != node->OutEdgeEnd(); ++iter)
373 {
374 SVFGEdge* edge = *iter;
375 if (edge->isIndirectVFGEdge() && !edge->isThreadMHPIndirectVFGEdge() &&
376 isInOverlayScope(edge->getDstNode()))
377 worklist.insert(edge->getDstNode());
378 }
379
380 while (!worklist.empty())
381 {
382 const SVFGNode* node = *worklist.begin();
383 worklist.erase(worklist.begin());
384 visited.insert(node);
385 if (SVFUtil::isa<StoreSVFGNode, LoadSVFGNode>(node))
386 successors.set(node->getId());
387 else
388 {
389 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->OutEdgeBegin(); iter != node->OutEdgeEnd(); ++iter)
390 {
391 SVFGEdge* edge = *iter;
392 if (edge->isIndirectVFGEdge() &&
393 !edge->isThreadMHPIndirectVFGEdge() &&
394 isInOverlayScope(edge->getDstNode()) &&
395 visited.find(edge->getDstNode()) == visited.end())
396 worklist.insert(edge->getDstNode());
397 }
398 }
399 }
400 successorCache[node] = successors;
401 return successors;
402}
iterator OutEdgeEnd()
iterator OutEdgeBegin()
iterators
Map< const StmtSVFGNode *, SVFGNodeIDSet > successorCache

◆ getThreadAwareEdgeCount()

size_t SVF::MTASVFGBuilder::getThreadAwareEdgeCount ( ) const
inline

Definition at line 157 of file MTASVFGBuilder.h.

158 {
159 return threadAwareEdges.size();
160 }

◆ getThreadVFQueryMap()

const ThreadVFQueryMap & SVF::MTASVFGBuilder::getThreadVFQueryMap ( ) const
inline

Definition at line 88 of file MTASVFGBuilder.h.

89 {
90 return threadVFQueryMap;
91 }
ThreadVFQueryMap threadVFQueryMap
[THREAD-VF] per-edge query map (see getThreadVFQueryMap).

◆ handleStoreLoad()

void MTASVFGBuilder::handleStoreLoad ( const StmtSVFGNode store,
const StmtSVFGNode load,
PointerAnalysis pta 
)
private

Store -> Load interference: add a thread-aware def-use edge if the store may happen in parallel with and may alias the load, unless excluded by a common lock (then only when the store is a span tail and the load a span head).

Definition at line 507 of file MTASVFGBuilder.cpp.

510{
511 const ICFGNode* storeNode = store->getICFGNode();
512 const ICFGNode* loadNode = load->getICFGNode();
513
515 if (!mayParallel)
516 return;
517
518 // No alias() re-check: the bucketed candidate generator only pairs accesses
519 // whose raw points-to sets share an object, so the intersection below is
520 // non-empty by construction and alias() could never answer NoAlias here.
521 // The label is only needed when the edge will be solved (main FSMPTA); in
522 // VFG_pre (sliced-only) mode skip the intersection -- it is never read.
525 {
526 pts = pta->getPts(store->getDstNodeID());
527 pts &= pta->getPts(load->getSrcNodeID());
528 }
529
530 // [THREAD-VF] source extraction runs for every candidate pair (both the
531 // pairs that survive and the ones the lock test prunes), so the sliced ILA
532 // can re-derive whether the edge holds.
533 const bool commonLock =
536 recordThreadVFSource(store, load, commonLock);
537
538 if (commonLock)
539 {
540 if (isTailOfSpan(store) && isHeadOfSpan(load))
541 addTDEdge(store->getId(), load->getId(), pts);
542 }
543 else
544 {
545 addTDEdge(store->getId(), load->getId(), pts);
546 }
547}
bool isProtectedByCommonLock(const ICFGNode *i1, const ICFGNode *i2)
virtual bool mayHappenInParallel(const ICFGNode *i1, const ICFGNode *i2)
Interface to query whether two instructions may happen-in-parallel.
Definition MHP.cpp:854
bool recordThreadVFQueries
false = skip [THREAD-VF] recording
SVFGEdge * addTDEdge(NodeID srcId, NodeID dstId, const PointsTo &pts)
Add a thread-MHP indirect value-flow edge srcId -> dstId carrying pts.
void recordThreadVFSource(const StmtSVFGNode *source, const StmtSVFGNode *destination, bool commonLock)
bool isHeadOfSpan(const StmtSVFGNode *node)
bool isTailOfSpan(const StmtSVFGNode *node)
virtual const PointsTo & getPts(NodeID ptr)=0
Get points-to targets of a pointer. It needs to be implemented in child class.
NodeID getSrcNodeID() const
Definition VFGNode.h:152
NodeID getDstNodeID() const
Definition VFGNode.h:157

◆ handleStoreStore()

void MTASVFGBuilder::handleStoreStore ( const StmtSVFGNode firstStore,
const StmtSVFGNode secondStore,
PointerAnalysis pta 
)
private

Store -> Store interference (symmetric): add thread-aware def-use edges in both directions, with the same lock-span pruning as store/load.

Definition at line 553 of file MTASVFGBuilder.cpp.

556{
557 const ICFGNode* firstNode = firstStore->getICFGNode();
558 const ICFGNode* secondNode = secondStore->getICFGNode();
559
561 if (!mayParallel)
562 return;
563
564 // No alias() re-check: see handleStoreLoad -- bucketing already guarantees a
565 // shared raw object. Skip the label intersection in VFG_pre (sliced-only) mode.
568 {
569 pts = pta->getPts(firstStore->getDstNodeID());
570 pts &= pta->getPts(secondStore->getDstNodeID());
571 }
572
573 // Both directions are candidate thread-aware edges; extract sources for each.
574 const bool commonLock =
577 {
580 }
581
582 if (commonLock)
583 {
585 addTDEdge(firstStore->getId(), secondStore->getId(), pts);
587 addTDEdge(secondStore->getId(), firstStore->getId(), pts);
588 }
589 else
590 {
591 addTDEdge(firstStore->getId(), secondStore->getId(), pts);
592 addTDEdge(secondStore->getId(), firstStore->getId(), pts);
593 }
594}

◆ isHeadOfSpan()

bool MTASVFGBuilder::isHeadOfSpan ( const StmtSVFGNode node)
private

Whether, for all lock spans n belongs to, n is the first write (span head).

Definition at line 407 of file MTASVFGBuilder.cpp.

408{
409 const auto found = spanHeadCache.find(node);
410 if (found != spanHeadCache.end())
411 return found->second;
412
414 for (NodeID id : predecessors)
415 {
416 const StmtSVFGNode* prevNode = SVFUtil::dyn_cast<StmtSVFGNode>(svfg->getSVFGNode(id));
417 if (prevNode != nullptr && lockAnalysis->isInSameSpan(
418 prevNode->getICFGNode(), node->getICFGNode()))
419 {
420 spanHeadCache[node] = false;
421 return false;
422 }
423 }
424 spanHeadCache[node] = true;
425 return true;
426}
bool isInSameSpan(const ICFGNode *I1, const ICFGNode *I2)
Map< const StmtSVFGNode *, bool > spanHeadCache
SVFGNodeIDSet getPredecessorNodes(const StmtSVFGNode *node)
Lock-span head/tail tests (non-interference lock-pair pruning).

◆ isInOverlayScope()

bool MTASVFGBuilder::isInOverlayScope ( const SVFGNode node) const
private

Definition at line 262 of file MTASVFGBuilder.cpp.

263{
264 return overlayScope == nullptr || overlayScope->isKeptNode(node);
265}
const SlicedSVFGView * overlayScope
Active overlay configuration; defaults suit VFG_pre.
bool isKeptNode(const SVFGNode *n) const
Whether the node is retained (see the class comment for the rule).

◆ isTailOfSpan()

bool MTASVFGBuilder::isTailOfSpan ( const StmtSVFGNode node)
private

Whether, for all lock spans n belongs to, n is the last write (span tail).

Definition at line 431 of file MTASVFGBuilder.cpp.

432{
433 assert(SVFUtil::isa<StoreSVFGNode>(node) &&
434 "tail test only for store nodes");
435
436 const auto found = spanTailCache.find(node);
437 if (found != spanTailCache.end())
438 return found->second;
439
440 const SVFGNodeIDSet successors = getSuccessorNodes(node);
441 for (NodeID id : successors)
442 {
443 const SVFGNode* successor = svfg->getSVFGNode(id);
444 if (SVFUtil::isa<LoadSVFGNode>(successor))
445 continue;
447 SVFUtil::dyn_cast<StmtSVFGNode>(successor);
449 successorStatement->getICFGNode(), node->getICFGNode()))
450 {
451 spanTailCache[node] = false;
452 return false;
453 }
454 }
455 spanTailCache[node] = true;
456 return true;
457}
Map< const StmtSVFGNode *, bool > spanTailCache
SVFGNodeIDSet getSuccessorNodes(const StmtSVFGNode *node)

◆ recordThreadVFSource()

void MTASVFGBuilder::recordThreadVFSource ( const StmtSVFGNode source,
const StmtSVFGNode destination,
bool  commonLock 
)
private

Record the [THREAD-VF] slicing sources for one candidate pair s –o--> s' (source = store, destination = load/store). Adds the endpoints, and — when the pair is protected by a common lock — the in-span successor/predecessor witnesses needed to re-decide the non-interference (tail/head) test.

Record the per-edge [THREAD-VF] query for one candidate pair s –o--> s' (see getThreadVFQueryMap for the rule): the endpoints, plus – under a common lock – the in-span Succ_spl(s) / Pred_spl'(s') witnesses. Enumerated fully (the tail/head boolean tests short-circuit; source extraction must not).

Definition at line 465 of file MTASVFGBuilder.cpp.

468{
469 // Per-edge Query set. The endpoints are NOT duplicated into the value --
470 // they are recoverable from the map key -- so the value holds only the
471 // additional in-span witnesses below (empty for the common lock-free case).
474
475 if (!commonLock)
476 return;
477
478 // Succ_spl(s) = { x in s's span | x is a store, s --o--> x }.
480 {
481 const SVFGNode* successor = svfg->getSVFGNode(id);
482 if (!SVFUtil::isa<StoreSVFGNode>(successor))
483 continue;
485 SVFUtil::cast<StmtSVFGNode>(successor);
487 successorStatement->getICFGNode(), source->getICFGNode()))
488 query.insert(successorStatement->getICFGNode());
489 }
490
491 // Pred_spl'(s') = { x in s' span | x --o--> s' }.
493 {
494 const StmtSVFGNode* prevNode =
495 SVFUtil::dyn_cast<StmtSVFGNode>(svfg->getSVFGNode(id));
496 if (prevNode != nullptr && lockAnalysis->isInSameSpan(
497 prevNode->getICFGNode(), destination->getICFGNode()))
498 query.insert(prevNode->getICFGNode());
499 }
500}

◆ replaceThreadAwareOverlay()

void MTASVFGBuilder::replaceThreadAwareOverlay ( MHP mhp,
LockAnalysis lockAnalysis,
const ThreadVFBuildConfig config 
)

Replace only the ILA-dependent thread-aware overlay. The underlying MemorySSA, stock SVFG, and fork/join value flow remain unchanged.

Definition at line 140 of file MTASVFGBuilder.cpp.

143{
144 assert(svfg != nullptr && "base SVFG must be built before replacing its overlay");
145 assert(mainMHP != nullptr && mainLockAnalysis != nullptr &&
146 "thread-aware overlay requires main ILA results");
147
149 mhp = mainMHP;
151 overlayScope = config.scope;
152 overlayCandidates = config.candidates;
153 recordThreadVFQueries = false;
155
156 storeNodes.clear();
157 loadNodes.clear();
158 threadVFQueryMap.clear();
159 predecessorCache.clear();
160 successorCache.clear();
161 spanHeadCache.clear();
162 spanTailCache.clear();
163
164 connectMHPEdges(svfg->getMSSA()->getPTA());
165 overlayScope = nullptr;
166 overlayCandidates = nullptr;
167}
void clearThreadAwareOverlay()
Remove all currently attached thread-aware interference edges.

Member Data Documentation

◆ labelInterferenceEdges

bool SVF::MTASVFGBuilder::labelInterferenceEdges = true
private

false = VFG_pre (sliced-only): omit edge points-to labels

Definition at line 175 of file MTASVFGBuilder.h.

◆ loadNodes

SVFGNodeSet SVF::MTASVFGBuilder::loadNodes
private

Definition at line 225 of file MTASVFGBuilder.h.

◆ lockAnalysis

LockAnalysis* SVF::MTASVFGBuilder::lockAnalysis
private

Definition at line 230 of file MTASVFGBuilder.h.

◆ mhp

MHP* SVF::MTASVFGBuilder::mhp
private

Definition at line 229 of file MTASVFGBuilder.h.

◆ overlayCandidates

const ThreadVFCandidateList* SVF::MTASVFGBuilder::overlayCandidates = nullptr
private

Definition at line 173 of file MTASVFGBuilder.h.

◆ overlayScope

const SlicedSVFGView* SVF::MTASVFGBuilder::overlayScope = nullptr
private

Active overlay configuration; defaults suit VFG_pre.

null = whole base SVFG

Definition at line 172 of file MTASVFGBuilder.h.

◆ predecessorCache

Map<const StmtSVFGNode*, SVFGNodeIDSet> SVF::MTASVFGBuilder::predecessorCache
private

Definition at line 232 of file MTASVFGBuilder.h.

◆ recordThreadVFQueries

bool SVF::MTASVFGBuilder::recordThreadVFQueries = true
private

false = skip [THREAD-VF] recording

Definition at line 174 of file MTASVFGBuilder.h.

◆ spanHeadCache

Map<const StmtSVFGNode*, bool> SVF::MTASVFGBuilder::spanHeadCache
private

Definition at line 234 of file MTASVFGBuilder.h.

◆ spanTailCache

Map<const StmtSVFGNode*, bool> SVF::MTASVFGBuilder::spanTailCache
private

Definition at line 235 of file MTASVFGBuilder.h.

◆ storeNodes

SVFGNodeSet SVF::MTASVFGBuilder::storeNodes
private

Definition at line 224 of file MTASVFGBuilder.h.

◆ successorCache

Map<const StmtSVFGNode*, SVFGNodeIDSet> SVF::MTASVFGBuilder::successorCache
private

Definition at line 233 of file MTASVFGBuilder.h.

◆ threadAwareEdges

SVFGEdgeSet SVF::MTASVFGBuilder::threadAwareEdges
private

Definition at line 236 of file MTASVFGBuilder.h.

◆ threadVFQueryMap

ThreadVFQueryMap SVF::MTASVFGBuilder::threadVFQueryMap
private

[THREAD-VF] per-edge query map (see getThreadVFQueryMap).

Definition at line 228 of file MTASVFGBuilder.h.


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