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

#include <MTA.h>

Public Types

using ResolveIndirectCalls = std::function< void(CallGraph *)>
 
using RacePair = MTA::RacePair
 The shared race detector lives in MTA; reuse its race-pair type.
 

Public Member Functions

 SlicedMTA ()
 
 ~SlicedMTA ()
 
 SlicedMTA (const SlicedMTA &)=delete
 
SlicedMTAoperator= (const SlicedMTA &)=delete
 
void runOnModule (SVFIR *pag, const ResolveIndirectCalls &resolveIndirectCalls)
 Run the slicing pipeline on a pre-built SVFIR.
 

Private Member Functions

bool runPreAnalysis (const ResolveIndirectCalls &resolveIndirectCalls)
 
bool runMTASlicingAndAnalysis ()
 
bool runPTASlicingAndAnalysis ()
 
bool runFinalRaceDetection ()
 
void buildVFGPre ()
 
void runWholeProgramDetection ()
 
BVDataPTAImplgetMainPTA () const
 
std::set< const SVFStmt * > getVulnerableStmts () const
 Union of both statements of every candidate race pair (the slice targets).
 
std::set< RacePairdetectRacePairsOnSlicedGraph (BVDataPTAImpl *slicedPTA, MHP *slicedMHP, LockAnalysis *slicedLockAnalysis)
 Re-check the candidate race pairs on the sliced graph using FSAM points-to.
 
LockAnalysisbuildFullLockAnalysis ()
 

Private Attributes

SVFIRsvfIr = nullptr
 
u32_t mainCxtDepth = 2
 
std::unique_ptr< TCTtct
 
std::unique_ptr< MHPmhp
 
std::unique_ptr< LockAnalysislockAnalysis
 
AndersenWaveDiffpreAnder = nullptr
 
std::unique_ptr< MTASVFGBuildervfgPreBuilder
 
SVFGvfgPre = nullptr
 
std::unique_ptr< MultiStageSlicermultiStageSlicer
 
std::unique_ptr< SingleSlicersingleSlicer
 
std::set< const ICFGNode * > singleSlicedNodes
 
std::unique_ptr< SlicedSVFIRViewmtaSlicedView
 
std::unique_ptr< SlicedSVFIRViewptaSlicedView
 
std::unique_ptr< SlicedSVFGViewslicedSVFGView
 
std::unique_ptr< FlowSensitivemtaFSMPTA
 
std::unique_ptr< SlicedTCTslicedTCT
 
std::unique_ptr< MHPslicedMhp
 
std::unique_ptr< LockAnalysisslicedLockAnalysis
 
std::unique_ptr< SlicedSVFIRViewfullLockView
 
std::unique_ptr< SlicedTCTfullLockTCT
 
std::unique_ptr< LockAnalysisfullLockAnalysis
 
bool hasThreadFunctions = false
 
std::set< RacePairracePairs
 

Detailed Description

Multi-stage on-demand slicing race detection pipeline (MSli).

runOnModule drives five stages on a pre-built SVFIR:

  1. (caller) build SVFIR + resolve indirect calls into the PAG
  2. pre-analysis: Andersen, TCT, MHP, lock, candidate race pairs, VFG_pre
  3. MTA slicing: slice the thread-aware graph, build the sliced MHP/lock
  4. PTA slicing + main flow-sensitive FSAM (FSMPTA) on the slice
  5. final race detection on the sliced graph using FSAM points-to

It operates entirely on the SVFIR (LLVM-free). The single LLVM-dependent step – materialising resolved indirect calls into the PAG – is injected by the caller as a callback (see runOnModule).

Behaviour is controlled by Options (MTFlowSensitive, EnableSlicing, SlicingSingle, SlicedDumpDot).

Definition at line 188 of file MTA.h.

Member Typedef Documentation

◆ RacePair

The shared race detector lives in MTA; reuse its race-pair type.

Definition at line 197 of file MTA.h.

◆ ResolveIndirectCalls

The one LLVM-dependent step of the pipeline: resolve the indirect-call edges discovered by Andersen into PAG copy/call edges. The caller (the LLVM-aware tool) supplies it via SVFIRBuilder::updateCallGraph.

Definition at line 194 of file MTA.h.

Constructor & Destructor Documentation

◆ SlicedMTA() [1/2]

SlicedMTA::SlicedMTA ( )
default

◆ ~SlicedMTA()

SlicedMTA::~SlicedMTA ( )

Definition at line 469 of file MTA.cpp.

470{
471 // Cleanup in reverse order of creation. Release the VFG_pre (and its MemSSA),
472 // the FSAM, the sliced/base TCTs -- all of which reference the SVFIR -- before
473 // releasing the SVFIR itself. The remaining unique_ptr members (mhp /
474 // lockAnalysis / sliced* / slicers / views) auto-destroy after this body.
475 vfgPreBuilder.reset();
476 mtaFSMPTA.reset();
477 slicedTCT.reset();
478 tct.reset();
480 // The Andersen pre-analysis is a shared singleton (reused by VFG_pre and the
481 // main FSMPTA, neither of which frees it); release it once here.
483}
static void releaseAndersenWaveDiff()
Definition Andersen.h:418
static void releaseSVFIR()
Definition SVFIR.h:128
std::unique_ptr< FlowSensitive > mtaFSMPTA
Definition MTA.h:263
std::unique_ptr< TCT > tct
Definition MTA.h:246
std::unique_ptr< SlicedTCT > slicedTCT
Definition MTA.h:264
std::unique_ptr< MTASVFGBuilder > vfgPreBuilder
Definition MTA.h:253

