51using namespace SVFUtil;
55 stat = std::make_unique<MTAStat>();
81 tcg =
tct->getThreadCallGraph();
87 stat->performThreadCallGraphStat(
tcg);
88 stat->performTCTStat(
tct.get());
128 return mhp.release();
143 SVFUtil::dyn_cast<GlobalValVar>(
addrStmt->getLHSVar());
165 std::deque<NodeID> worklist;
168 worklist.push_back(pt);
171 while (!worklist.empty())
174 worklist.pop_front();
180 worklist.push_back(target);
188 worklist.push_back(
field);
236 for (
const auto&
item : *callGraph)
241 for (
auto bbIt : *fun)
242 for (
const ICFGNode* node :
bbIt.second->getICFGNodeList())
252 if (
const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
258 SVFUtil::dyn_cast<StoreStmt>(stmt))
293 std::vector<RaceClass>
classes;
321 const std::vector<RaceClass>&
classes,
354 const std::vector<size_t>& members =
firstClass.members;
389 if (
const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(*it))
398 svfir, pta,
mhp, lockAnalysis, callGraph,
escSet,
406 const std::vector<RaceClass>
classes =
430 std::set<RacePair> racePairs;
473 std::set<const ICFGNode*>
nodes;
479 SVFUtil::dyn_cast<StmtVFGNode>(svfg->
getSVFGNode(
id)))
480 if (
stmtNode->getICFGNode() !=
nullptr)
487 const std::set<const ICFGNode*>& icfgNodes)
491 for (
const ICFGNode* node : icfgNodes)
493 if (node->getFun() !=
nullptr)
495 statements.insert(node->getSVFStmts().begin(), node->getSVFStmts().end());
499 SVFUtil::outs() <<
" ICFG nodes: " << icfgNodes.size() <<
"\n";
512 const std::string fields[] =
514 std::to_string(
statement->getEdgeKind()),
516 block ==
nullptr ? std::string() :
block->getName(),
518 value ==
nullptr ? std::string() : value->
getName(),
519 value ==
nullptr ? std::string() : value->
getSourceLoc(),
523 for (
const std::string&
field : fields)
525 key += std::to_string(
field.size());
534 for (
unsigned char byte : value)
537 digest *= 1099511628211ULL;
540 digest *= 1099511628211ULL;
544 const std::set<RacePair>&
pairs)
563 std::set<std::pair<std::string, std::string>>
pairKeys;
575 updateDigest(
digests.pair, pair.first);
576 updateDigest(
digests.pair, pair.second);
626 <<
" nodes; [Pre-TVF] "
628 <<
" interference edges\n";
653 tct->dump(
"original_tct");
669 if (
deepPair.second->isMultiforked())
680 prePair.second->setMultiforked(
true);
732 SVFUtil::outs() <<
"[SKIP] No race candidates; VFG_pre is unnecessary\n";
744 SVFUtil::outs() <<
"[SKIP] No race pairs found in pre-analysis\n";
760 SVFUtil::outs() <<
"[Slicing Mode] Single unified slice (V_Single) for ILA + FSPTA\n";
778 SVFUtil::outs() <<
"[Slicing Mode] Differential slices (separate ILA + FSPTA)\n";
801 SVFUtil::errs() <<
"[ERROR] Failed to execution-close VFG'_pre\n";
807 <<
" dependency nodes, "
809 <<
" execution-closure nodes\n";
820 edge.first->getId(),
edge.second->getId());
861 if (
slicedView->getThreadCallGraph() !=
nullptr)
862 slicedView->getThreadCallGraph()->dump(
"sliced_tcg");
906 SVFUtil::outs() <<
"\n=== PTA Slicing and Sliced Pointer Analysis ===\n";
910 SVFUtil::outs() <<
"[SKIP] No thread functions found in pre-analysis, skipping PTA slicing\n";
915 SVFUtil::outs() <<
"[SKIP] No race pairs found in pre-analysis, skipping PTA slicing\n";
929 SVFUtil::outs() <<
"[Main FSMPTA] Base SVFG or sliced ILA unavailable\n";
937 SVFUtil::outs() <<
"[Slicing Mode] Reusing unified slice (V_Single) for FSPTA\n";
944 SVFUtil::errs() <<
"[ERROR] Single-slice FSMPTA execution closure failed\n";
952 <<
" execution-closure SVFG nodes\n";
974 SVFUtil::errs() <<
"[ERROR] Differential PTA slicing requires the ILA slicer\n";
982 SVFUtil::errs() <<
"[ERROR] Execution-closed VFG'_pre is unavailable\n";
1001 <<
" interference edges over VFG'_pre\n";
1015 SVFUtil::errs() <<
"[ERROR] Initial FSPTA slice escapes VFG'_pre by "
1031 SVFUtil::errs() <<
"[ERROR] FSMPTA execution closure escapes VFG'_pre by "
1045 <<
" SVFG nodes (final / pre-candidate / execution-closed), "
1047 <<
" execution-closure solve nodes\n";
1062 SVFUtil::outs() <<
"[Main FSMPTA] Reusing BaseSVFG; Main-TVF comes from the sliced main ILA\n";
1065 SVFUtil::errs() <<
"[ERROR] Unsupported FSMPTA mapping/clustering configuration\n";
1072 auto solver = std::make_unique<FSMPTA<const SlicedSVFGView*>>(
1077 solver->getSVFG()->dump(
"mta_svfg");
1106 <<
" alarm-digest=" <<
digests.alarm
1107 <<
" pair-digest=" <<
digests.pair <<
"\n";
1109 SVFUtil::outs() <<
"\nNo race pairs detected in sliced graph.\n";
1114 SVFUtil::errs() <<
"[ERROR] MTA sliced view not available\n";
1119 SVFUtil::errs() <<
"[ERROR] Sliced MHP or LockAnalysis not available\n";
1124 SVFUtil::errs() <<
"[ERROR] Main flow-sensitive pointer analysis not available\n";
1157 <<
" alarm-digest=" <<
digests.alarm
1158 <<
" pair-digest=" <<
digests.pair <<
"\n";
1168 SVFUtil::outs() <<
"\nNo race pairs detected in sliced graph.\n";
1179 SVFUtil::outs() <<
"\n=== Whole-program FSAM Race Detection (no slicing) ===\n";
1182 SVFUtil::outs() <<
"[SKIP] No thread functions / race pairs in pre-analysis\n";
1191 std::set<const ICFGNode*>
allNodes;
1209 "Whole-program ILA: construct MHP/ForkJoin");
1221 std::make_unique<LockAnalysis>(
slicedTCT.get());
1236 <<
" interference edges over the whole BaseSVFG\n";
1240 auto solver = std::make_unique<FSMPTA<SVFG*>>(
1270 <<
" alarm-digest=" <<
digests.alarm
1271 <<
" pair-digest=" <<
digests.pair <<
"\n";
1278 if (
svfir !=
nullptr || pag ==
nullptr || preAnalysis.
getPAG() != pag)
1280 SVFUtil::errs() <<
"[ERROR] SlicedMTA is single-use and requires a "
1281 <<
"matching SVFIR and Andersen pre-analysis\n";
1335 edge->getDstNode()->getFunction() !=
nullptr)
1370 SVFUtil::dyn_cast<LoadStmt>(pair.stmt1))
1375 SVFUtil::dyn_cast<StoreStmt>(pair.stmt1))
1385 SVFUtil::dyn_cast<LoadStmt>(pair.stmt2))
1390 SVFUtil::dyn_cast<StoreStmt>(pair.stmt2))
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
static AndersenWaveDiff * createAndersenWaveDiff(SVFIR *_pag)
Create an singleton instance directly instead of invoking llvm pass manager.
const PointsTo & getPts(NodeID id) override
void dump(const std::string &filename)
Dump the graph.
static NodeBS buildExecutionDependencyClosure(SVFG *graph, AndersenBase *preAnalysis, NodeBS dependencyNodes)
bool hasBasicBlock() const
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
const GEdgeSetTy & getOutEdges() const
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
ICFGNodeIDToNodeMapTy::iterator iterator
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 NodeThreadSummary * getThreadSummary(const ICFGNode *inst) const
static std::unique_ptr< MHP > create(TCT *t, ICFGGraph icfg, CGGraph cg, StateRepresentation representation=StateRepresentation::MaterializedContexts)
Construct MHP and initialize its graph-dependent ForkJoinAnalysis.
TCT * getTCT() const
Get Thread Creation Tree.
static ThreadVFBuildConfig wholeProgram()
static ThreadVFBuildConfig mainPhase(const SlicedSVFGView &scope, const ThreadVFCandidateList *candidates=nullptr)
std::pair< const StmtSVFGNode *, const StmtSVFGNode * > ThreadVFEdge
@ SlicingOnly
Build unlabelled connectivity for VFG_pre slicing.
static void emitRacePairs(MHP *mhp, LockAnalysis *lockAnalysis, const std::vector< RaceOccurrence > &occurrences, const std::vector< RaceClass > &classes, std::set< RacePair > &outRacePairs)
virtual LockAnalysis * computeLocksets(TCT *tct)
Compute locksets.
static std::vector< RaceClass > buildRaceClasses(const std::vector< RaceOccurrence > &occurrences, const std::vector< size_t > &occurrenceIndices)
std::unique_ptr< TCT > tct
static bool occurrencesRace(MHP *mhp, const RaceOccurrence &first, const RaceOccurrence &second)
virtual ~MTA()
Destructor.
static PointsTo getGlobalObjectVariables(SVFIR *svfir)
Escape/points-to helpers for the shared detector.
Map< NodeID, std::vector< size_t > > ObjectToRaceOccurrences
virtual MHP * computeMHP(TCT *tct)
Compute MHP.
static void commitRacePair(std::set< RacePair > &out, const RaceOccurrence &first, const RaceOccurrence &second)
static void collectRaceOccurrences(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, CallGraph *callGraph, const PointsTo &escapedObjects, std::vector< RaceOccurrence > &occurrences, ObjectToRaceOccurrences &objectToOccurrences)
Helpers for the equivalence-class race detector.
std::unique_ptr< MTAStat > stat
static std::set< const SVFStmt * > detectRace(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, CallGraph *callGraph, std::set< RacePair > &outRacePairs)
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)
Carries around command line options.
static const Option< bool > MTAEnableSlicing
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 > MTASingleStageSlicing
MTA slicing: one unified slice for ILA + FSPTA (single-pass baseline), Default: false.
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.
bool hasSVFGNode(NodeID id) const
Whether has the SVFGNode.
SVFGNode * getSVFGNode(NodeID id) const
Get a SVFG node.
u32_t getSVFGNodeNum() const
Return total SVFG node number.
SVFStmtList & getSVFStmtList(const ICFGNode *inst)
Given an instruction, get all its PAGEdges.
bool hasSVFStmtList(const ICFGNode *inst) const
Whether this instruction has SVFIR Edge.
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.
const bool hasLLVMValue() const
virtual const std::string getSourceLoc() const
virtual const std::string & getName() const
const std::string valueOnlyToString() const
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
NodeBS preCandidateSolveNodeIds
bool runWholeProgramDetection()
static RaceDigests computeRaceDigests(const std::set< RacePair > &pairs)
std::unique_ptr< LockAnalysis > lockAnalysis
std::set< RacePair > racePairs
AndersenWaveDiff * preAndersen
std::unique_ptr< MTASVFGBuilder > preSVFGBuilder
static std::string raceStatementKey(const SVFStmt *statement)
bool runPTASlicingAndAnalysis()
MTASVFGBuilder::ThreadVFCandidateList selectedThreadVFCandidates
bool runFinalRaceDetection()
std::set< const SVFStmt * > getVulnerableStmts() const
Union of both statements of every candidate race pair (the slice targets).
ThreadCallGraph * threadCallGraph
std::unique_ptr< LockAnalysis > slicedLockAnalysis
std::unique_ptr< SlicedSVFIRView > mtaSlicedView
std::set< RacePair > detectRacePairsOnSlicedGraph(const std::set< RacePair > &preAnalysisRacePairs, BVDataPTAImpl *slicedPTA, MHP *slicedMHP, LockAnalysis *slicedLockAnalysis)
Refine the pre-analysis candidate pairs with main-phase ILA and FSAM.
bool runMTASlicingAndAnalysis()
std::unique_ptr< MultiStageSlicer > multiStageSlicer
static std::set< const ICFGNode * > collectICFGNodes(SVFG *svfg, const NodeBS &svfgNodeIds)
static void updateDigest(u64_t &digest, const std::string &value)
std::set< const ICFGNode * > singleSlicedNodes
std::unique_ptr< SingleSlicer > singleSlicer
void buildPreAnalysisSVFG()
static void reportPTASliceStatistics(const std::set< const ICFGNode * > &icfgNodes)
NodeBS singleSlicedSVFGNodeIds
bool runOnModule(SVFIR *pag, AndersenWaveDiff &preAnalysis)
Run the slicing pipeline with its prepared Andersen pre-analysis.
std::unique_ptr< SlicedSVFIRView > ptaSlicedView
std::unique_ptr< TCT > tct
std::unique_ptr< SlicedSVFGView > slicedSVFGView
std::unique_ptr< SlicedTCT > slicedTCT
std::unique_ptr< MHP > mhp
std::unique_ptr< MHP > slicedMHP
static void reportOriginalStatistics(SVFIR *svfir)
Pipeline utilities shared by the sliced and whole-program paths.
BVDataPTAImpl * getMainPTA() const
std::unique_ptr< FlowSensitive > mainFSMPTA
const SlicedICFGView * getICFG() const
Get SlicedICFGView.
static std::unique_ptr< SlicedTCT > create(PointerAnalysis &pointerAnalysis, const SlicedSVFIRView &slicedView, u32_t contextLimit)
bool test(unsigned Idx) const
bool intersectWithComplement(const SparseBitVector &RHS)
bool isMultiforked() const
TCTNode * getTCTNode(NodeID id) const
Get TCT node.
static std::unique_ptr< TCT > create(PointerAnalysis *p)
Construct and build a TCT with the command-line context bound.
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
iter_range< typename GenericGraphTraits< GraphType >::nodes_iterator > nodes(const GraphType &G)
bool operator<(const RaceClassKey &other) const
const NodeBS * interleaving
One occurrence of a memory access under one thread instance.
A race pair: two statements that may race.