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
31#include "Util/Options.h"
32#include "MTA/MTA.h"
33#include "MTA/MHP.h"
34#include "MTA/TCT.h"
35#include "MTA/LockAnalysis.h"
36#include "MTA/MTAStat.h"
37#include "MTA/MTASVFGBuilder.h"
38#include "MTA/FSMPTA.h"
39#include "MTA/MTASlicer.h"
40#include "WPA/Andersen.h"
42#include "Util/SVFUtil.h"
43#include <algorithm>
44#include <deque>
45#include <set>
46#include <string>
47#include <utility>
48#include <vector>
49
50using namespace SVF;
51using namespace SVFUtil;
52
53MTA::MTA() : tcg(nullptr), tct(nullptr), mhp(nullptr), lsa(nullptr)
54{
55 stat = std::make_unique<MTAStat>();
56}
57
59{
60 delete mhp;
61 delete lsa;
62}
63
68{
69 DBOUT(DGENERAL, outs() << pasMsg("MTA analysis\n"));
70 DBOUT(DMTA, outs() << pasMsg("MTA analysis\n"));
71
74 pta->getCallGraph()->dump("ptacg");
75 pag->getICFG()->updateCallGraph(pta->getCallGraph());
76
77 DBOUT(DGENERAL, outs() << pasMsg("Build TCT\n"));
78 DBOUT(DMTA, outs() << pasMsg("Build TCT\n"));
79 DOTIMESTAT(double tctStart = stat->getClk());
80 tct = TCT::create(pta);
81 tcg = tct->getThreadCallGraph();
82 DOTIMESTAT(double tctEnd = stat->getClk());
83 DOTIMESTAT(stat->TCTTime += (tctEnd - tctStart) / TIMEINTERVAL);
84
85 if (pta->printStat())
86 {
87 stat->performThreadCallGraphStat(tcg);
88 stat->performTCTStat(tct.get());
89 }
90
92 tcg->dump("tcg");
93
94 mhp = computeMHP(tct.get());
95 lsa = computeLocksets(tct.get());
96
97 // MTA's only client is race detection; always report.
99
100 return false;
101}
102
107{
109 lsa->analyze(PAG::getPAG()->getICFG(), const_cast<CallGraph*>(PAG::getPAG()->getCallGraph()));
110 return lsa;
111}
112
114{
115 DBOUT(DGENERAL, outs() << pasMsg("MHP analysis\n"));
116 DBOUT(DMTA, outs() << pasMsg("MHP analysis\n"));
117
118 DOTIMESTAT(double mhpStart = stat->getClk());
119 std::unique_ptr<MHP> mhp = MHP::create(
120 tct, PAG::getPAG()->getICFG(),
121 const_cast<CallGraph*>(PAG::getPAG()->getCallGraph()));
122 mhp->analyze(PAG::getPAG()->getICFG(), const_cast<CallGraph*>(PAG::getPAG()->getCallGraph()));
123 DOTIMESTAT(double mhpEnd = stat->getClk());
124 DOTIMESTAT(stat->MHPTime += (mhpEnd - mhpStart) / TIMEINTERVAL);
125
126 DBOUT(DGENERAL, outs() << pasMsg("MHP analysis finish\n"));
127 DBOUT(DMTA, outs() << pasMsg("MHP analysis finish\n"));
128 return mhp.release();
129}
130
131// Collect the global objects (addr-taken global vars at the global ICFG node).
133{
136
137 for (const SVFStmt* stmt : globalICFGNode->getSVFStmts())
138 {
139 const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt);
140 if (addrStmt != nullptr)
141 {
142 const GlobalValVar* globalVar =
143 SVFUtil::dyn_cast<GlobalValVar>(addrStmt->getLHSVar());
144 if (globalVar != nullptr)
145 {
146 globalObjVars.set(addrStmt->getRHSVarID());
147 }
148 }
149 }
150
151 return globalObjVars;
152}
153
154// Transitive closure of a set under TWO relations: points-to (an object -> the
155// objects it points to) and containment (a base object -> its field sub-objects).
156// The containment step is essential for field sensitivity: a field-sensitive
157// access resolves to a GepObjVar that is NOT reachable from its base by points-to
158// edges, so without it a race on a (non-zero-offset) struct field -- or on an
159// object reached through a struct's pointer field -- would be screened out of the
160// escape set as "not shared".
162{
163 SVFIR* pag = pta->getPAG();
165 std::deque<NodeID> worklist;
166 for (NodeID pt : pts)
167 {
168 worklist.push_back(pt);
169 }
170
171 while (!worklist.empty())
172 {
173 NodeID obj = worklist.front();
174 worklist.pop_front();
175
176 for (NodeID target : pta->getPts(obj)) // points-to
177 if (!ptsClosure.test(target))
178 {
179 ptsClosure.set(target);
180 worklist.push_back(target);
181 }
182
183 if (pag->getBaseObject(obj) != nullptr) // containment (object nodes only)
185 if (!ptsClosure.test(field))
186 {
187 ptsClosure.set(field);
188 worklist.push_back(field);
189 }
190 }
191
192 return ptsClosure;
193}
194
195// C3: distinct threads must mutually interleave; the same thread self-races only
196// when it is multiforked (more than one dynamic instance).
198 MHP* mhp, const RaceOccurrence& first, const RaceOccurrence& second)
199{
200 if (first.tid != second.tid)
201 return first.interleaving->test(second.tid) &&
202 second.interleaving->test(first.tid);
203 return mhp->getTCT()->getTCTNode(first.tid)->isMultiforked();
204}
205
206// Record one order-normalised racing statement pair.
207void MTA::commitRacePair(std::set<RacePair>& out,
208 const RaceOccurrence& first,
209 const RaceOccurrence& second)
210{
211 out.emplace(first.stmt, second.stmt);
212}
213
215{
216 if (tid != other.tid)
217 return tid < other.tid;
218 if (isStore != other.isStore)
219 return isStore < other.isStore;
221 return true;
223 return false;
224 if (locked != other.locked)
225 return locked < other.locked;
226 return lockNodeId < other.lockNodeId;
227}
228
230 SVFIR* svfir, AndersenBase* pta, MHP* mhp,
231 LockAnalysis* lockAnalysis, CallGraph* callGraph,
233 std::vector<RaceOccurrence>& occurrences,
235{
236 for (const auto& item : *callGraph)
237 {
238 const FunObjVar* fun = item.second->getFunction();
239 if (!fun || !fun->hasBasicBlock())
240 continue;
241 for (auto bbIt : *fun)
242 for (const ICFGNode* node : bbIt.second->getICFGNodeList())
243 {
245 mhp->getThreadSummary(node);
246 if (threadSummary == nullptr)
247 continue;
248 for (const SVFStmt* stmt : svfir->getSVFStmtList(node))
249 {
251 bool isStore;
252 if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
253 {
254 accessedPtr = load->getRHSVarID();
255 isStore = false;
256 }
257 else if (const StoreStmt* store =
258 SVFUtil::dyn_cast<StoreStmt>(stmt))
259 {
260 accessedPtr = store->getLHSVarID();
261 isStore = true;
262 }
263 else
264 continue;
265
268 if (objects.empty())
269 continue;
270
271 const bool locked =
272 lockAnalysis->isProtectedByCommonLock(node, node);
273 const size_t firstNewOccurrence = occurrences.size();
274 for (const auto& tidAndInterleaving :
275 threadSummary->interleavingByTid)
276 occurrences.push_back(
277 {
278 stmt, node, isStore, tidAndInterleaving.first,
279 &tidAndInterleaving.second, locked});
280 for (NodeID object : objects)
281 for (size_t index = firstNewOccurrence;
282 index < occurrences.size(); ++index)
284 }
285 }
286 }
287}
288
289std::vector<MTA::RaceClass> MTA::buildRaceClasses(
290 const std::vector<RaceOccurrence>& occurrences,
291 const std::vector<size_t>& occurrenceIndices)
292{
293 std::vector<RaceClass> classes;
296 {
298 const RaceClassKey key
299 {
300 occurrence.tid, occurrence.isStore, occurrence.interleaving,
301 occurrence.locked,
302 occurrence.locked ? occurrence.node->getId() : 0};
303 const auto found = keyToClass.find(key);
304 if (found == keyToClass.end())
305 {
306 keyToClass[key] = classes.size();
307 classes.push_back(
308 {
309 occurrence.isStore, occurrence.locked, occurrenceIndex,
310 {occurrenceIndex}});
311 }
312 else
313 classes[found->second].members.push_back(occurrenceIndex);
314 }
315 return classes;
316}
317
319 MHP* mhp, LockAnalysis* lockAnalysis,
320 const std::vector<RaceOccurrence>& occurrences,
321 const std::vector<RaceClass>& classes,
322 std::set<RacePair>& outRacePairs)
323{
324 for (size_t firstIndex = 0; firstIndex < classes.size(); ++firstIndex)
325 for (size_t secondIndex = firstIndex;
326 secondIndex < classes.size(); ++secondIndex)
327 {
330 if (!firstClass.isStore && !secondClass.isStore)
331 continue;
332
334 occurrences[firstClass.representative];
336 occurrences[secondClass.representative];
337 if (!occurrencesRace(
339 continue;
340
341 if (firstIndex != secondIndex)
342 {
343 if (firstClass.locked && secondClass.locked &&
344 lockAnalysis->isProtectedByCommonLock(
346 continue;
347 for (size_t memberIndex : firstClass.members)
348 for (size_t otherIndex : secondClass.members)
351 }
352 else
353 {
354 const std::vector<size_t>& members = firstClass.members;
355 if (firstClass.locked &&
356 lockAnalysis->isProtectedByCommonLock(
358 continue;
359 for (size_t firstPosition = 0;
360 firstPosition < members.size(); ++firstPosition)
361 for (size_t secondPosition = firstPosition;
362 secondPosition < members.size(); ++secondPosition)
365 occurrences[members[secondPosition]]);
366 }
367 }
368}
369
370// Equivalence-class race detector: screen accesses, bucket by object, collapse
371// occurrences sharing the race predicate's inputs into classes, then pair classes.
372std::set<const SVFStmt*> MTA::detectRace(
373 SVFIR* svfir, AndersenBase* pta, MHP* mhp, LockAnalysis* lockAnalysis,
374 CallGraph* callGraph,
375 std::set<RacePair>& outRacePairs)
376{
377
378 outRacePairs.clear();
379 std::set<const SVFStmt*> bugStmts;
380
381 // Escape set: objects shared across threads. Seed from globals + the actual
382 // argument at each fork site (the spawner's value, which a spawnee-formal
383 // closure can miss), then take the transitive points-to closure.
385 if (ThreadCallGraph* tcg = SVFUtil::dyn_cast<ThreadCallGraph>(callGraph))
386 {
387 const ThreadAPI* tapi = tcg->getThreadAPI();
388 for (auto it = tcg->forksitesBegin(), eit = tcg->forksitesEnd(); it != eit; ++it)
389 if (const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(*it))
390 if (const ValVar* actual = tapi->getActualParmAtForkSite(cs))
391 seed |= pta->getPts(actual->getId());
392 }
394
395 std::vector<RaceOccurrence> occurrences;
398 svfir, pta, mhp, lockAnalysis, callGraph, escSet,
400
401 // Within each object, occurrences sharing the race predicate's inputs (tid,
402 // interleaving, isStore, lock sig) race the same partners, so collapse into a
403 // class and judge C2/C3/C4 once per class pair -- O(classes^2) not O(occ^2).
404 for (const auto& objectAndOccs : objectToOccurrences)
405 {
406 const std::vector<RaceClass> classes =
409 mhp, lockAnalysis, occurrences, classes, outRacePairs);
410 }
411
412 for (const RacePair& pair : outRacePairs)
413 {
414 bugStmts.insert(pair.stmt1);
415 bugStmts.insert(pair.stmt2);
416 }
417 return bugStmts;
418}
419
421{
422 DBOUT(DGENERAL, outs() << pasMsg("Starting Race Detection\n"));
423
424 SVFIR* pag = SVFIR::getPAG();
426 CallGraph* callGraph = pta->getCallGraph();
427
428 // Shared equivalence-class detector (the same one the slicing pipeline uses),
429 // run over the Andersen pre-analysis with this MTA's MHP/lock results.
430 std::set<RacePair> racePairs;
431 detectRace(pag, pta, mhp, lsa, callGraph, racePairs);
432
433 for (const RacePair& rp : racePairs)
434 outs() << SVFUtil::bugMsg1("race pair(") << " stmt1: " << rp.stmt1->toString()
435 << ", stmt2: " << rp.stmt2->toString() << SVFUtil::bugMsg1(")") << "\n";
436}
437
438//===----------------------------------------------------------------------===//
439// SlicedMTA -- Multi-stage on-demand slicing race detection (MSli).
440//
441// Library-side orchestration of the slicing pipeline over the SVFIR.
442//===----------------------------------------------------------------------===//
443
444// Output statistics for the original (unsliced) SVFIR.
446{
447 size_t icfgNodeCount = 0;
448 for (ICFG::iterator it = svfir->getICFG()->begin(), eit = svfir->getICFG()->end(); it != eit; ++it)
450
451 size_t functionCount = 0;
452 for (auto it = svfir->getCallGraph()->begin(), eit = svfir->getCallGraph()->end(); it != eit; ++it)
454
455 size_t pagStmtCount = 0;
456 for (ICFG::iterator it = svfir->getICFG()->begin(),
457 eit = svfir->getICFG()->end(); it != eit; ++it)
458 {
459 const ICFGNode* node = it->second;
460 if (svfir->hasSVFStmtList(node))
461 pagStmtCount += svfir->getSVFStmtList(node).size();
462 }
463
464 SVFUtil::outs() << "\n[Original SVFIR] Statistics:\n";
465 SVFUtil::outs() << " ICFG nodes: " << icfgNodeCount << "\n";
466 SVFUtil::outs() << " Functions: " << functionCount << "\n";
467 SVFUtil::outs() << " PAG statements: " << pagStmtCount << "\n";
468}
469
470std::set<const ICFGNode*> SlicedMTA::collectICFGNodes(
471 SVFG* svfg, const NodeBS& svfgNodeIds)
472{
473 std::set<const ICFGNode*> nodes;
474 for (NodeID id : svfgNodeIds)
475 {
476 if (!svfg->hasSVFGNode(id))
477 continue;
478 if (const StmtVFGNode* stmtNode =
479 SVFUtil::dyn_cast<StmtVFGNode>(svfg->getSVFGNode(id)))
480 if (stmtNode->getICFGNode() != nullptr)
481 nodes.insert(stmtNode->getICFGNode());
482 }
483 return nodes;
484}
485
487 const std::set<const ICFGNode*>& icfgNodes)
488{
489 std::set<const FunObjVar*> functions;
490 std::set<const SVFStmt*> statements;
491 for (const ICFGNode* node : icfgNodes)
492 {
493 if (node->getFun() != nullptr)
494 functions.insert(node->getFun());
495 statements.insert(node->getSVFStmts().begin(), node->getSVFStmts().end());
496 }
497
498 SVFUtil::outs() << "[PTA Sliced] Statistics:\n";
499 SVFUtil::outs() << " ICFG nodes: " << icfgNodes.size() << "\n";
500 SVFUtil::outs() << " Functions: " << functions.size() << "\n";
501 SVFUtil::outs() << " PAG statements: " << statements.size() << "\n";
502}
503
505{
506 std::string key;
507 const ICFGNode* node = statement->getICFGNode();
508 const FunObjVar* function = node == nullptr ? nullptr : node->getFun();
509 const SVFBasicBlock* block = statement->getBB();
510 const SVFVar* value = statement->getValue();
511
512 const std::string fields[] =
513 {
514 std::to_string(statement->getEdgeKind()),
515 function == nullptr ? std::string() : function->getName(),
516 block == nullptr ? std::string() : block->getName(),
517 node == nullptr ? std::string() : node->getSourceLoc(),
518 value == nullptr ? std::string() : value->getName(),
519 value == nullptr ? std::string() : value->getSourceLoc(),
520 value != nullptr && value->hasLLVMValue()
521 ? value->valueOnlyToString() : std::string()
522 };
523 for (const std::string& field : fields)
524 {
525 key += std::to_string(field.size());
526 key += ':';
527 key += field;
528 }
529 return key;
530}
531
532void SlicedMTA::updateDigest(u64_t& digest, const std::string& value)
533{
534 for (unsigned char byte : value)
535 {
536 digest ^= static_cast<u64_t>(byte);
537 digest *= 1099511628211ULL;
538 }
539 digest ^= 0xffULL;
540 digest *= 1099511628211ULL;
541}
542
544 const std::set<RacePair>& pairs)
545{
547 std::set<std::string> statementKeys;
548 for (const RacePair& pair : pairs)
549 {
550 statementToKey.emplace(pair.stmt1, std::string());
551 statementToKey.emplace(pair.stmt2, std::string());
552 }
553 for (auto& statementAndKey : statementToKey)
554 {
555 statementAndKey.second = raceStatementKey(statementAndKey.first);
556 statementKeys.insert(statementAndKey.second);
557 }
558
559 RaceDigests digests{1469598103934665603ULL, 1469598103934665603ULL};
560 for (const std::string& key : statementKeys)
561 updateDigest(digests.alarm, key);
562
563 std::set<std::pair<std::string, std::string>> pairKeys;
564 for (const RacePair& pair : pairs)
565 {
566 std::string first = statementToKey.at(pair.stmt1);
567 std::string second = statementToKey.at(pair.stmt2);
568 if (second < first)
569 std::swap(first, second);
570 pairKeys.emplace(std::move(first), std::move(second));
571 }
572
573 for (const auto& pair : pairKeys)
574 {
575 updateDigest(digests.pair, pair.first);
576 updateDigest(digests.pair, pair.second);
577 }
578 return digests;
579}
580
581SlicedMTA::SlicedMTA() : mainContextDepth(Options::MaxContextLen())
582{
583}
584
585SlicedMTA::~SlicedMTA() = default;
586
588{
589 // The main FSMPTA phase is the flow-sensitive FSAM (FSMPTA), a
590 // BVDataPTAImpl, so the downstream race detector queries it polymorphically.
591 return mainFSMPTA.get();
592}
593
594std::set<const SVFStmt*> SlicedMTA::getVulnerableStmts() const
595{
596 std::set<const SVFStmt*> vulnerableStatements;
597 for (const RacePair& pair : racePairs)
598 {
599 vulnerableStatements.insert(pair.stmt1);
600 vulnerableStatements.insert(pair.stmt2);
601 }
603}
604
605// Pre-Analysis (Pointer Analysis + TCT + MHP & Lock + Race Detection).
606// Build the BaseSVFG once, then attach its pre-analysis TVF overlay. The base is
607// reused by the main FSMPTA after replacing only that overlay.
609{
610 ScopedPhaseTimer timer("Build thread-aware VFG_pre");
611 // Treat fork/join as calls so the SVFG carries the thread-oblivious
612 // (fork/join-ordered) value flow.
613 if (ThreadCallGraph* tcg = SVFUtil::dyn_cast<ThreadCallGraph>(preAndersen->getCallGraph()))
614 {
615 tcg->updateCallGraph(preAndersen);
616 tcg->updateJoinEdge(preAndersen);
617 }
618 preSVFGBuilder = std::make_unique<MTASVFGBuilder>(
619 mhp.get(), lockAnalysis.get(),
621 // The Pre-TVF overlay is sliced, never solved: omit its interference-edge
622 // labels. Main-TVF labels are added after the pre overlay is removed.
623 preSVFG = preSVFGBuilder->buildPTROnlySVFG(preAndersen);
624 if (isMTAStatEnabled())
625 SVFUtil::outs() << "[BaseSVFG] built once: " << preSVFG->getSVFGNodeNum()
626 << " nodes; [Pre-TVF] "
627 << preSVFGBuilder->getThreadAwareEdgeCount()
628 << " interference edges\n";
629}
630
632{
633 SVFUtil::outs() << "\n=== Pre-Analysis ===\n";
634
635 const bool dumpDot = Options::DumpMTAGraphs();
636
637 // The LLVM-aware tool has already run Andersen and materialised its resolved
638 // indirect calls into the PAG. Reuse that same analysis throughout MSli.
640 SVFUtil::dyn_cast<ThreadCallGraph>(preAndersen->getCallGraph());
641 if (threadCallGraph == nullptr)
642 {
643 SVFUtil::errs() << "[ERROR] Thread call graph failed\n";
644 return false;
645 }
646
647 // Step 2: Build the context-insensitive pre-analysis Thread Creation Tree.
648 {
649 ScopedPhaseTimer timer("Create Thread Create Tree");
651 }
652 if (dumpDot)
653 tct->dump("original_tct");
654
655 // A thread with several instances at the main depth must be multiforked in
656 // this depth-0 TCT, or the pre-analysis under-approximates the main phase.
657 {
658 ScopedPhaseTimer timer("Mark truncation-merged multiforked threads");
659 std::unique_ptr<TCT> deepTct =
661
662 // >1 instance at the main depth, or a single instance that is itself
663 // multiforked (merged just beyond the main depth), marks the fork site.
665 for (const auto& deepPair : *deepTct)
666 if (const ICFGNode* forkSite = deepPair.second->getCxtThread().getThread())
667 {
669 if (deepPair.second->isMultiforked())
671 }
672
673 for (const auto& prePair : *tct)
674 {
675 const ICFGNode* forkSite = prePair.second->getCxtThread().getThread();
676 if (forkSite == nullptr)
677 continue;
679 if (fIt != forkSiteInstances.end() && fIt->second > 1)
680 prePair.second->setMultiforked(true);
681 }
682 }
683
684 // Step 3: Interleaving and Lock Analysis
685 {
686 ScopedPhaseTimer ilaTimer("Run Interleaving and Lock Analysis");
687 {
688 ScopedPhaseTimer timer("ILA: construct MHP/ForkJoin");
690 tct.get(), svfir->getICFG(),
691 const_cast<CallGraph*>(svfir->getCallGraph()));
692 }
693 {
694 ScopedPhaseTimer timer("ILA: MHP propagation");
695 mhp->analyze(svfir->getICFG(), const_cast<CallGraph*>(svfir->getCallGraph()));
696 }
697 {
698 ScopedPhaseTimer timer("ILA: Lock analysis");
699 lockAnalysis = std::make_unique<LockAnalysis>(tct.get());
700 lockAnalysis->analyze(svfir->getICFG(), const_cast<CallGraph*>(svfir->getCallGraph()));
701 }
702 }
703
704 // Step 4: Detect thread functions
705 {
706 ScopedPhaseTimer timer("Detect Thread Functions");
708 }
710 {
711 SVFUtil::outs() << "[WARNING] No thread functions found\n";
712 return true; // Not an error, just no threads to analyze
713 }
714
715 // Step 5: Detect race statements
716 std::set<const SVFStmt*> vulnerableStatements;
717 {
718 ScopedPhaseTimer timer("Detect Race Statements");
719 // Shared equivalence-class detector (the same one MTA::reportRaces uses).
721 svfir, preAndersen, mhp.get(), lockAnalysis.get(),
723 }
724 SVFUtil::outs() << "Found " << vulnerableStatements.size() << " vulnerable statements\n";
725 SVFUtil::outs() << "Found " << racePairs.size() << " race pairs\n";
726
727 // Step 6: build the thread-aware VFG only when a downstream slice/solve
728 // exists. No-race programs end after the pre-detector.
729 if (!racePairs.empty())
731 else
732 SVFUtil::outs() << "[SKIP] No race candidates; VFG_pre is unnecessary\n";
733
734 return true;
735}
736
737// MTA Slicing and Analysis (using pre-analysis pointer analysis results)
739{
740 SVFUtil::outs() << "\n=== MTA Slicing and Analysis ===\n";
741
742 if (racePairs.empty())
743 {
744 SVFUtil::outs() << "[SKIP] No race pairs found in pre-analysis\n";
745 return true;
746 }
747
748 const bool dumpDot = Options::DumpMTAGraphs();
749
750 // Step 1: Get vulnerable statements from race pairs
751 std::set<const SVFStmt*> vulnerableStatements = getVulnerableStmts();
752
753 std::set<const ICFGNode*> mtaSlicedNodes;
754
756 {
757 // Single-pass baseline (MSli §3/§5.4): one unified slice (V_Single)
758 // combining synchronization + data + call dependence, shared by both the
759 // ILA and the FSPTA stages. Computed once here; reused in PTA slicing.
760 SVFUtil::outs() << "[Slicing Mode] Single unified slice (V_Single) for ILA + FSPTA\n";
761 singleSlicer = std::make_unique<SingleSlicer>(
762 svfir, preAndersen, mhp.get(), lockAnalysis.get(),
763 preSVFG /* data dependence over the thread-aware VFG_pre */);
764 {
765 ScopedPhaseTimer timer("Unified Slicing");
768 singleSlicedNodes = std::move(singleSlice.icfgNodes);
770 }
772 if (isMTAStatEnabled())
773 SVFUtil::outs() << "Unified sliced to " << mtaSlicedNodes.size()
774 << " nodes\n";
775 }
776 else
777 {
778 SVFUtil::outs() << "[Slicing Mode] Differential slices (separate ILA + FSPTA)\n";
779 multiStageSlicer = std::make_unique<MultiStageSlicer>(
780 svfir, preAndersen, mhp.get(), lockAnalysis.get(), preSVFG);
781
782 // ILA slicing sources = [INIT] race statements + [THREAD-VF] sources. Keep
783 // a candidate edge's query (see MTASVFGBuilder::getThreadVFQueryMap) only if
784 // both endpoints survive the FSPTA slice -- i.e. the edge is in
785 // ThreadVF(VFG'_pre). Closure computed here (pre<->pre) and reused by PTA slicing.
786 std::set<const ICFGNode*> threadVFSources;
788 {
789 ScopedPhaseTimer timer("Select THREAD-VF slicing sources");
790 if (preSVFGBuilder)
791 {
792 multiStageSlicer->computePreCandidateSlice(vulnerableStatements);
794 multiStageSlicer->getPreCandidateSlice();
797 preSVFG, preAndersen, preCandidate.nodeIds());
799 !preCandidate.svfgNodes.empty())
800 {
801 SVFUtil::errs() << "[ERROR] Failed to execution-close VFG'_pre\n";
802 return false;
803 }
804 if (isMTAStatEnabled())
806 << "[VFG'_pre] " << preCandidate.svfgNodes.size()
807 << " dependency nodes, "
809 << " execution-closure nodes\n";
810
811 // The query map can be large; use node-ID membership rather than
812 // two ordered-set lookups for every candidate edge.
813 for (const auto& entry : preSVFGBuilder->getThreadVFQueryMap())
814 {
815 const MTASVFGBuilder::ThreadVFEdge& edge = entry.first;
816 if (preCandidateSolveNodeIds.test(edge.first->getId()) &&
817 preCandidateSolveNodeIds.test(edge.second->getId()))
818 {
819 selectedThreadVFCandidates.emplace_back(
820 edge.first->getId(), edge.second->getId());
821 // The query value holds only the lock-span witnesses; the
822 // endpoints are implicit in the edge key.
823 threadVFSources.insert(edge.first->getICFGNode());
824 threadVFSources.insert(edge.second->getICFGNode());
825 threadVFSources.insert(entry.second.begin(), entry.second.end());
826 }
827 }
828 }
829 }
830 std::sort(selectedThreadVFCandidates.begin(),
833 std::unique(selectedThreadVFCandidates.begin(),
836 {
837 ScopedPhaseTimer timer("MTA Slicing");
839 }
840 if (isMTAStatEnabled())
841 SVFUtil::outs() << "MTA sliced to " << mtaSlicedNodes.size()
842 << " nodes\n";
843 } // end differential MTA slice
844
845 // Step 4: Build MTA SlicedSVFIRView (using pre-analysis pointer analysis)
846 {
847 ScopedPhaseTimer timer("Build MTA Sliced View");
848 mtaSlicedView = std::make_unique<SlicedSVFIRView>(
851 }
852 if (isMTAStatEnabled())
853 mtaSlicedView->dumpStats("MTA Sliced");
854
856
857 if (dumpDot)
858 {
859 SVFUtil::outs() << "\n[Dump] MTA Sliced views:\n";
860 slicedView->getICFG()->dump("sliced_icfg");
861 if (slicedView->getThreadCallGraph() != nullptr)
862 slicedView->getThreadCallGraph()->dump("sliced_tcg");
863 slicedView->getPAG()->dump("sliced_pag");
864 }
865
866 // Step 5: Build Sliced TCT (using pre-analysis pointer analysis)
867 {
868 ScopedPhaseTimer timer("Sliced Thread Create Tree");
869 if (isMTAStatEnabled())
870 SVFUtil::outs() << "[SlicedTCT] Using max context length: "
871 << mainContextDepth << " (from -max-cxt)\n";
872 // Reuse the shared pre-analysis (Andersen) for the sliced TCT.
875 if (dumpDot)
876 slicedTCT->dump("sliced_tct");
877 }
878
879 // Step 6: Sliced MHP and Lock Analysis
880 {
881 ScopedPhaseTimer ilaTimer("Sliced Interleaving and Lock Analysis");
882 {
883 ScopedPhaseTimer timer("Sliced ILA: construct MHP/ForkJoin");
885 slicedTCT.get(), slicedView->getICFG(),
886 slicedView->getThreadCallGraph(),
888 }
889 {
890 ScopedPhaseTimer timer("Sliced ILA: MHP propagation");
891 slicedMHP->analyze(slicedView->getICFG(), slicedView->getThreadCallGraph());
892 }
893 {
894 ScopedPhaseTimer timer("Sliced ILA: Lock analysis");
895 slicedLockAnalysis = std::make_unique<LockAnalysis>(slicedTCT.get());
896 slicedLockAnalysis->analyze(slicedView->getICFG(), slicedView->getThreadCallGraph());
897 }
898 }
899
900 return true;
901}
902
903// PTA Slicing and Sliced Pointer Analysis
905{
906 SVFUtil::outs() << "\n=== PTA Slicing and Sliced Pointer Analysis ===\n";
907
909 {
910 SVFUtil::outs() << "[SKIP] No thread functions found in pre-analysis, skipping PTA slicing\n";
911 return true;
912 }
913 if (racePairs.empty())
914 {
915 SVFUtil::outs() << "[SKIP] No race pairs found in pre-analysis, skipping PTA slicing\n";
916 return true;
917 }
918
919 const bool dumpDot = Options::DumpMTAGraphs();
920
921 std::set<const SVFStmt*> vulnerableStatements = getVulnerableStmts();
922
923 std::set<const ICFGNode*> ptaSlicedNodes;
925
926 if (slicedMHP == nullptr || slicedLockAnalysis == nullptr ||
927 preSVFGBuilder == nullptr || preSVFG == nullptr)
928 {
929 SVFUtil::outs() << "[Main FSMPTA] Base SVFG or sliced ILA unavailable\n";
930 return false;
931 }
932
934 {
935 // Single-pass baseline: reuse the unified V_Single computed in MTA slicing
936 // (no separate data-dependence slice); FSPTA runs on the same slice as ILA.
937 SVFUtil::outs() << "[Slicing Mode] Reusing unified slice (V_Single) for FSPTA\n";
943 {
944 SVFUtil::errs() << "[ERROR] Single-slice FSMPTA execution closure failed\n";
945 return false;
946 }
948 if (isMTAStatEnabled())
949 SVFUtil::outs() << "PTA reuses unified slice: "
950 << ptaSlicedNodes.size() << " ICFG nodes, "
951 << finalSVFGNodeIds.count()
952 << " execution-closure SVFG nodes\n";
953
955
958 mainScope);
959 {
960 ScopedPhaseTimer timer("Replace Pre-TVF with Main-TVF overlay");
961 preSVFGBuilder->replaceThreadAwareOverlay(
963 }
964 }
965 else
966 {
967 SVFUtil::outs() << "Using " << vulnerableStatements.size() << " vulnerable statements from pre-analysis\n";
968 SVFUtil::outs() << "Using " << racePairs.size() << " race pairs from pre-analysis\n";
969
970 // Differential stage 1 always constructs this slicer and its conservative
971 // pre-candidate closure before stage 2 starts.
972 if (multiStageSlicer == nullptr)
973 {
974 SVFUtil::errs() << "[ERROR] Differential PTA slicing requires the ILA slicer\n";
975 return false;
976 }
977
979 multiStageSlicer->getPreCandidateSlice();
980 if (preCandidateSolveNodeIds.empty() && !preCandidate.svfgNodes.empty())
981 {
982 SVFUtil::errs() << "[ERROR] Execution-closed VFG'_pre is unavailable\n";
983 return false;
984 }
987
988 // The base SVFG is stable. Replace only the pre-analysis TVF overlay
989 // with edges derived from the context-sensitive sliced main ILA.
993 {
994 ScopedPhaseTimer timer("Replace Pre-TVF with Main-TVF overlay");
995 preSVFGBuilder->replaceThreadAwareOverlay(
997 }
998 if (isMTAStatEnabled())
999 SVFUtil::outs() << "[Main-TVF] "
1000 << preSVFGBuilder->getThreadAwareEdgeCount()
1001 << " interference edges over VFG'_pre\n";
1002
1004 {
1005 ScopedPhaseTimer timer("PTA Slicing over refined main VFG");
1007 }
1008 ptaSlicedNodes = finalSlice.icfgNodes;
1009 finalSVFGNodeIds = finalSlice.nodeIds();
1010
1013 if (!outsideCandidate.empty())
1014 {
1015 SVFUtil::errs() << "[ERROR] Initial FSPTA slice escapes VFG'_pre by "
1016 << outsideCandidate.count() << " SVFG nodes\n";
1017 return false;
1018 }
1019
1020 {
1021 ScopedPhaseTimer timer("Build FSMPTA execution dependency closure");
1025 }
1026
1028 outsideCandidate.intersectWithComplement(preCandidateIds);
1029 if (!outsideCandidate.empty())
1030 {
1031 SVFUtil::errs() << "[ERROR] FSMPTA execution closure escapes VFG'_pre by "
1032 << outsideCandidate.count() << " SVFG nodes\n";
1033 return false;
1034 }
1035
1036 // Report the exact execution-closed solve set, rather than the smaller
1037 // pre-closure dependency seed shown by the old implementation.
1039
1040 if (isMTAStatEnabled())
1041 {
1042 SVFUtil::outs() << "[FSPTA Slice] " << finalSlice.svfgNodes.size()
1043 << " / " << preCandidate.svfgNodes.size() << " / "
1044 << preCandidateIds.count()
1045 << " SVFG nodes (final / pre-candidate / execution-closed), "
1046 << finalSVFGNodeIds.count()
1047 << " execution-closure solve nodes\n";
1048 SVFUtil::outs() << "PTA sliced to " << ptaSlicedNodes.size()
1049 << " nodes\n";
1050 }
1051 }
1052
1053 if (isMTAStatEnabled())
1055
1056 // Slicers are no longer needed. The builder and its one stable base SVFG
1057 // remain alive because FSMPTA solves that graph directly.
1058 multiStageSlicer.reset();
1059 singleSlicer.reset();
1060
1061 // Step 5: solve the exact final slice on the stable base SVFG plus Main-TVF.
1062 SVFUtil::outs() << "[Main FSMPTA] Reusing BaseSVFG; Main-TVF comes from the sliced main ILA\n";
1064 {
1065 SVFUtil::errs() << "[ERROR] Unsupported FSMPTA mapping/clustering configuration\n";
1066 return false;
1067 }
1068 {
1069 ScopedPhaseTimer timer("Flow-Sensitive FSAM Analysis");
1070 slicedSVFGView = std::make_unique<SlicedSVFGView>(
1072 auto solver = std::make_unique<FSMPTA<const SlicedSVFGView*>>(
1074 solver->analyze();
1075 if (dumpDot)
1076 {
1077 solver->getSVFG()->dump("mta_svfg");
1078 slicedSVFGView->dump("sliced_svfg");
1079 }
1080 mainFSMPTA = std::move(solver);
1081 }
1082
1083 return true;
1084}
1085
1086// Final Race Detection using sliced analysis results
1088{
1089 SVFUtil::outs() << "\n=== Final Race Detection ===\n";
1090
1091 if (!hasThreadFunctions)
1092 {
1093 SVFUtil::outs() << "[SKIP] No thread functions found\n";
1094 return true;
1095 }
1096 if (racePairs.empty())
1097 {
1098 SVFUtil::outs() << "\n=== Race Detection Summary ===\n";
1099 SVFUtil::outs() << "Race pairs (pre-analysis): 0\n";
1100 SVFUtil::outs() << "Race pairs (sliced graph): 0\n";
1101 SVFUtil::outs() << "Race statements (sliced graph): 0\n";
1102 if (isMTAStatEnabled())
1103 {
1105 SVFUtil::outs() << "[MSLI-RQ] mode=MSli alarms=0 pairs=0"
1106 << " alarm-digest=" << digests.alarm
1107 << " pair-digest=" << digests.pair << "\n";
1108 }
1109 SVFUtil::outs() << "\nNo race pairs detected in sliced graph.\n";
1110 return true;
1111 }
1112 if (mtaSlicedView == nullptr)
1113 {
1114 SVFUtil::errs() << "[ERROR] MTA sliced view not available\n";
1115 return false;
1116 }
1117 if (slicedMHP == nullptr || slicedLockAnalysis == nullptr)
1118 {
1119 SVFUtil::errs() << "[ERROR] Sliced MHP or LockAnalysis not available\n";
1120 return false;
1121 }
1122 if (getMainPTA() == nullptr)
1123 {
1124 SVFUtil::errs() << "[ERROR] Main flow-sensitive pointer analysis not available\n";
1125 return false;
1126 }
1127
1128 std::set<RacePair> detectedPairs;
1129 {
1130 ScopedPhaseTimer timer("Final Race Detection");
1132 racePairs, // Refine only pre-analysis candidates
1133 getMainPTA(), // Use flow-sensitive FSAM points-to
1134 slicedMHP.get(), slicedLockAnalysis.get());
1135 }
1136
1137 // Distinct racy statements (the endpoints of the race pairs) -- a stabler,
1138 // smaller-to-report metric than the pair count.
1139 std::set<const SVFStmt*> racyStmts;
1140 for (const RacePair& pair : detectedPairs)
1141 {
1142 racyStmts.insert(pair.stmt1);
1143 racyStmts.insert(pair.stmt2);
1144 }
1145
1146 SVFUtil::outs() << "\n=== Race Detection Summary ===\n";
1147 SVFUtil::outs() << "Race pairs (pre-analysis): " << racePairs.size() << "\n";
1148 SVFUtil::outs() << "Race pairs (sliced graph): " << detectedPairs.size() << "\n";
1149 SVFUtil::outs() << "Race statements (sliced graph): " << racyStmts.size() << "\n";
1150 // Machine-readable line for the artifact's `msli` table generator: the race
1151 // statements reported after slicing (the preservation metric).
1152 if (isMTAStatEnabled())
1153 {
1155 SVFUtil::outs() << "[MSLI-RQ] mode=MSli alarms=" << racyStmts.size()
1156 << " pairs=" << detectedPairs.size()
1157 << " alarm-digest=" << digests.alarm
1158 << " pair-digest=" << digests.pair << "\n";
1159 }
1160
1161 if (!detectedPairs.empty())
1162 {
1163 SVFUtil::outs() << "\n=== Bug Report ===\n";
1164 SVFUtil::outs() << "Found " << detectedPairs.size() << " race pair(s) in sliced graph\n";
1165 }
1166 else
1167 {
1168 SVFUtil::outs() << "\nNo race pairs detected in sliced graph.\n";
1169 }
1170
1171 return true;
1172}
1173
1174// No-slice A/B baseline: run the same analysis as the sliced path over the whole
1175// program. SlicedTCT is retained here to preserve its main-context construction;
1176// MHP and LockAnalysis consume the original full graphs directly.
1178{
1179 SVFUtil::outs() << "\n=== Whole-program FSAM Race Detection (no slicing) ===\n";
1180 if (!hasThreadFunctions || racePairs.empty())
1181 {
1182 SVFUtil::outs() << "[SKIP] No thread functions / race pairs in pre-analysis\n";
1183 return true;
1184 }
1185
1186 // SlicedTCT currently consumes the sliced-view representation even for the
1187 // full baseline. Time that construction explicitly so the A/B phase table
1188 // accounts for it instead of leaving it in unattributed wall time.
1189 {
1190 ScopedPhaseTimer timer("Build Whole-program View");
1191 std::set<const ICFGNode*> allNodes;
1192 for (ICFG::iterator it = svfir->getICFG()->begin(),
1193 eit = svfir->getICFG()->end(); it != eit; ++it)
1194 allNodes.insert(it->second);
1195 ptaSlicedView = std::make_unique<SlicedSVFIRView>(
1197 }
1198
1199 {
1200 ScopedPhaseTimer timer("Whole-program TCT/MHP/Lock");
1201 {
1202 ScopedPhaseTimer phaseTimer("Whole-program Thread Create Tree");
1205 }
1207 {
1209 "Whole-program ILA: construct MHP/ForkJoin");
1213 }
1214 {
1215 ScopedPhaseTimer phaseTimer("Whole-program ILA: MHP propagation");
1216 slicedMHP->analyze(svfir->getICFG(), fullCallGraph);
1217 }
1218 {
1219 ScopedPhaseTimer phaseTimer("Whole-program ILA: Lock analysis");
1221 std::make_unique<LockAnalysis>(slicedTCT.get());
1223 }
1224 }
1225
1228 {
1229 ScopedPhaseTimer timer("Whole-program Replace Pre-TVF with Main-TVF overlay");
1230 preSVFGBuilder->replaceThreadAwareOverlay(
1232 }
1233 if (isMTAStatEnabled())
1234 SVFUtil::outs() << "[Main-TVF] "
1235 << preSVFGBuilder->getThreadAwareEdgeCount()
1236 << " interference edges over the whole BaseSVFG\n";
1237
1238 {
1239 ScopedPhaseTimer timer("Whole-program Flow-Sensitive FSMPTA Solve");
1240 auto solver = std::make_unique<FSMPTA<SVFG*>>(
1242 solver->analyze();
1243 mainFSMPTA = std::move(solver);
1244 }
1245
1246 std::set<RacePair> detectedPairs;
1247 {
1248 ScopedPhaseTimer timer("Final Race Detection (whole program)");
1250 racePairs, getMainPTA(), slicedMHP.get(),
1251 slicedLockAnalysis.get());
1252 }
1253
1254 std::set<const SVFStmt*> racyStmts;
1255 for (const RacePair& pair : detectedPairs)
1256 {
1257 racyStmts.insert(pair.stmt1);
1258 racyStmts.insert(pair.stmt2);
1259 }
1260
1261 SVFUtil::outs() << "\n=== Race Detection Summary ===\n";
1262 SVFUtil::outs() << "Race pairs (pre-analysis): " << racePairs.size() << "\n";
1263 SVFUtil::outs() << "Race pairs (whole program): " << detectedPairs.size() << "\n";
1264 SVFUtil::outs() << "Race statements (whole program): " << racyStmts.size() << "\n";
1265 if (isMTAStatEnabled())
1266 {
1268 SVFUtil::outs() << "[MSLI-RQ] mode=FSAM alarms=" << racyStmts.size()
1269 << " pairs=" << detectedPairs.size()
1270 << " alarm-digest=" << digests.alarm
1271 << " pair-digest=" << digests.pair << "\n";
1272 }
1273 return true;
1274}
1275
1277{
1278 if (svfir != nullptr || pag == nullptr || preAnalysis.getPAG() != pag)
1279 {
1280 SVFUtil::errs() << "[ERROR] SlicedMTA is single-use and requires a "
1281 << "matching SVFIR and Andersen pre-analysis\n";
1282 return false;
1283 }
1284 svfir = pag;
1285 preAndersen = &preAnalysis;
1286
1287 SVFUtil::outs() << "[Config] Slicing: "
1288 << (Options::MTAEnableSlicing() ? "enabled" : "disabled")
1289 << "\n";
1290
1291 if (isMTAStatEnabled())
1293
1294 // The pre-analysis is context-insensitive in BOTH modes (the sliced run and
1295 // the FSAM baseline must share an identical pre-analysis substrate); the
1296 // main phase then runs at the configured context depth.
1297 // TCT context bounds are explicit constructor inputs; no process-global
1298 // option is mutated while the pipeline is running.
1299 const bool preOk = runPreAnalysis();
1300 if (!preOk)
1301 return false;
1302
1304 {
1305 if (!runMTASlicingAndAnalysis()) return false;
1306 if (!runPTASlicingAndAnalysis()) return false;
1307 if (!runFinalRaceDetection()) return false;
1308 }
1309 else
1310 {
1311 if (!runWholeProgramDetection()) return false;
1312 }
1313
1314 SVFUtil::outs() << "\n=== Analysis Complete ===\n";
1315 return true;
1316}
1317
1318//===----------------------------------------------------------------------===//
1319// Race detection for the SlicedMTA pipeline (final detection + whole-program
1320// baseline), driven by the sliced/FSAM analyses. hasThreadFunctions is a generic
1321// helper on the base MTA detector; detectRacePairsOnSlicedGraph is the pipeline's
1322// sliced-graph screen and stays on SlicedMTA.
1323//===----------------------------------------------------------------------===//
1324
1325// Whether any thread (fork-target) function is reachable via a fork edge.
1327{
1328 for (CallGraph::iterator it = callGraph->begin(), eit = callGraph->end();
1329 it != eit; ++it)
1330 {
1331 const CallGraphNode* node = it->second;
1332 for (const CallGraphEdge* edge : node->getOutEdges())
1333 {
1334 if (edge->getEdgeKind() == CallGraphEdge::TDForkEdge &&
1335 edge->getDstNode()->getFunction() != nullptr)
1336 {
1337 return true;
1338 }
1339 }
1340 }
1341 return false;
1342}
1343
1344// Detect race pairs on the sliced graph using sliced analysis results.
1345std::set<SlicedMTA::RacePair> SlicedMTA::detectRacePairsOnSlicedGraph(
1346 const std::set<RacePair>& preAnalysisRacePairs,
1348 MHP* slicedMHP,
1349 LockAnalysis* slicedLockAnalysis)
1350{
1351
1352 std::set<RacePair> filteredRacePairs;
1353
1354 // MSli's main phase refines the alarms produced by the conservative
1355 // pre-analysis. Main ILA and FSMPTA are recomputed independently on their
1356 // slices; only the candidate universe comes from pre-analysis.
1357 for (const RacePair& pair : preAnalysisRacePairs)
1358 {
1359 const ICFGNode* node1 = pair.stmt1->getICFGNode();
1360 const ICFGNode* node2 = pair.stmt2->getICFGNode();
1361
1362 if (!slicedMHP->mayHappenInParallelCache(node1, node2))
1363 continue;
1364
1365 if (slicedLockAnalysis->isProtectedByCommonLock(node1, node2))
1366 continue;
1367
1369 if (const LoadStmt* ldStmt1 =
1370 SVFUtil::dyn_cast<LoadStmt>(pair.stmt1))
1371 {
1372 pts1 = slicedPTA->getPts(ldStmt1->getRHSVarID());
1373 }
1374 else if (const StoreStmt* stStmt1 =
1375 SVFUtil::dyn_cast<StoreStmt>(pair.stmt1))
1376 {
1377 pts1 = slicedPTA->getPts(stStmt1->getLHSVarID());
1378 }
1379 else
1380 {
1381 continue;
1382 }
1383
1384 if (const LoadStmt* ldStmt2 =
1385 SVFUtil::dyn_cast<LoadStmt>(pair.stmt2))
1386 {
1387 pts2 = slicedPTA->getPts(ldStmt2->getRHSVarID());
1388 }
1389 else if (const StoreStmt* stStmt2 =
1390 SVFUtil::dyn_cast<StoreStmt>(pair.stmt2))
1391 {
1392 pts2 = slicedPTA->getPts(stStmt2->getLHSVarID());
1393 }
1394 else
1395 {
1396 continue;
1397 }
1398
1399 // Check if points-to sets still intersect
1400 if (pts1.intersects(pts2))
1401 filteredRacePairs.insert(pair);
1402 }
1403
1404 return filteredRacePairs;
1405}
#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
int index
Definition cJSON.h:170
cJSON * item
Definition cJSON.h:222
static AndersenWaveDiff * createAndersenWaveDiff(SVFIR *_pag)
Create an singleton instance directly instead of invoking llvm pass manager.
Definition Andersen.h:408
const PointsTo & getPts(NodeID id) override
void dump(const std::string &filename)
Dump the graph.
static NodeBS buildExecutionDependencyClosure(SVFG *graph, AndersenBase *preAnalysis, NodeBS dependencyNodes)
Definition FSMPTA.cpp:121
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.
Definition ICFGNode.h:75
ICFGNodeIDToNodeMapTy::iterator iterator
Definition ICFG.h:58
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:52
void analyze(ICFGGraph icfg, CGGraph cg)
Definition MHP.cpp:115
const NodeThreadSummary * getThreadSummary(const ICFGNode *inst) const
Definition MHP.cpp:257
static std::unique_ptr< MHP > create(TCT *t, ICFGGraph icfg, CGGraph cg, StateRepresentation representation=StateRepresentation::MaterializedContexts)
Construct MHP and initialize its graph-dependent ForkJoinAnalysis.
Definition MHP.h:646
TCT * getTCT() const
Get Thread Creation Tree.
Definition MHP.h:110
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)
Definition MTA.cpp:318
virtual LockAnalysis * computeLocksets(TCT *tct)
Compute locksets.
Definition MTA.cpp:106
static std::vector< RaceClass > buildRaceClasses(const std::vector< RaceOccurrence > &occurrences, const std::vector< size_t > &occurrenceIndices)
Definition MTA.cpp:289
ThreadCallGraph * tcg
Definition MTA.h:202
std::unique_ptr< TCT > tct
Definition MTA.h:203
static bool occurrencesRace(MHP *mhp, const RaceOccurrence &first, const RaceOccurrence &second)
Definition MTA.cpp:197
virtual ~MTA()
Destructor.
Definition MTA.cpp:58
static PointsTo getGlobalObjectVariables(SVFIR *svfir)
Escape/points-to helpers for the shared detector.
Definition MTA.cpp:132
LockAnalysis * lsa
Definition MTA.h:206
Map< NodeID, std::vector< size_t > > ObjectToRaceOccurrences
Definition MTA.h:179
MHP * mhp
Definition MTA.h:205
virtual MHP * computeMHP(TCT *tct)
Compute MHP.
Definition MTA.cpp:113
MTA()
Constructor.
Definition MTA.cpp:53
static void commitRacePair(std::set< RacePair > &out, const RaceOccurrence &first, const RaceOccurrence &second)
Definition MTA.cpp:207
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.
Definition MTA.cpp:229
std::unique_ptr< MTAStat > stat
Definition MTA.h:204
static std::set< const SVFStmt * > detectRace(SVFIR *svfir, AndersenBase *pta, MHP *mhp, LockAnalysis *lockAnalysis, CallGraph *callGraph, std::set< RacePair > &outRacePairs)
Definition MTA.cpp:372
static bool hasThreadFunctions(CallGraph *callGraph)
Definition MTA.cpp:1326
virtual bool runOnModule(SVFIR *module)
We start the pass here.
Definition MTA.cpp:67
virtual void reportRaces()
Run the shared detector and print a race report.
Definition MTA.cpp:420
static PointsTo getPointsToClosure(AndersenBase *pta, const PointsTo &pts)
Definition MTA.cpp:161
Carries around command line options.
Definition Options.h:16
static const Option< bool > MTAEnableSlicing
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 > MTASingleStageSlicing
MTA slicing: one unified slice for ILA + FSPTA (single-pass baseline), Default: false.
Definition Options.h:263
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
bool hasSVFGNode(NodeID id) const
Whether has the SVFGNode.
Definition SVFG.h:156
SVFGNode * getSVFGNode(NodeID id) const
Get a SVFG node.
Definition SVFG.h:150
u32_t getSVFGNodeNum() const
Return total SVFG node number.
Definition SVFG.h:271
SVFStmtList & getSVFStmtList(const ICFGNode *inst)
Given an instruction, get all its PAGEdges.
Definition SVFIR.h:318
bool hasSVFStmtList(const ICFGNode *inst) const
Whether this instruction has SVFIR Edge.
Definition SVFIR.h:308
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
const bool hasLLVMValue() const
Definition LLVMUtil.cpp:770
virtual const std::string getSourceLoc() const
Definition SVFValue.h:194
virtual const std::string & getName() const
Definition SVFValue.h:184
const std::string valueOnlyToString() const
Definition LLVMUtil.cpp:751
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
NodeBS preCandidateSolveNodeIds
Definition MTA.h:302
bool runWholeProgramDetection()
Definition MTA.cpp:1177
static RaceDigests computeRaceDigests(const std::set< RacePair > &pairs)
Definition MTA.cpp:543
std::unique_ptr< LockAnalysis > lockAnalysis
Definition MTA.h:293
SVFIR * svfir
Definition MTA.h:287
std::set< RacePair > racePairs
Definition MTA.h:320
AndersenWaveDiff * preAndersen
Definition MTA.h:297
bool runPreAnalysis()
Definition MTA.cpp:631
bool hasThreadFunctions
Definition MTA.h:319
std::unique_ptr< MTASVFGBuilder > preSVFGBuilder
Definition MTA.h:299
static std::string raceStatementKey(const SVFStmt *statement)
Definition MTA.cpp:504
bool runPTASlicingAndAnalysis()
Definition MTA.cpp:904
MTASVFGBuilder::ThreadVFCandidateList selectedThreadVFCandidates
Definition MTA.h:307
bool runFinalRaceDetection()
Definition MTA.cpp:1087
std::set< const SVFStmt * > getVulnerableStmts() const
Union of both statements of every candidate race pair (the slice targets).
Definition MTA.cpp:594
ThreadCallGraph * threadCallGraph
Definition MTA.h:298
std::unique_ptr< LockAnalysis > slicedLockAnalysis
Definition MTA.h:318
std::unique_ptr< SlicedSVFIRView > mtaSlicedView
Definition MTA.h:312
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.
Definition MTA.cpp:1345
bool runMTASlicingAndAnalysis()
Definition MTA.cpp:738
std::unique_ptr< MultiStageSlicer > multiStageSlicer
Definition MTA.h:301
static std::set< const ICFGNode * > collectICFGNodes(SVFG *svfg, const NodeBS &svfgNodeIds)
Definition MTA.cpp:470
static void updateDigest(u64_t &digest, const std::string &value)
Definition MTA.cpp:532
std::set< const ICFGNode * > singleSlicedNodes
Definition MTA.h:310
std::unique_ptr< SingleSlicer > singleSlicer
Definition MTA.h:303
void buildPreAnalysisSVFG()
Definition MTA.cpp:608
static void reportPTASliceStatistics(const std::set< const ICFGNode * > &icfgNodes)
Definition MTA.cpp:486
NodeBS singleSlicedSVFGNodeIds
Definition MTA.h:311
u32_t mainContextDepth
Definition MTA.h:290
bool runOnModule(SVFIR *pag, AndersenWaveDiff &preAnalysis)
Run the slicing pipeline with its prepared Andersen pre-analysis.
Definition MTA.cpp:1276
std::unique_ptr< SlicedSVFIRView > ptaSlicedView
Definition MTA.h:313
std::unique_ptr< TCT > tct
Definition MTA.h:291
std::unique_ptr< SlicedSVFGView > slicedSVFGView
Definition MTA.h:314
std::unique_ptr< SlicedTCT > slicedTCT
Definition MTA.h:316
std::unique_ptr< MHP > mhp
Definition MTA.h:292
std::unique_ptr< MHP > slicedMHP
Definition MTA.h:317
static void reportOriginalStatistics(SVFIR *svfir)
Pipeline utilities shared by the sliced and whole-program paths.
Definition MTA.cpp:445
BVDataPTAImpl * getMainPTA() const
Definition MTA.cpp:587
std::unique_ptr< FlowSensitive > mainFSMPTA
Definition MTA.h:315
SVFG * preSVFG
Definition MTA.h:300
const SlicedICFGView * getICFG() const
Get SlicedICFGView.
static std::unique_ptr< SlicedTCT > create(PointerAnalysis &pointerAnalysis, const SlicedSVFIRView &slicedView, u32_t contextLimit)
Definition MTASlicer.cpp:56
bool test(unsigned Idx) const
bool intersectWithComplement(const SparseBitVector &RHS)
unsigned count() const
bool isMultiforked() const
Definition TCT.h:122
TCTNode * getTCTNode(NodeID id) const
Get TCT node.
Definition TCT.h:209
static std::unique_ptr< TCT > create(PointerAnalysis *p)
Construct and build a TCT with the command-line context bound.
Definition TCT.cpp:41
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
unsigned long long u64_t
Definition GeneralType.h:69
u32_t NodeID
Definition GeneralType.h:76
bool isMTAStatEnabled()
Definition MTAStat.h:46
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition GeneralType.h:56
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
iter_range< typename GenericGraphTraits< GraphType >::nodes_iterator > nodes(const GraphType &G)
bool operator<(const RaceClassKey &other) const
Definition MTA.cpp:214
const NodeBS * interleaving
Definition MTA.h:172
One occurrence of a memory access under one thread instance.
Definition MTA.h:151
A race pair: two statements that may race.
Definition MTA.h:112