◆ SlicedMTA() [2/2]

SVF::SlicedMTA::SlicedMTA ( const SlicedMTA )
delete

Member Function Documentation

◆ buildFullLockAnalysis()

LockAnalysis * SlicedMTA::buildFullLockAnalysis ( )
private

Definition at line 855 of file MTA.cpp.

856{
857 if (fullLockAnalysis != nullptr)
858 return fullLockAnalysis.get();
859 std::set<const ICFGNode*> allNodes;
860 for (ICFG::iterator it = svfIr->getICFG()->begin(), eit = svfIr->getICFG()->end(); it != eit; ++it)
861 allNodes.insert(it->second);
862 fullLockView = std::make_unique<SlicedSVFIRView>(
864 fullLockTCT = std::make_unique<SlicedTCT>(preAnder, fullLockView.get(), slicedMaxContextLen());
865 fullLockAnalysis = std::make_unique<LockAnalysis>(fullLockTCT.get());
866 const SlicedSVFIRView* flv = fullLockView.get();
867 fullLockAnalysis->analyze(flv->getICFG(), flv->getThreadCallGraph());
868 return fullLockAnalysis.get();
869}
iterator begin()
Iterators.
ICFGNodeIDToNodeMapTy::iterator iterator
Definition ICFG.h:58
CallGraph * getCallGraph() const
Return call graph.
ICFG * getICFG() const
Definition SVFIR.h:231
std::unique_ptr< SlicedSVFIRView > fullLockView
Definition MTA.h:268
SVFIR * svfIr
Definition MTA.h:242
std::unique_ptr< LockAnalysis > fullLockAnalysis
Definition MTA.h:270
std::unique_ptr< SlicedTCT > fullLockTCT
Definition MTA.h:269
AndersenWaveDiff * preAnder
Definition MTA.h:252
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ buildVFGPre()

void SlicedMTA::buildVFGPre ( )
private

Definition at line 508 of file MTA.cpp.

509{
510 timePhase("Build thread-aware VFG_pre", [&]()
511 {
512 // preAnder is the pre-analysis Andersen built in runPreAnalysis.
513 // Treat fork/join as calls so the SVFG carries the thread-oblivious
514 // (fork/join-ordered) value flow.
515 if (ThreadCallGraph* tcg = SVFUtil::dyn_cast<ThreadCallGraph>(preAnder->getCallGraph()))
516 {
517 tcg->updateCallGraph(preAnder);
518 tcg->updateJoinEdge(preAnder);
519 }
520 vfgPreBuilder = std::make_unique<MTASVFGBuilder>(mhp.get(), lockAnalysis.get());
521 vfgPre = vfgPreBuilder->buildPTROnlySVFG(preAnder);
522 SVFUtil::outs() << "[VFG_pre] thread-aware SVFG: " << vfgPre->getSVFGNodeNum()
523 << " nodes, " << MTASVFGBuilder::numOfNewSVFGEdges << " interference edges\n";
524 });
525}
static u32_t numOfNewSVFGEdges
Number of thread-aware (interference) SVFG edges added.
u32_t getSVFGNodeNum() const
Return total SVFG node number.
Definition SVFG.h:271
std::unique_ptr< LockAnalysis > lockAnalysis
Definition MTA.h:248
SVFG * vfgPre
Definition MTA.h:254
std::unique_ptr< MHP > mhp
Definition MTA.h:247
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52

◆ detectRacePairsOnSlicedGraph()

std::set< SlicedMTA::RacePair > SlicedMTA::detectRacePairsOnSlicedGraph ( BVDataPTAImpl slicedPTA,
MHP slicedMHP,
LockAnalysis slicedLockAnalysis 
)
private

Re-check the candidate race pairs on the sliced graph using FSAM points-to.

Definition at line 1057 of file MTA.cpp.

1061{
1062
1063 std::set<RacePair> filteredRacePairs;
1064
1065 // Re-derive candidates at the main context on this graph: slicedMHP carries
1066 // only kept nodes, so the sliced and whole runs invoke the identical detector.
1067 std::set<RacePair> candidatePairs;
1070
1071 // The only remaining screen is the flow-sensitive points-to refinement (the
1072 // ILA conditions C1-C4 were already applied by detectRace above).
1073 for (const RacePair& pair : candidatePairs)
1074 {
1075 // Re-check points-to intersection using sliced PTA
1077 if (const LoadStmt* ldStmt1 = SVFUtil::dyn_cast<LoadStmt>(pair.stmt1))
1078 {
1079 pts1 = slicedPTA->getPts(ldStmt1->getRHSVarID());
1080 }
1081 else if (const StoreStmt* stStmt1 = SVFUtil::dyn_cast<StoreStmt>(pair.stmt1))
1082 {
1083 pts1 = slicedPTA->getPts(stStmt1->getLHSVarID());
1084 }
1085 else
1086 {
1087 continue;
1088 }
1089
1090 if (const LoadStmt* ldStmt2 = SVFUtil::dyn_cast<LoadStmt>(pair.stmt2))
1091 {
1092 pts2 = slicedPTA->getPts(ldStmt2->getRHSVarID());
1093 }
1094 else if (const StoreStmt* stStmt2 = SVFUtil::dyn_cast<StoreStmt>(pair.stmt2))
1095 {
1096 pts2 = slicedPTA->getPts(stStmt2->getLHSVarID());
1097 }
1098 else
1099 {
1100 continue;
1101 }
1102
1103 // Check if points-to sets still intersect
1104 if (pts1.intersects(pts2))
1105 filteredRacePairs.insert(pair);
1106 }
1107
1108 return filteredRacePairs;
1109}
static std::set< const SVFStmt * > detectRace(SVFIR *svfIr, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, CallGraph *callGraph, std::set< RacePair > &outRacePairs)
Definition MTA.cpp:221
MTA::RacePair RacePair
The shared race detector lives in MTA; reuse its race-pair type.
Definition MTA.h:197
std::unique_ptr< LockAnalysis > slicedLockAnalysis
Definition MTA.h:266

◆ getMainPTA()

BVDataPTAImpl * SlicedMTA::getMainPTA ( ) const
private

Main pointer-analysis instance feeding final race detection (the flow-sensitive FSAM, a BVDataPTAImpl queried polymorphically).

Definition at line 485 of file MTA.cpp.

486{
487 // The main FSMPTA phase is the flow-sensitive FSAM (FSMPTA), a
488 // BVDataPTAImpl, so the downstream race detector queries it polymorphically.
489 return mtaFSMPTA.get();
490}

◆ getVulnerableStmts()

std::set< const SVFStmt * > SlicedMTA::getVulnerableStmts ( ) const
private

Union of both statements of every candidate race pair (the slice targets).

Definition at line 492 of file MTA.cpp.

493{
494 std::set<const SVFStmt*> v;
495 for (const RacePair& pair : racePairs)
496 {
497 v.insert(pair.stmt1);
498 v.insert(pair.stmt2);
499 }
500 return v;
501}
std::set< RacePair > racePairs
Definition MTA.h:272

◆ operator=()

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

◆ runFinalRaceDetection()

bool SlicedMTA::runFinalRaceDetection ( )
private

Definition at line 872 of file MTA.cpp.

873{
874 SVFUtil::outs() << "\n=== Final Race Detection ===\n";
875
877 {
878 SVFUtil::outs() << "[SKIP] No thread functions found\n";
879 return true;
880 }
881 if (mtaSlicedView == nullptr)
882 {
883 SVFUtil::outs() << "[SKIP] MTA sliced view not available\n";
884 return true;
885 }
886 if (slicedMhp == nullptr || slicedLockAnalysis == nullptr)
887 {
888 SVFUtil::outs() << "[SKIP] Sliced MHP or LockAnalysis not available\n";
889 return true;
890 }
891 if (getMainPTA() == nullptr)
892 {
893 SVFUtil::outs() << "[SKIP] Main flow-sensitive pointer analysis not available\n";
894 return true;
895 }
896
897 std::set<RacePair> detectedPairs;
898 LockAnalysis* fullLock = buildFullLockAnalysis(); // whole-ICFG lock (no bridging)
899 timePhase("Final Race Detection", [&]()
900 {
902 getMainPTA(), // Use flow-sensitive FSAM points-to
903 slicedMhp.get(), fullLock);
904 });
905
906 // Distinct racy statements (the endpoints of the race pairs) -- a stabler,
907 // smaller-to-report metric than the pair count.
908 std::set<const SVFStmt*> racyStmts;
909 for (const RacePair& rp : detectedPairs)
910 {
911 racyStmts.insert(rp.stmt1);
912 racyStmts.insert(rp.stmt2);
913 }
914
915 SVFUtil::outs() << "\n=== Race Detection Summary ===\n";
916 SVFUtil::outs() << "Race pairs (pre-analysis): " << racePairs.size() << "\n";
917 SVFUtil::outs() << "Race pairs (sliced graph): " << detectedPairs.size() << "\n";
918 SVFUtil::outs() << "Race statements (sliced graph): " << racyStmts.size() << "\n";
919 // Machine-readable line for the artifact's `msli` table generator: the race
920 // statements reported after slicing (the preservation metric).
921 SVFUtil::outs() << "[MSLI-RQ] mode=MSli alarms=" << racyStmts.size() << "\n";
922
923 if (!detectedPairs.empty())
924 {
925 SVFUtil::outs() << "\n=== Bug Report ===\n";
926 SVFUtil::outs() << "Found " << detectedPairs.size() << " race pair(s) in sliced graph\n";
927 }
928 else
929 {
930 SVFUtil::outs() << "\nNo race pairs detected in sliced graph.\n";
931 }
932
933 return true;
934}
bool hasThreadFunctions
Definition MTA.h:271
std::set< RacePair > detectRacePairsOnSlicedGraph(BVDataPTAImpl *slicedPTA, MHP *slicedMHP, LockAnalysis *slicedLockAnalysis)
Re-check the candidate race pairs on the sliced graph using FSAM points-to.
Definition MTA.cpp:1057
std::unique_ptr< SlicedSVFIRView > mtaSlicedView
Definition MTA.h:260
std::unique_ptr< MHP > slicedMhp
Definition MTA.h:265
LockAnalysis * buildFullLockAnalysis()
Definition MTA.cpp:855
BVDataPTAImpl * getMainPTA() const
Definition MTA.cpp:485

