Static Value-Flow Analysis
Loading...
Searching...
No Matches
MTA.cpp
Go to the documentation of this file.
1//===- MTA.cpp -- Analysis of multithreaded programs-------------//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22
23
24/*
25 * MTA.cpp
26 *
27 * Created on: May 14, 2014
28 * Author: Yulei Sui, Peng Di
29 *
30 * This file also implements SlicedMTA, the multi-stage on-demand program
31 * slicing pipeline (MSli) introduced in "Multi-Stage On-Demand Program Slicing
32 * for Modular Analysis of Multi-Threaded Programs" (ISSTA 2026).
33 */
34
35#include "Util/Options.h"
36#include "MTA/MTA.h"
37#include "MTA/MHP.h"
38#include "MTA/TCT.h"
39#include "MTA/LockAnalysis.h"
40#include "MTA/MTAStat.h"
41#include "MTA/MTASVFGBuilder.h"
42#include "MTA/FSMPTA.h"
43#include "MTA/MTASlicer.h"
44#include "WPA/Andersen.h"
46#include "Util/SVFUtil.h"
47#include <chrono>
48#include <deque>
49#include <iomanip>
50#include <set>
51#include <string>
52#include <utility>
53#include <vector>
54
55using namespace SVF;
56using namespace SVFUtil;
57
58MTA::MTA() : tcg(nullptr), tct(nullptr), mhp(nullptr), lsa(nullptr)
59{
60 stat = std::make_unique<MTAStat>();
61}
62
64{
65 if (tcg)
66 delete tcg;
67
68 delete mhp;
69 delete lsa;
70}
71
76{
77 DBOUT(DGENERAL, outs() << pasMsg("MTA analysis\n"));
78 DBOUT(DMTA, outs() << pasMsg("MTA analysis\n"));
79
82 pta->getCallGraph()->dump("ptacg");
83 pag->getICFG()->updateCallGraph(pta->getCallGraph());
84
85 DBOUT(DGENERAL, outs() << pasMsg("Build TCT\n"));
86 DBOUT(DMTA, outs() << pasMsg("Build TCT\n"));
87 DOTIMESTAT(double tctStart = stat->getClk());
88 tct = std::make_unique<TCT>(pta);
89 tcg = tct->getThreadCallGraph();
90 DOTIMESTAT(double tctEnd = stat->getClk());
91 DOTIMESTAT(stat->TCTTime += (tctEnd - tctStart) / TIMEINTERVAL);
92
93 if (pta->printStat())
94 {
95 stat->performThreadCallGraphStat(tcg);
96 stat->performTCTStat(tct.get());
97 }
98
100 tcg->dump("tcg");
101
102 mhp = computeMHP(tct.get());
103 lsa = computeLocksets(tct.get());
104
105 // MTA's only client is race detection; always report.
106 reportRaces();
107
108 return false;
109}
110
115{
117 lsa->analyze(PAG::getPAG()->getICFG(), const_cast<CallGraph*>(PAG::getPAG()->getCallGraph()));
118 return lsa;
119}
120
122{
123 DBOUT(DGENERAL, outs() << pasMsg("MHP analysis\n"));
124 DBOUT(DMTA, outs() << pasMsg("MHP analysis\n"));
125
126 DOTIMESTAT(double mhpStart = stat->getClk());
127 MHP* mhp = new MHP(tct);
128 mhp->analyze(PAG::getPAG()->getICFG(), const_cast<CallGraph*>(PAG::getPAG()->getCallGraph()));
129 DOTIMESTAT(double mhpEnd = stat->getClk());
130 DOTIMESTAT(stat->MHPTime += (mhpEnd - mhpStart) / TIMEINTERVAL);
131
132 DBOUT(DGENERAL, outs() << pasMsg("MHP analysis finish\n"));
133 DBOUT(DMTA, outs() << pasMsg("MHP analysis finish\n"));
134 return mhp;
135}
136
137// Collect the global objects (addr-taken global vars at the global ICFG node).
139{
142
143 for (const SVFStmt* stmt : globalICFGNode->getSVFStmts())
144 {
145 const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt);
146 if (addrStmt != nullptr)
147 {
148 const GlobalValVar* globalVar = SVFUtil::dyn_cast<GlobalValVar>(addrStmt->getLHSVar());
149 if (globalVar != nullptr)
150 {
151 globalObjVars.set(addrStmt->getRHSVarID());
152 }
153 }
154 }
155
156 return globalObjVars;
157}
158
159// Transitive closure of a set under TWO relations: points-to (an object -> the
160// objects it points to) and containment (a base object -> its field sub-objects).
161// The containment step is essential for field sensitivity: a field-sensitive
162// access resolves to a GepObjVar that is NOT reachable from its base by points-to
163// edges, so without it a race on a (non-zero-offset) struct field -- or on an
164// object reached through a struct's pointer field -- would be screened out of the
165// escape set as "not shared".
167{
168 SVFIR* pag = pta->getPAG();
170 std::deque<NodeID> worklist;
171 for (NodeID pt : pts)
172 {
173 worklist.push_back(pt);
174 }
175
176 while (!worklist.empty())
177 {
178 NodeID obj = worklist.front();
179 worklist.pop_front();
180
181 for (NodeID target : pta->getPts(obj)) // points-to
182 if (!ptsClosure.test(target))
183 {
184 ptsClosure.set(target);
185 worklist.push_back(target);
186 }
187
188 if (pag->getBaseObject(obj) != nullptr) // containment (object nodes only)
190 if (!ptsClosure.test(field))
191 {
192 ptsClosure.set(field);
193 worklist.push_back(field);
194 }
195 }
196
197 return ptsClosure;
198}
199
200// C3: distinct threads must mutually interleave; the same thread self-races only
201// when it is multiforked (more than one dynamic instance).
203{
204 if (first.tid != second.tid)
205 return first.interleav.test(second.tid) && second.interleav.test(first.tid);
206 return mhp->getTCT()->getTCTNode(first.tid)->isMultiforked();
207}
208
209// Record one order-normalised racing statement pair.
210void MTA::commitRacePair(std::set<RacePair>& out,
212{
213 const SVFStmt* stmt1 = first.stmt;
214 const SVFStmt* stmt2 = second.stmt;
215 if (stmt2 < stmt1) std::swap(stmt1, stmt2);
216 out.insert(RacePair(stmt1, stmt2));
217}
218
219// Equivalence-class race detector: screen accesses, bucket by object, collapse
220// occurrences sharing the race predicate's inputs into classes, then pair classes.
221std::set<const SVFStmt*> MTA::detectRace(
222 SVFIR* svfIr, AndersenBase* pta, MHP* mhp, LockAnalysis* lockAnalysis,
223 CallGraph* callGraph,
224 std::set<RacePair>& outRacePairs)
225{
226
227 std::set<const SVFStmt*> bugStmts;
228
229 // Escape set: objects shared across threads. Seed from globals + the actual
230 // argument at each fork site (the spawner's value, which a spawnee-formal
231 // closure can miss), then take the transitive points-to closure.
233 if (ThreadCallGraph* tcg = SVFUtil::dyn_cast<ThreadCallGraph>(callGraph))
234 {
235 const ThreadAPI* tapi = tcg->getThreadAPI();
236 for (auto it = tcg->forksitesBegin(), eit = tcg->forksitesEnd(); it != eit; ++it)
237 if (const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(*it))
238 if (const ValVar* actual = tapi->getActualParmAtForkSite(cs))
239 seed |= pta->getPts(actual->getId());
240 }
242
243 // One occurrence per (statement, thread instance), indexed by object (C1 ->
244 // "same bucket") as collected, so the points-to set is consumed straight into
245 // the buckets and never stored per occurrence.
246 std::vector<RaceOccurrence> occurrences;
248 for (const auto& item : *callGraph)
249 {
250 const FunObjVar* fun = item.second->getFunction();
251 if (!fun || !fun->hasBasicBlock()) continue;
252 for (auto bbIt : *fun)
253 for (const ICFGNode* node : bbIt.second->getICFGNodeList())
254 {
255 if (!mhp->hasThreadStmtSet(node)) continue; // screen 1: concurrent?
256 for (const SVFStmt* stmt : svfIr->getSVFStmtList(node))
257 {
259 bool isStore;
260 if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
261 {
262 accessedPtr = load->getRHSVarID();
263 isStore = false;
264 }
265 else if (const StoreStmt* store = SVFUtil::dyn_cast<StoreStmt>(stmt))
266 {
267 accessedPtr = store->getLHSVarID();
268 isStore = true;
269 }
270 else continue;
272 objects &= escSet; // screen 2: touches shared object?
273 if (objects.empty()) continue;
274 bool locked = lockAnalysis->isProtectedByCommonLock(node, node);
275 const size_t firstNew = occurrences.size();
276 for (const CxtThreadStmt& threadStmt : mhp->getThreadStmtSet(node))
277 occurrences.push_back({stmt, node, isStore, threadStmt.getTid(),
279 for (NodeID object : objects)
280 for (size_t k = firstNew; k < occurrences.size(); ++k)
282 }
283 }
284 }
285
286 // Within each object, occurrences sharing the race predicate's inputs (tid,
287 // interleaving, isStore, lock sig) race the same partners, so collapse into a
288 // class and judge C2/C3/C4 once per class pair -- O(classes^2) not O(occ^2).
289 for (const auto& objectAndOccs : objectToOccurrences)
290 {
291 struct RaceClass
292 {
293 bool isStore, locked;
294 size_t rep;
295 std::vector<size_t> members;
296 };
297 struct RaceKey
298 {
299 NodeID tid;
300 bool isStore;
301 NodeBS interleav;
302 const ICFGNode* lockNode;
303
304 bool operator<(const RaceKey& other) const
305 {
306 if (tid != other.tid)
307 return tid < other.tid;
308 if (isStore != other.isStore)
309 return isStore < other.isStore;
310 if (SVFUtil::cmpNodeBS(interleav, other.interleav))
311 return true;
312 if (SVFUtil::cmpNodeBS(other.interleav, interleav))
313 return false;
314 return lockNode < other.lockNode;
315 }
316 };
317 std::vector<RaceClass> classes;
319 for (size_t occIdx : objectAndOccs.second)
320 {
321 const RaceOccurrence& occ = occurrences[occIdx];
322 RaceKey key{occ.tid, occ.isStore, occ.interleav, occ.locked ? occ.node : nullptr};
323 auto found = keyToClass.find(key);
324 if (found == keyToClass.end())
325 {
326 keyToClass[key] = classes.size();
327 classes.push_back({occ.isStore, occ.locked, occIdx, {occIdx}});
328 }
329 else
330 classes[found->second].members.push_back(occIdx);
331 }
332 for (size_t firstIdx = 0; firstIdx < classes.size(); ++firstIdx)
333 for (size_t secondIdx = firstIdx; secondIdx < classes.size(); ++secondIdx)
334 {
337 if (!firstClass.isStore && !secondClass.isStore) continue; // C2: >=1 write
338 const RaceOccurrence& firstRep = occurrences[firstClass.rep];
339 const RaceOccurrence& secondRep = occurrences[secondClass.rep];
340 if (!occurrencesRace(mhp, firstRep, secondRep)) continue; // C3
341 // C4 + emit. Lock relation is uniform per class (the reps decide it),
342 // so emit a statement-COVERING set -- every racy member as an endpoint.
343 if (firstIdx != secondIdx)
344 {
345 if (firstClass.locked && secondClass.locked &&
346 lockAnalysis->isProtectedByCommonLock(firstRep.node, secondRep.node))
347 continue;
348 for (size_t memberIdx : firstClass.members)
349 commitRacePair(outRacePairs, occurrences[memberIdx],
351 for (size_t memberIdx : secondClass.members)
352 commitRacePair(outRacePairs, occurrences[firstClass.members[0]],
354 }
355 else
356 {
357 const std::vector<size_t>& members = firstClass.members;
358 // Multiforked self-race: every member self-races a concurrent
359 // instance of itself, independent of any cross-race below.
360 for (size_t memberIdx : members)
361 if (!firstClass.locked ||
362 !lockAnalysis->isProtectedByCommonLock(occurrences[memberIdx].node,
363 occurrences[memberIdx].node))
365 // Cross-race needs >=2 members: two distinct occurrences to pair.
366 if (members.size() >= 2 &&
367 (!firstClass.locked ||
368 !lockAnalysis->isProtectedByCommonLock(occurrences[members[0]].node,
369 occurrences[members[1]].node)))
370 for (size_t pos = 0; pos < members.size(); ++pos)
371 commitRacePair(outRacePairs, occurrences[members[pos]],
372 occurrences[members[pos == 0 ? 1 : 0]]);
373 }
374 }
375 }
376
377 for (const RacePair& r : outRacePairs)
378 {
379 bugStmts.insert(r.stmt1);
380 bugStmts.insert(r.stmt2);
381 }
382 return bugStmts;
383}
384
386{
387 DBOUT(DGENERAL, outs() << pasMsg("Starting Race Detection\n"));
388
389 SVFIR* pag = SVFIR::getPAG();
391 CallGraph* callGraph = pta->getCallGraph();
392
393 // Shared equivalence-class detector (the same one the slicing pipeline uses),
394 // run over the Andersen pre-analysis with this MTA's MHP/lock results.
395 std::set<RacePair> racePairs;
396 detectRace(pag, pta, mhp, lsa, callGraph, racePairs);
397
398 for (const RacePair& rp : racePairs)
399 outs() << SVFUtil::bugMsg1("race pair(") << " stmt1: " << rp.stmt1->toString()
400 << ", stmt2: " << rp.stmt2->toString() << SVFUtil::bugMsg1(")") << "\n";
401}
402
403//===----------------------------------------------------------------------===//
404// SlicedMTA -- Multi-stage on-demand slicing race detection (MSli).
405//
406// Library-side orchestration of the slicing pipeline over the SVFIR.
407//===----------------------------------------------------------------------===//
408
409namespace
410{
411
412// Timing helper.
413void timePhase(const char* name, const std::function<void()>& fn)
414{
415 SVFUtil::outs() << "[TIMER] Phase: " << name << " - started\n";
416 auto start = std::chrono::steady_clock::now();
417 fn();
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";
421 if (ms >= 1000.0)
422 SVFUtil::outs() << " (" << std::fixed << std::setprecision(2) << (ms / 1000.0) << " s)";
423 SVFUtil::outs() << "\n";
424}
425
426// Output statistics for the original (unsliced) SVFIR.
427void reportOriginalStats(SVFIR* svfIr)
428{
429 size_t icfgNodeCount = 0;
430 for (ICFG::iterator it = svfIr->getICFG()->begin(), eit = svfIr->getICFG()->end(); it != eit; ++it)
432
433 size_t functionCount = 0;
434 for (auto it = svfIr->getCallGraph()->begin(), eit = svfIr->getCallGraph()->end(); it != eit; ++it)
436
437 size_t pagStmtCount = 0;
438 for (PAG::iterator it = svfIr->getPAG()->begin(), eit = svfIr->getPAG()->end(); it != eit; ++it)
439 pagStmtCount++;
440
441 SVFUtil::outs() << "\n[Original SVFIR] Statistics:\n";
442 SVFUtil::outs() << " ICFG nodes: " << icfgNodeCount << "\n";
443 SVFUtil::outs() << " Functions: " << functionCount << "\n";
444 SVFUtil::outs() << " PAG statements: " << pagStmtCount << "\n";
445}
446
447// Check and report a step result.
448bool checkAndReport(const char* phase, bool condition)
449{
450 if (!condition)
451 SVFUtil::errs() << "[ERROR] " << phase << " failed\n";
452 return condition;
453}
454
455// Main-phase context depth. The default must not depend on -mta-enable-slicing:
456// the sliced run and the whole-program FSAM baseline are compared against each
457// other, so both must analyze at the same context sensitivity.
459{
460 if (!Options::MaxContextLen.isSet())
461 return 2;
462 return Options::MaxContextLen();
463}
464
465} // anonymous namespace
466
467SlicedMTA::SlicedMTA() = default;
468
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}
484
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}
491
492std::set<const SVFStmt*> SlicedMTA::getVulnerableStmts() const
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}
502
503// Pre-Analysis (Pointer Analysis + TCT + MHP & Lock + Race Detection).
504// Build the thread-aware value-flow graph (VFG_pre) once, on a shared Andersen
505// (reused by the main FSMPTA via the AndersenWaveDiff singleton). This is the
506// substrate the paper uses for both slicing (data dependence over the
507// thread-aware value flow) and the main sparse FS resolution.
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}
526
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}
632
633// MTA Slicing and Analysis (using pre-analysis pointer analysis results)
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}
749
750// PTA Slicing and Sliced Pointer Analysis
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}
851
852// Build a lock analysis over the WHOLE ICFG (every node kept => real control flow,
853// no bridged edges). Used for the final detection's lock signature so the sliced
854// run reproduces the whole-program lock relation exactly (query preservation).
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}
870
871// Final Race Detection using sliced analysis results
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}
935
936// No-slice A/B baseline: run the SAME refined machinery as the sliced path
937// (SlicedTCT/MHP/LockAnalysis + flow-sensitive FSAM + the same final re-check),
938// but over a "slice" that keeps EVERY ICFG node -- i.e. the whole program. This
939// is the correct reference: if slicing preserves the result, this must produce
940// the same race set as the real (reduced) slice, only slower.
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}
997
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}
1030
1031//===----------------------------------------------------------------------===//
1032// Race detection for the SlicedMTA pipeline (final detection + whole-program
1033// baseline), driven by the sliced/FSAM analyses. hasThreadFunctions is a generic
1034// helper on the base MTA detector; detectRacePairsOnSlicedGraph is the pipeline's
1035// sliced-graph screen and stays on SlicedMTA.
1036//===----------------------------------------------------------------------===//
1037
1038// Whether any thread (fork-target) function is reachable via a fork edge.
1040{
1041 for (CallGraph::iterator it = callGraph->begin(), eit = callGraph->end(); it != eit; ++it)
1042 {
1043 const CallGraphNode* node = it->second;
1044 for (const CallGraphEdge* edge : node->getOutEdges())
1045 {
1046 if (edge->getEdgeKind() == CallGraphEdge::TDForkEdge &&
1047 edge->getDstNode()->getFunction() != nullptr)
1048 {
1049 return true;
1050 }
1051 }
1052 }
1053 return false;
1054}
1055
1056// Detect race pairs on the sliced graph using sliced analysis results.
1057std::set<SlicedMTA::RacePair> SlicedMTA::detectRacePairsOnSlicedGraph(
1059 MHP* slicedMHP,
1060 LockAnalysis* slicedLockAnalysis)
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}
unsigned u32_t
Definition CommandLine.h:18
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition SVFType.h:576
#define TIMEINTERVAL
Definition SVFType.h:604
#define DMTA
Definition SVFType.h:597
#define DGENERAL
Definition SVFType.h:582
#define DOTIMESTAT(X)
Definition SVFType.h:578
if(prebuffer< 0)
Definition cJSON.cpp:1269
const char *const name
Definition cJSON.h:264
cJSON * item
Definition cJSON.h:222
int count
Definition cJSON.h:216
void setValue(T v)
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
static void releaseAndersenWaveDiff()
Definition Andersen.h:418
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.
Definition ConsG.cpp:595
bool hasBasicBlock() const
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
const GEdgeSetTy & getOutEdges() const
ICFGNodeIDToNodeMapTy::iterator iterator
Definition ICFG.h:58
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
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244
void analyze(ICFGGraph icfg, CGGraph cg)
bool isProtectedByCommonLock(const ICFGNode *i1, const ICFGNode *i2)
Definition MHP.h:57
void analyze(ICFGGraph icfg, CGGraph cg)
Definition MHP.cpp:120
const NodeBS & getInterleavingThreads(const CxtThreadStmt &cts)
Get interleaving thread for statement inst.
Definition MHP.h:112
const CxtThreadStmtSet & getThreadStmtSet(const ICFGNode *inst) const
Get/has ThreadStmt.
Definition MHP.h:124
bool hasThreadStmtSet(const ICFGNode *inst) const
Definition MHP.h:130
TCT * getTCT() const
Get Thread Creation Tree.
Definition MHP.h:95
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.
Definition MTA.cpp:114
static std::set< const SVFStmt * > detectRace(SVFIR *svfIr, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, CallGraph *callGraph, std::set< RacePair > &outRacePairs)
Definition MTA.cpp:221
ThreadCallGraph * tcg
Definition MTA.h:164
std::unique_ptr< TCT > tct
Definition MTA.h:165
static bool occurrencesRace(MHP *mhp, const RaceOccurrence &first, const RaceOccurrence &second)
Helpers for the equivalence-class race detector.
Definition MTA.cpp:202
virtual ~MTA()
Destructor.
Definition MTA.cpp:63
LockAnalysis * lsa
Definition MTA.h:168
MHP * mhp
Definition MTA.h:167
static PointsTo getGlobalObjectVariables(SVFIR *svfIr)
Escape/points-to helpers for the shared detector.
Definition MTA.cpp:138
virtual MHP * computeMHP(TCT *tct)
Compute MHP.
Definition MTA.cpp:121
MTA()
Constructor.
Definition MTA.cpp:58
static void commitRacePair(std::set< RacePair > &out, const RaceOccurrence &first, const RaceOccurrence &second)
Definition MTA.cpp:210
std::unique_ptr< MTAStat > stat
Definition MTA.h:166
static bool hasThreadFunctions(CallGraph *callGraph)
Definition MTA.cpp:1039
virtual bool runOnModule(SVFIR *module)
We start the pass here.
Definition MTA.cpp:75
virtual void reportRaces()
Run the shared detector and print a race report.
Definition MTA.cpp:385
static PointsTo getPointsToClosure(AndersenBase *pta, const PointsTo &pts)
Definition MTA.cpp:166
static const Option< bool > SlicedDumpDot
MTA slicing: dump intermediate dot graphs (ICFG/TCG/SVFG/...), Default: false.
Definition Options.h:265
static const Option< bool > EnableSlicing
MTA slicing: slice before the FSAM main analysis (false = whole-program baseline),...
Definition Options.h:261
static const Option< bool > DumpMTAGraphs
MTA: dump the pointer-analysis and thread call graphs (ptacg/tcg.dot), Default: false.
Definition Options.h:258
static const Option< bool > SlicingSingle
MTA slicing: one unified slice for ILA + FSPTA (single-pass baseline), Default: false.
Definition Options.h:263
static Option< u32_t > MaxContextLen
Definition Options.h:81
bool printStat()
Whether print statistics.
NodeID getBaseObjVarID(NodeID id)
SVFIR * getPAG() const
CallGraph * getCallGraph() const
Return call graph.
virtual const NodeBS & getAllFieldsObjVars(NodeID id)
void set(u32_t n)
Inserts n in the set.
Definition PointsTo.cpp:157
u32_t getSVFGNodeNum() const
Return total SVFG node number.
Definition SVFG.h:271
static void releaseSVFIR()
Definition SVFIR.h:128
SVFStmtList & getSVFStmtList(const ICFGNode *inst)
Given an instruction, get all its PAGEdges.
Definition SVFIR.h:318
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:498
const CallGraph * getCallGraph()
Get CG.
Definition SVFIR.h:248
ICFG * getICFG() const
Definition SVFIR.h:231
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:120
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
u32_t mainCxtDepth
Definition MTA.h:245
std::unique_ptr< LockAnalysis > lockAnalysis
Definition MTA.h:248
void buildVFGPre()
Definition MTA.cpp:508
std::set< RacePair > racePairs
Definition MTA.h:272
std::unique_ptr< SlicedSVFIRView > fullLockView
Definition MTA.h:268
bool hasThreadFunctions
Definition MTA.h:271
SVFIR * svfIr
Definition MTA.h:242
void runOnModule(SVFIR *pag, const ResolveIndirectCalls &resolveIndirectCalls)
Run the slicing pipeline on a pre-built SVFIR.
Definition MTA.cpp:998
std::unique_ptr< FlowSensitive > mtaFSMPTA
Definition MTA.h:263
void runWholeProgramDetection()
Definition MTA.cpp:941
bool runPTASlicingAndAnalysis()
Definition MTA.cpp:751
bool runFinalRaceDetection()
Definition MTA.cpp:872
std::set< const SVFStmt * > getVulnerableStmts() const
Union of both statements of every candidate race pair (the slice targets).
Definition MTA.cpp:492
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< LockAnalysis > slicedLockAnalysis
Definition MTA.h:266
std::unique_ptr< LockAnalysis > fullLockAnalysis
Definition MTA.h:270
std::unique_ptr< SlicedSVFIRView > mtaSlicedView
Definition MTA.h:260
std::unique_ptr< SlicedTCT > fullLockTCT
Definition MTA.h:269
bool runMTASlicingAndAnalysis()
Definition MTA.cpp:634
std::unique_ptr< MultiStageSlicer > multiStageSlicer
Definition MTA.h:255
AndersenWaveDiff * preAnder
Definition MTA.h:252
std::unique_ptr< MHP > slicedMhp
Definition MTA.h:265
std::set< const ICFGNode * > singleSlicedNodes
Definition MTA.h:259
std::unique_ptr< SingleSlicer > singleSlicer
Definition MTA.h:256
std::unique_ptr< SlicedSVFIRView > ptaSlicedView
Definition MTA.h:261
std::unique_ptr< TCT > tct
Definition MTA.h:246
SVFG * vfgPre
Definition MTA.h:254
std::unique_ptr< SlicedSVFGView > slicedSVFGView
Definition MTA.h:262
std::function< void(CallGraph *)> ResolveIndirectCalls
Definition MTA.h:194
std::unique_ptr< SlicedTCT > slicedTCT
Definition MTA.h:264
std::unique_ptr< MHP > mhp
Definition MTA.h:247
LockAnalysis * buildFullLockAnalysis()
Definition MTA.cpp:855
bool runPreAnalysis(const ResolveIndirectCalls &resolveIndirectCalls)
Definition MTA.cpp:527
std::unique_ptr< MTASVFGBuilder > vfgPreBuilder
Definition MTA.h:253
BVDataPTAImpl * getMainPTA() const
Definition MTA.cpp:485
const SlicedICFGView * getICFG() const
Get SlicedICFGView.
bool isMultiforked() const
Definition TCT.h:121
TCTNode * getTCTNode(NodeID id) const
Get TCT node.
Definition TCT.h:203
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)
Definition SVFUtil.cpp:87
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition SVFUtil.cpp:105
bool cmpNodeBS(const NodeBS &lpts, const NodeBS &rpts)
Definition SVFUtil.h:127
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
u32_t NodeID
Definition GeneralType.h:76
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition GeneralType.h:56
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:67
IntervalValue operator<(const IntervalValue &lhs, const IntervalValue &rhs)
One occurrence of a memory access under one thread instance.
Definition MTA.h:148
A race pair: two statements that may race.
Definition MTA.h:120