56using namespace SVFUtil;
60 stat = std::make_unique<MTAStat>();
88 tct = std::make_unique<TCT>(pta);
89 tcg =
tct->getThreadCallGraph();
95 stat->performThreadCallGraphStat(
tcg);
96 stat->performTCTStat(
tct.get());
170 std::deque<NodeID> worklist;
173 worklist.push_back(pt);
176 while (!worklist.empty())
179 worklist.pop_front();
185 worklist.push_back(target);
193 worklist.push_back(
field);
215 if (stmt2 < stmt1) std::swap(stmt1, stmt2);
237 if (
const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(*it))
248 for (
const auto&
item : *callGraph)
252 for (
auto bbIt : *fun)
253 for (
const ICFGNode* node :
bbIt.second->getICFGNodeList())
260 if (
const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
265 else if (
const StoreStmt* store = SVFUtil::dyn_cast<StoreStmt>(stmt))
293 bool isStore, locked;
306 if (tid != other.tid)
307 return tid < other.tid;
308 if (isStore != other.isStore)
309 return isStore < other.isStore;
317 std::vector<RaceClass>
classes;
395 std::set<RacePair> racePairs;
416 auto start = std::chrono::steady_clock::now();
418 auto end = std::chrono::steady_clock::now();
419 double ms = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(end -
start).
count();
420 SVFUtil::outs() <<
"[TIMER] Phase: " <<
name <<
" - finished in " << std::fixed << std::setprecision(2) <<
ms <<
" ms";
422 SVFUtil::outs() <<
" (" << std::fixed << std::setprecision(2) << (
ms / 1000.0) <<
" s)";
494 std::set<const SVFStmt*>
v;
497 v.insert(
pair.stmt1);
498 v.insert(
pair.stmt2);
510 timePhase(
"Build thread-aware VFG_pre", [&]()
517 tcg->updateCallGraph(preAnder);
518 tcg->updateJoinEdge(preAnder);
537 timePhase(
"Andersen's pointer analysis", [&]()
557 timePhase(
"Create Thread Create Tree", [&]()
562 tct->dump(
"original_tct");
566 timePhase(
"Mark truncation-merged multiforked threads", [&]()
580 if (
deepPair.second->isMultiforked())
591 prePair.second->setMultiforked(
true);
596 timePhase(
"Run Interleaving and Lock Analysis", [&]()
598 mhp = std::make_unique<MHP>(
tct.get());
605 timePhase(
"Detect Thread Functions", [&]()
617 timePhase(
"Detect Race Statements", [&]()
640 SVFUtil::outs() <<
"[SKIP] No race pairs found in pre-analysis\n";
656 SVFUtil::outs() <<
"[Slicing Mode] Single unified slice (V_Single) for ILA + FSPTA\n";
669 SVFUtil::outs() <<
"[Slicing Mode] Differential slices (separate ILA + FSPTA)\n";
680 const std::set<const SVFGNode*>&
retained =
685 for (
const auto& entry :
vfgPreBuilder->getThreadVFQueryMap())
699 <<
" ILA slicing sources from VFG_pre value-flow construction\n";
721 if (
slicedView->getThreadCallGraph() !=
nullptr)
722 slicedView->getThreadCallGraph()->dump(
"sliced_tcg");
727 timePhase(
"Sliced Thread Create Tree", [&]()
730 SVFUtil::outs() <<
"[SlicedTCT] Using max context length: " << maxContextLen
731 <<
" (from -max-cxt)\n";
739 timePhase(
"Sliced Interleaving and Lock Analysis", [&]()
753 SVFUtil::outs() <<
"\n=== PTA Slicing and Sliced Pointer Analysis ===\n";
757 SVFUtil::outs() <<
"[SKIP] No thread functions found in pre-analysis, skipping PTA slicing\n";
762 SVFUtil::outs() <<
"[SKIP] No race pairs found in pre-analysis, skipping PTA slicing\n";
776 SVFUtil::outs() <<
"[Slicing Mode] Reusing unified slice (V_Single) for FSPTA\n";
827 SVFUtil::outs() <<
"[Main FSMPTA] Sliced MHP/LockAnalysis unavailable\n";
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", [&]()
837 auto solver = std::make_unique<FSMPTA<const SlicedSVFGView*>>(
843 solver->getSVFG()->dump(
"mta_svfg");
888 SVFUtil::outs() <<
"[SKIP] Sliced MHP or LockAnalysis not available\n";
893 SVFUtil::outs() <<
"[SKIP] Main flow-sensitive pointer analysis not available\n";
930 SVFUtil::outs() <<
"\nNo race pairs detected in sliced graph.\n";
943 SVFUtil::outs() <<
"\n=== Whole-program FSAM Race Detection (no slicing) ===\n";
946 SVFUtil::outs() <<
"[SKIP] No thread functions / race pairs in pre-analysis\n";
957 timePhase(
"Whole-program Sliced TCT/MHP/Lock", [&]()
967 timePhase(
"Whole-program Flow-Sensitive FSAM Analysis", [&]()
970 auto solver = std::make_unique<FSMPTA<const SlicedSVFGView*>>(
978 timePhase(
"Final Race Detection (whole program)", [&]()
1047 edge->getDstNode()->getFunction() !=
nullptr)
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
ConstraintGraph * getConstraintGraph()
Get constraint graph.
static AndersenWaveDiff * createAndersenWaveDiff(SVFIR *_pag)
Create an singleton instance directly instead of invoking llvm pass manager.
static void releaseAndersenWaveDiff()
const PointsTo & getPts(NodeID id) override
void dump(const std::string &filename)
Dump the graph.
void dump(std::string name)
Dump graph into dot file.
bool hasBasicBlock() const
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
const GEdgeSetTy & getOutEdges() const
ICFGNodeIDToNodeMapTy::iterator iterator
void dump(const std::string &file, bool simple=false)
Dump graph into dot file.
void updateCallGraph(CallGraph *callgraph)
update ICFG for indirect calls
GlobalICFGNode * getGlobalICFGNode() const
void analyze(ICFGGraph icfg, CGGraph cg)
bool isProtectedByCommonLock(const ICFGNode *i1, const ICFGNode *i2)
void analyze(ICFGGraph icfg, CGGraph cg)
const NodeBS & getInterleavingThreads(const CxtThreadStmt &cts)
Get interleaving thread for statement inst.
const CxtThreadStmtSet & getThreadStmtSet(const ICFGNode *inst) const
Get/has ThreadStmt.
bool hasThreadStmtSet(const ICFGNode *inst) const
TCT * getTCT() const
Get Thread Creation Tree.
static u32_t numOfNewSVFGEdges
Number of thread-aware (interference) SVFG edges added.
std::pair< const StmtSVFGNode *, const StmtSVFGNode * > ThreadVFEdge
virtual LockAnalysis * computeLocksets(TCT *tct)
Compute locksets.
static std::set< const SVFStmt * > detectRace(SVFIR *svfIr, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, CallGraph *callGraph, std::set< RacePair > &outRacePairs)
std::unique_ptr< TCT > tct
static bool occurrencesRace(MHP *mhp, const RaceOccurrence &first, const RaceOccurrence &second)
Helpers for the equivalence-class race detector.
virtual ~MTA()
Destructor.
static PointsTo getGlobalObjectVariables(SVFIR *svfIr)
Escape/points-to helpers for the shared detector.
virtual MHP * computeMHP(TCT *tct)
Compute MHP.
static void commitRacePair(std::set< RacePair > &out, const RaceOccurrence &first, const RaceOccurrence &second)
std::unique_ptr< MTAStat > stat
static bool hasThreadFunctions(CallGraph *callGraph)
virtual bool runOnModule(SVFIR *module)
We start the pass here.
virtual void reportRaces()
Run the shared detector and print a race report.
static PointsTo getPointsToClosure(AndersenBase *pta, const PointsTo &pts)
static const Option< bool > SlicedDumpDot
MTA slicing: dump intermediate dot graphs (ICFG/TCG/SVFG/...), Default: false.
static const Option< bool > EnableSlicing
MTA slicing: slice before the FSAM main analysis (false = whole-program baseline),...
static const Option< bool > DumpMTAGraphs
MTA: dump the pointer-analysis and thread call graphs (ptacg/tcg.dot), Default: false.
static const Option< bool > SlicingSingle
MTA slicing: one unified slice for ILA + FSPTA (single-pass baseline), Default: false.
static Option< u32_t > MaxContextLen
bool printStat()
Whether print statistics.
NodeID getBaseObjVarID(NodeID id)
CallGraph * getCallGraph() const
Return call graph.
virtual const NodeBS & getAllFieldsObjVars(NodeID id)
void set(u32_t n)
Inserts n in the set.
u32_t getSVFGNodeNum() const
Return total SVFG node number.
static void releaseSVFIR()
SVFStmtList & getSVFStmtList(const ICFGNode *inst)
Given an instruction, get all its PAGEdges.
const BaseObjVar * getBaseObject(NodeID id) const
const CallGraph * getCallGraph()
Get CG.
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
std::unique_ptr< LockAnalysis > lockAnalysis
std::set< RacePair > racePairs
std::unique_ptr< SlicedSVFIRView > fullLockView
void runOnModule(SVFIR *pag, const ResolveIndirectCalls &resolveIndirectCalls)
Run the slicing pipeline on a pre-built SVFIR.
std::unique_ptr< FlowSensitive > mtaFSMPTA
void runWholeProgramDetection()
bool runPTASlicingAndAnalysis()
bool runFinalRaceDetection()
std::set< const SVFStmt * > getVulnerableStmts() const
Union of both statements of every candidate race pair (the slice targets).
std::set< RacePair > detectRacePairsOnSlicedGraph(BVDataPTAImpl *slicedPTA, MHP *slicedMHP, LockAnalysis *slicedLockAnalysis)
Re-check the candidate race pairs on the sliced graph using FSAM points-to.
std::unique_ptr< LockAnalysis > slicedLockAnalysis
std::unique_ptr< LockAnalysis > fullLockAnalysis
std::unique_ptr< SlicedSVFIRView > mtaSlicedView
std::unique_ptr< SlicedTCT > fullLockTCT
bool runMTASlicingAndAnalysis()
std::unique_ptr< MultiStageSlicer > multiStageSlicer
AndersenWaveDiff * preAnder
std::unique_ptr< MHP > slicedMhp
std::set< const ICFGNode * > singleSlicedNodes
std::unique_ptr< SingleSlicer > singleSlicer
std::unique_ptr< SlicedSVFIRView > ptaSlicedView
std::unique_ptr< TCT > tct
std::unique_ptr< SlicedSVFGView > slicedSVFGView
std::function< void(CallGraph *)> ResolveIndirectCalls
std::unique_ptr< SlicedTCT > slicedTCT
std::unique_ptr< MHP > mhp
LockAnalysis * buildFullLockAnalysis()
bool runPreAnalysis(const ResolveIndirectCalls &resolveIndirectCalls)
std::unique_ptr< MTASVFGBuilder > vfgPreBuilder
BVDataPTAImpl * getMainPTA() const
const SlicedICFGView * getICFG() const
Get SlicedICFGView.
bool isMultiforked() const
TCTNode * getTCTNode(NodeID id) const
Get TCT node.
CallSiteSet::const_iterator forksitesEnd() const
CallSiteSet::const_iterator forksitesBegin() const
Fork sites iterators.
ThreadAPI * getThreadAPI() const
Thread API.
std::string bugMsg1(const std::string &msg)
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
bool cmpNodeBS(const NodeBS &lpts, const NodeBS &rpts)
std::ostream & errs()
Overwrite llvm::errs()
std::ostream & outs()
Overwrite llvm::outs()
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
llvm::IRBuilder IRBuilder
IntervalValue operator<(const IntervalValue &lhs, const IntervalValue &rhs)
One occurrence of a memory access under one thread instance.
A race pair: two statements that may race.