◆ runMTASlicingAndAnalysis()

bool SlicedMTA::runMTASlicingAndAnalysis ( )
private

Definition at line 634 of file MTA.cpp.

635{
636 SVFUtil::outs() << "\n=== MTA Slicing and Analysis ===\n";
637
638 if (racePairs.empty())
639 {
640 SVFUtil::outs() << "[SKIP] No race pairs found in pre-analysis\n";
641 return true;
642 }
643
644 const bool dumpDot = Options::SlicedDumpDot();
645
646 // Step 1: Get vulnerable statements from race pairs
647 std::set<const SVFStmt*> vulnerableStatements = getVulnerableStmts();
648
649 std::set<const ICFGNode*> mtaSlicedNodes;
650
652 {
653 // Single-pass baseline (MSli §3/§5.4): one unified slice (V_Single)
654 // combining synchronization + data + call dependence, shared by both the
655 // ILA and the FSPTA stages. Computed once here; reused in PTA slicing.
656 SVFUtil::outs() << "[Slicing Mode] Single unified slice (V_Single) for ILA + FSPTA\n";
657 singleSlicer = std::make_unique<SingleSlicer>(
658 svfIr, preAnder, mhp.get(), lockAnalysis.get(),
659 vfgPre /* data dependence over the thread-aware VFG_pre */);
660 timePhase("Unified Slicing", [&]()
661 {
663 });
665 SVFUtil::outs() << "Unified sliced to " << mtaSlicedNodes.size() << " nodes\n";
666 }
667 else
668 {
669 SVFUtil::outs() << "[Slicing Mode] Differential slices (separate ILA + FSPTA)\n";
670 multiStageSlicer = std::make_unique<MultiStageSlicer>(
671 svfIr, preAnder, mhp.get(), lockAnalysis.get(), vfgPre);
672
673 // ILA slicing sources = [INIT] race statements + [THREAD-VF] sources. Keep
674 // a candidate edge's query (see MTASVFGBuilder::getThreadVFQueryMap) only if
675 // both endpoints survive the FSPTA slice -- i.e. the edge is in
676 // ThreadVF(VFG'_pre). Closure computed here (pre<->pre) and reused by PTA slicing.
677 std::set<const ICFGNode*> threadVFSources;
678 if (vfgPreBuilder)
679 {
680 const std::set<const SVFGNode*>& retained =
681 multiStageSlicer->getRetainedSVFGNodes(vulnerableStatements);
682 // Millions of query entries are scanned; use a constant-time lookup
683 // view of the retained nodes instead of two ordered-set lookups each.
685 for (const auto& entry : vfgPreBuilder->getThreadVFQueryMap())
686 {
687 const MTASVFGBuilder::ThreadVFEdge& edge = entry.first;
688 if (retainedView.count(edge.first) && retainedView.count(edge.second))
689 {
690 // The query value holds only the lock-span witnesses; the
691 // endpoints are implicit in the edge key.
692 threadVFSources.insert(edge.first->getICFGNode());
693 threadVFSources.insert(edge.second->getICFGNode());
694 threadVFSources.insert(entry.second.begin(), entry.second.end());
695 }
696 }
697 }
698 SVFUtil::outs() << "[THREAD-VF] " << threadVFSources.size()
699 << " ILA slicing sources from VFG_pre value-flow construction\n";
700 timePhase("MTA Slicing", [&]()
701 {
703 });
704 SVFUtil::outs() << "MTA sliced to " << mtaSlicedNodes.size() << " nodes\n";
705 } // end differential MTA slice
706
707 // Step 4: Build MTA SlicedSVFIRView (using pre-analysis pointer analysis)
708 timePhase("Build MTA Sliced View", [&]()
709 {
710 mtaSlicedView = std::make_unique<SlicedSVFIRView>(
712 });
713 mtaSlicedView->dumpStats("MTA Sliced");
714
716
717 if (dumpDot)
718 {
719 SVFUtil::outs() << "\n[Dump] MTA Sliced views:\n";
720 slicedView->getICFG()->dump("sliced_icfg");
721 if (slicedView->getThreadCallGraph() != nullptr)
722 slicedView->getThreadCallGraph()->dump("sliced_tcg");
723 slicedView->getPAG()->dump("sliced_pag");
724 }
725
726 // Step 5: Build Sliced TCT (using pre-analysis pointer analysis)
727 timePhase("Sliced Thread Create Tree", [&]()
728 {
729 u32_t maxContextLen = slicedMaxContextLen();
730 SVFUtil::outs() << "[SlicedTCT] Using max context length: " << maxContextLen
731 << " (from -max-cxt)\n";
732 // Reuse the shared pre-analysis (Andersen) for the sliced TCT.
733 slicedTCT = std::make_unique<SlicedTCT>(preAnder, slicedView, maxContextLen);
734 if (dumpDot)
735 slicedTCT->dump("sliced_tct");
736 });
737
738 // Step 6: Sliced MHP and Lock Analysis
739 timePhase("Sliced Interleaving and Lock Analysis", [&]()
740 {
741 slicedMhp = std::make_unique<MHP>(slicedTCT.get());
742 slicedMhp->analyze(slicedView->getICFG(), slicedView->getThreadCallGraph());
743 slicedLockAnalysis = std::make_unique<LockAnalysis>(slicedTCT.get());
744 slicedLockAnalysis->analyze(slicedView->getICFG(), slicedView->getThreadCallGraph());
745 });
746
747 return true;
748}
unsigned u32_t
Definition CommandLine.h:18
std::pair< const StmtSVFGNode *, const StmtSVFGNode * > ThreadVFEdge
static const Option< bool > SlicedDumpDot
MTA slicing: dump intermediate dot graphs (ICFG/TCG/SVFG/...), Default: false.
Definition Options.h:265
static const Option< bool > SlicingSingle
MTA slicing: one unified slice for ILA + FSPTA (single-pass baseline), Default: false.
Definition Options.h:263
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
std::set< const SVFStmt * > getVulnerableStmts() const
Union of both statements of every candidate race pair (the slice targets).
Definition MTA.cpp:492
std::unique_ptr< MultiStageSlicer > multiStageSlicer
Definition MTA.h:255
std::set< const ICFGNode * > singleSlicedNodes
Definition MTA.h:259
std::unique_ptr< SingleSlicer > singleSlicer
Definition MTA.h:256
const SlicedICFGView * getICFG() const
Get SlicedICFGView.

◆ runOnModule()

void SlicedMTA::runOnModule ( SVFIR pag,
const ResolveIndirectCalls resolveIndirectCalls 
)

Run the slicing pipeline on a pre-built SVFIR.

Definition at line 998 of file MTA.cpp.

999{
1000 svfIr = pag;
1001
1002 SVFUtil::outs() << "[Config] Slicing: " << (Options::EnableSlicing() ? "enabled" : "disabled") << "\n";
1003
1005
1006 // The pre-analysis is context-insensitive in BOTH modes (the sliced run and
1007 // the FSAM baseline must share an identical pre-analysis substrate); the
1008 // main phase then runs at the configured context depth.
1014 if (!preOk)
1015 return;
1016
1018 {
1019 if (!runMTASlicingAndAnalysis()) return;
1020 if (!runPTASlicingAndAnalysis()) return;
1021 if (!runFinalRaceDetection()) return;
1022 }
1023 else
1024 {
1026 }
1027
1028 SVFUtil::outs() << "\n=== Analysis Complete ===\n";
1029}
void setValue(T v)
static const Option< bool > EnableSlicing
MTA slicing: slice before the FSAM main analysis (false = whole-program baseline),...
Definition Options.h:261
static Option< u32_t > MaxContextLen
Definition Options.h:81
u32_t mainCxtDepth
Definition MTA.h:245
void runWholeProgramDetection()
Definition MTA.cpp:941
bool runPTASlicingAndAnalysis()
Definition MTA.cpp:751
bool runFinalRaceDetection()
Definition MTA.cpp:872
bool runMTASlicingAndAnalysis()
Definition MTA.cpp:634
bool runPreAnalysis(const ResolveIndirectCalls &resolveIndirectCalls)
Definition MTA.cpp:527

◆ runPreAnalysis()

bool SlicedMTA::runPreAnalysis ( const ResolveIndirectCalls resolveIndirectCalls)
private

Definition at line 527 of file MTA.cpp.

528{
529 SVFUtil::outs() << "\n=== Pre-Analysis ===\n";
530
531 const bool dumpDot = Options::SlicedDumpDot();
532
533 // Step 1: Pointer Analysis. Inclusion-based Andersen's (more precise than
534 // Steensgaard's unification, so fewer spurious MHP/races and a smaller slice).
535 // The same Andersen instance (a singleton) is reused for the thread-aware
536 // VFG_pre and the main FSMPTA, so the whole pipeline shares one pre-analysis.
537 timePhase("Andersen's pointer analysis", [&]()
538 {
540 if (dumpDot)
541 {
542 preAnder->getConstraintGraph()->dump("original_consg");
543 preAnder->getCallGraph()->dump("original_tcg");
544 }
545 // Materialise resolved indirect calls into the PAG (LLVM-dependent step,
546 // injected by the caller), then update the ICFG with the resolved calls.
549 if (dumpDot)
550 svfIr->getICFG()->dump("original_icfg");
551 });
552 if (!checkAndReport("Pointer Analysis", preAnder != nullptr))
553 return false;
554
555 // Step 2: Build Thread Create Tree (the caller forces -max-cxt to 0 around the
556 // whole pre-analysis when slicing; see runOnModule).
557 timePhase("Create Thread Create Tree", [&]()
558 {
559 tct = std::make_unique<TCT>(preAnder);
560 });
561 if (dumpDot)
562 tct->dump("original_tct");
563
564 // A thread with several instances at the main depth must be multiforked in
565 // this depth-0 TCT, or the pre-analysis under-approximates the main phase.
566 timePhase("Mark truncation-merged multiforked threads", [&]()
567 {
572
573 // >1 instance at the main depth, or a single instance that is itself
574 // multiforked (merged just beyond the main depth), marks the fork site.
576 for (const auto& deepPair : deepTct)
577 if (const ICFGNode* forkSite = deepPair.second->getCxtThread().getThread())
578 {
580 if (deepPair.second->isMultiforked())
582 }
583
584 for (const auto& prePair : *tct)
585 {
586 const ICFGNode* forkSite = prePair.second->getCxtThread().getThread();
587 if (forkSite == nullptr)
588 continue;
590 if (fIt != forkSiteInstances.end() && fIt->second > 1)
591 prePair.second->setMultiforked(true);
592 }
593 });
594
595 // Step 3: Interleaving and Lock Analysis
596 timePhase("Run Interleaving and Lock Analysis", [&]()
597 {
598 mhp = std::make_unique<MHP>(tct.get());
599 mhp->analyze(svfIr->getICFG(), const_cast<CallGraph*>(svfIr->getCallGraph()));
600 lockAnalysis = std::make_unique<LockAnalysis>(tct.get());
601 lockAnalysis->analyze(svfIr->getICFG(), const_cast<CallGraph*>(svfIr->getCallGraph()));
602 });
603
604 // Step 4: Detect thread functions
605 timePhase("Detect Thread Functions", [&]()
606 {
608 });
610 {
611 SVFUtil::outs() << "[WARNING] No thread functions found\n";
612 return true; // Not an error, just no threads to analyze
613 }
614
615 // Step 5: Detect race statements
616 std::set<const SVFStmt*> vulnerableStatements;
617 timePhase("Detect Race Statements", [&]()
618 {
619 // Shared equivalence-class detector (the same one MTA::reportRaces uses).
621 svfIr, preAnder, mhp.get(), lockAnalysis.get(),
623 });
624 SVFUtil::outs() << "Found " << vulnerableStatements.size() << " vulnerable statements\n";
625 SVFUtil::outs() << "Found " << racePairs.size() << " race pairs\n";
626
627 // Step 6: build the thread-aware VFG once (substrate for slicing + main FS).
628 buildVFGPre();
629
630 return true;
631}
if(prebuffer< 0)
Definition cJSON.cpp:1269
ConstraintGraph * getConstraintGraph()
Get constraint graph.
Definition Andersen.h:122
static AndersenWaveDiff * createAndersenWaveDiff(SVFIR *_pag)
Create an singleton instance directly instead of invoking llvm pass manager.
Definition Andersen.h:408
void dump(const std::string &filename)
Dump the graph.
void dump(std::string name)
Dump graph into dot file.
Definition ConsG.cpp:595
void dump(const std::string &file, bool simple=false)
Dump graph into dot file.
Definition ICFG.cpp:412
void updateCallGraph(CallGraph *callgraph)
update ICFG for indirect calls
Definition ICFG.cpp:428
static bool hasThreadFunctions(CallGraph *callGraph)
Definition MTA.cpp:1039
const CallGraph * getCallGraph()
Get CG.
Definition SVFIR.h:248
void buildVFGPre()
Definition MTA.cpp:508
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition GeneralType.h:56

◆ runPTASlicingAndAnalysis()

bool SlicedMTA::runPTASlicingAndAnalysis ( )
private

Definition at line 751 of file MTA.cpp.

752{
753 SVFUtil::outs() << "\n=== PTA Slicing and Sliced Pointer Analysis ===\n";
754
756 {
757 SVFUtil::outs() << "[SKIP] No thread functions found in pre-analysis, skipping PTA slicing\n";
758 return true;
759 }
760 if (racePairs.empty())
761 {
762 SVFUtil::outs() << "[SKIP] No race pairs found in pre-analysis, skipping PTA slicing\n";
763 return true;
764 }
765
766 const bool dumpDot = Options::SlicedDumpDot();
767
768 std::set<const SVFStmt*> vulnerableStatements = getVulnerableStmts();
769
770 std::set<const ICFGNode*> ptaSlicedNodes;
771
773 {
774 // Single-pass baseline: reuse the unified V_Single computed in MTA slicing
775 // (no separate data-dependence slice); FSPTA runs on the same slice as ILA.
776 SVFUtil::outs() << "[Slicing Mode] Reusing unified slice (V_Single) for FSPTA\n";
778 SVFUtil::outs() << "PTA reuses unified slice: " << ptaSlicedNodes.size() << " nodes\n";
779 }
780 else
781 {
782 SVFUtil::outs() << "Using " << vulnerableStatements.size() << " vulnerable statements from pre-analysis\n";
783 SVFUtil::outs() << "Using " << racePairs.size() << " race pairs from pre-analysis\n";
784
785 // Stage 2 of the multi-stage slicer built during MTA slicing (it memoised
786 // the shared data-dependence closure over VFG_pre); construct only if
787 // absent (defensive: the ILA stage normally created it).
788 if (!multiStageSlicer)
789 multiStageSlicer = std::make_unique<MultiStageSlicer>(
790 svfIr, preAnder, mhp.get(), lockAnalysis.get(),
791 vfgPre /* paper-faithful data dependence over the thread-aware VFG */);
792
793 timePhase("PTA Slicing", [&]()
794 {
796 });
797 SVFUtil::outs() << "PTA sliced to " << ptaSlicedNodes.size() << " nodes\n";
798 }
799
800 // Step 4: Build PTA SlicedSVFIRView for pointer analysis. Its control flow is
801 // never walked (FSMPTA uses only isKeptNode), so skip bridged-edge construction.
802 timePhase("Build PTA Sliced View", [&]()
803 {
804 ptaSlicedView = std::make_unique<SlicedSVFIRView>(
806 /*buildBridged=*/false);
807 });
808 ptaSlicedView->dumpStats("PTA Sliced");
809
810 // Both slices are fixed and the main FSMPTA builds a fresh SVFG, so release
811 // VFG_pre and the slicers: the pre- and main graphs never coexist in memory.
812 multiStageSlicer.reset();
813 singleSlicer.reset();
814 vfgPreBuilder.reset();
815 vfgPre = nullptr;
816
817 // Step 5: Main FSMPTA phase (flow-sensitive FSAM over a thread-aware SVFG).
818 // Always rebuild the thread-aware value flow from the SLICED ILA: the sliced
819 // MHP/lock analysis is context-sensitive, whereas the pre-analysis VFG_pre was
820 // built context-insensitively (max-cxt forced to 0 for slicing). Reusing
821 // VFG_pre would decide the interference (thread-aware value-flow) edges from a
822 // context-insensitive ILA and over-approximate the FSAM points-to, so a fresh
823 // context-sensitive SVFG is required to preserve the result. [THREAD-VF]
824 // seeding keeps the queried interference witnesses in the slice.
825 if (slicedMhp == nullptr || slicedLockAnalysis == nullptr)
826 {
827 SVFUtil::outs() << "[Main FSMPTA] Sliced MHP/LockAnalysis unavailable\n";
828 return false;
829 }
830 SVFUtil::outs() << "[Main FSMPTA] Thread-aware value flow rebuilt from the SLICED ILA "
831 "(fresh context-sensitive SVFG; [THREAD-VF] load-bearing)\n";
832 timePhase("Flow-Sensitive FSAM Analysis", [&]()
833 {
834 // The sliced SVFG view: membership from the FSPTA ICFG slice; the SVFG
835 // itself is built inside the solver and bound afterwards (for dumping).
836 slicedSVFGView = std::make_unique<SlicedSVFGView>(ptaSlicedView->getICFG());
837 auto solver = std::make_unique<FSMPTA<const SlicedSVFGView*>>(
838 slicedMhp.get(), slicedLockAnalysis.get(), slicedSVFGView.get());
839 solver->analyze();
840 slicedSVFGView->setSVFG(solver->getSVFG());
841 if (dumpDot)
842 {
843 solver->getSVFG()->dump("mta_svfg");
844 slicedSVFGView->dump("sliced_svfg");
845 }
846 mtaFSMPTA = std::move(solver);
847 });
848
849 return true;
850}
std::unique_ptr< SlicedSVFIRView > ptaSlicedView
Definition MTA.h:261
std::unique_ptr< SlicedSVFGView > slicedSVFGView
Definition MTA.h:262

◆ runWholeProgramDetection()

void SlicedMTA::runWholeProgramDetection ( )
private

No-slice A/B baseline: run the FSAM detection on the whole program (no slicing), so its time and race set can be compared against the sliced run.

Definition at line 941 of file MTA.cpp.

942{
943 SVFUtil::outs() << "\n=== Whole-program FSAM Race Detection (no slicing) ===\n";
944 if (!hasThreadFunctions || racePairs.empty())
945 {
946 SVFUtil::outs() << "[SKIP] No thread functions / race pairs in pre-analysis\n";
947 return;
948 }
949
950 // Full "slice" = every ICFG node.
951 std::set<const ICFGNode*> allNodes;
952 for (ICFG::iterator it = svfIr->getICFG()->begin(), eit = svfIr->getICFG()->end(); it != eit; ++it)
953 allNodes.insert(it->second);
954 ptaSlicedView = std::make_unique<SlicedSVFIRView>(
956
957 timePhase("Whole-program Sliced TCT/MHP/Lock", [&]()
958 {
959 slicedTCT = std::make_unique<SlicedTCT>(preAnder, ptaSlicedView.get(), slicedMaxContextLen());
960 slicedMhp = std::make_unique<MHP>(slicedTCT.get());
961 const SlicedSVFIRView* pv = ptaSlicedView.get();
962 slicedMhp->analyze(pv->getICFG(), pv->getThreadCallGraph());
963 slicedLockAnalysis = std::make_unique<LockAnalysis>(slicedTCT.get());
964 slicedLockAnalysis->analyze(pv->getICFG(), pv->getThreadCallGraph());
965 });
966
967 timePhase("Whole-program Flow-Sensitive FSAM Analysis", [&]()
968 {
969 slicedSVFGView = std::make_unique<SlicedSVFGView>(ptaSlicedView->getICFG());
970 auto solver = std::make_unique<FSMPTA<const SlicedSVFGView*>>(
971 mhp.get(), lockAnalysis.get(), slicedSVFGView.get());
972 solver->analyze();
973 slicedSVFGView->setSVFG(solver->getSVFG());
974 mtaFSMPTA = std::move(solver);
975 });
976
977 std::set<RacePair> detectedPairs;
978 timePhase("Final Race Detection (whole program)", [&]()
979 {
981 getMainPTA(), slicedMhp.get(), slicedLockAnalysis.get());
982 });
983
984 std::set<const SVFStmt*> racyStmts;
985 for (const RacePair& rp : detectedPairs)
986 {
987 racyStmts.insert(rp.stmt1);
988 racyStmts.insert(rp.stmt2);
989 }
990
991 SVFUtil::outs() << "\n=== Race Detection Summary ===\n";
992 SVFUtil::outs() << "Race pairs (pre-analysis): " << racePairs.size() << "\n";
993 SVFUtil::outs() << "Race pairs (whole program): " << detectedPairs.size() << "\n";
994 SVFUtil::outs() << "Race statements (whole program): " << racyStmts.size() << "\n";
995 SVFUtil::outs() << "[MSLI-RQ] mode=FSAM alarms=" << racyStmts.size() << "\n";
996}

Member Data Documentation

◆ fullLockAnalysis

std::unique_ptr<LockAnalysis> SVF::SlicedMTA::fullLockAnalysis
private

Definition at line 270 of file MTA.h.

◆ fullLockTCT

std::unique_ptr<SlicedTCT> SVF::SlicedMTA::fullLockTCT
private

Definition at line 269 of file MTA.h.

◆ fullLockView

std::unique_ptr<SlicedSVFIRView> SVF::SlicedMTA::fullLockView
private

Definition at line 268 of file MTA.h.

◆ hasThreadFunctions

bool SVF::SlicedMTA::hasThreadFunctions = false
private

Definition at line 271 of file MTA.h.

◆ lockAnalysis

std::unique_ptr<LockAnalysis> SVF::SlicedMTA::lockAnalysis
private

Definition at line 248 of file MTA.h.

◆ mainCxtDepth

u32_t SVF::SlicedMTA::mainCxtDepth = 2
private

Definition at line 245 of file MTA.h.

◆ mhp

std::unique_ptr<MHP> SVF::SlicedMTA::mhp
private

Definition at line 247 of file MTA.h.

◆ mtaFSMPTA

std::unique_ptr<FlowSensitive> SVF::SlicedMTA::mtaFSMPTA
private

Definition at line 263 of file MTA.h.

◆ mtaSlicedView

std::unique_ptr<SlicedSVFIRView> SVF::SlicedMTA::mtaSlicedView
private

Definition at line 260 of file MTA.h.

◆ multiStageSlicer

std::unique_ptr<MultiStageSlicer> SVF::SlicedMTA::multiStageSlicer
private

Definition at line 255 of file MTA.h.

◆ preAnder

AndersenWaveDiff* SVF::SlicedMTA::preAnder = nullptr
private

Definition at line 252 of file MTA.h.

◆ ptaSlicedView

std::unique_ptr<SlicedSVFIRView> SVF::SlicedMTA::ptaSlicedView
private

Definition at line 261 of file MTA.h.

◆ racePairs

std::set<RacePair> SVF::SlicedMTA::racePairs
private

Definition at line 272 of file MTA.h.

◆ singleSlicedNodes

std::set<const ICFGNode*> SVF::SlicedMTA::singleSlicedNodes
private

Definition at line 259 of file MTA.h.

◆ singleSlicer

std::unique_ptr<SingleSlicer> SVF::SlicedMTA::singleSlicer
private

Definition at line 256 of file MTA.h.

◆ slicedLockAnalysis

std::unique_ptr<LockAnalysis> SVF::SlicedMTA::slicedLockAnalysis
private

Definition at line 266 of file MTA.h.

◆ slicedMhp

std::unique_ptr<MHP> SVF::SlicedMTA::slicedMhp
private

Definition at line 265 of file MTA.h.

◆ slicedSVFGView

std::unique_ptr<SlicedSVFGView> SVF::SlicedMTA::slicedSVFGView
private

Definition at line 262 of file MTA.h.

◆ slicedTCT

std::unique_ptr<SlicedTCT> SVF::SlicedMTA::slicedTCT
private

Definition at line 264 of file MTA.h.

◆ svfIr

SVFIR* SVF::SlicedMTA::svfIr = nullptr
private

Definition at line 242 of file MTA.h.

◆ tct

std::unique_ptr<TCT> SVF::SlicedMTA::tct
private

Definition at line 246 of file MTA.h.

◆ vfgPre

SVFG* SVF::SlicedMTA::vfgPre = nullptr
private

Definition at line 254 of file MTA.h.

◆ vfgPreBuilder

std::unique_ptr<MTASVFGBuilder> SVF::SlicedMTA::vfgPreBuilder
private

Definition at line 253 of file MTA.h.


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