1*e5dd7070Spatrick //===-- MPIBugReporter.cpp - bug reporter -----------------------*- C++ -*-===//
2*e5dd7070Spatrick //
3*e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e5dd7070Spatrick //
7*e5dd7070Spatrick //===----------------------------------------------------------------------===//
8*e5dd7070Spatrick ///
9*e5dd7070Spatrick /// \file
10*e5dd7070Spatrick /// This file defines prefabricated reports which are emitted in
11*e5dd7070Spatrick /// case of MPI related bugs, detected by path-sensitive analysis.
12*e5dd7070Spatrick ///
13*e5dd7070Spatrick //===----------------------------------------------------------------------===//
14*e5dd7070Spatrick 
15*e5dd7070Spatrick #include "MPIBugReporter.h"
16*e5dd7070Spatrick #include "MPIChecker.h"
17*e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18*e5dd7070Spatrick 
19*e5dd7070Spatrick namespace clang {
20*e5dd7070Spatrick namespace ento {
21*e5dd7070Spatrick namespace mpi {
22*e5dd7070Spatrick 
reportDoubleNonblocking(const CallEvent & MPICallEvent,const ento::mpi::Request & Req,const MemRegion * const RequestRegion,const ExplodedNode * const ExplNode,BugReporter & BReporter) const23*e5dd7070Spatrick void MPIBugReporter::reportDoubleNonblocking(
24*e5dd7070Spatrick     const CallEvent &MPICallEvent, const ento::mpi::Request &Req,
25*e5dd7070Spatrick     const MemRegion *const RequestRegion,
26*e5dd7070Spatrick     const ExplodedNode *const ExplNode,
27*e5dd7070Spatrick     BugReporter &BReporter) const {
28*e5dd7070Spatrick 
29*e5dd7070Spatrick   std::string ErrorText;
30*e5dd7070Spatrick   ErrorText = "Double nonblocking on request " +
31*e5dd7070Spatrick               RequestRegion->getDescriptiveName() + ". ";
32*e5dd7070Spatrick 
33*e5dd7070Spatrick   auto Report = std::make_unique<PathSensitiveBugReport>(
34*e5dd7070Spatrick       *DoubleNonblockingBugType, ErrorText, ExplNode);
35*e5dd7070Spatrick 
36*e5dd7070Spatrick   Report->addRange(MPICallEvent.getSourceRange());
37*e5dd7070Spatrick   SourceRange Range = RequestRegion->sourceRange();
38*e5dd7070Spatrick 
39*e5dd7070Spatrick   if (Range.isValid())
40*e5dd7070Spatrick     Report->addRange(Range);
41*e5dd7070Spatrick 
42*e5dd7070Spatrick   Report->addVisitor(std::make_unique<RequestNodeVisitor>(
43*e5dd7070Spatrick       RequestRegion, "Request is previously used by nonblocking call here. "));
44*e5dd7070Spatrick   Report->markInteresting(RequestRegion);
45*e5dd7070Spatrick 
46*e5dd7070Spatrick   BReporter.emitReport(std::move(Report));
47*e5dd7070Spatrick }
48*e5dd7070Spatrick 
reportMissingWait(const ento::mpi::Request & Req,const MemRegion * const RequestRegion,const ExplodedNode * const ExplNode,BugReporter & BReporter) const49*e5dd7070Spatrick void MPIBugReporter::reportMissingWait(
50*e5dd7070Spatrick     const ento::mpi::Request &Req, const MemRegion *const RequestRegion,
51*e5dd7070Spatrick     const ExplodedNode *const ExplNode,
52*e5dd7070Spatrick     BugReporter &BReporter) const {
53*e5dd7070Spatrick   std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
54*e5dd7070Spatrick                         " has no matching wait. "};
55*e5dd7070Spatrick 
56*e5dd7070Spatrick   auto Report = std::make_unique<PathSensitiveBugReport>(*MissingWaitBugType,
57*e5dd7070Spatrick                                                          ErrorText, ExplNode);
58*e5dd7070Spatrick 
59*e5dd7070Spatrick   SourceRange Range = RequestRegion->sourceRange();
60*e5dd7070Spatrick   if (Range.isValid())
61*e5dd7070Spatrick     Report->addRange(Range);
62*e5dd7070Spatrick   Report->addVisitor(std::make_unique<RequestNodeVisitor>(
63*e5dd7070Spatrick       RequestRegion, "Request is previously used by nonblocking call here. "));
64*e5dd7070Spatrick   Report->markInteresting(RequestRegion);
65*e5dd7070Spatrick 
66*e5dd7070Spatrick   BReporter.emitReport(std::move(Report));
67*e5dd7070Spatrick }
68*e5dd7070Spatrick 
reportUnmatchedWait(const CallEvent & CE,const clang::ento::MemRegion * const RequestRegion,const ExplodedNode * const ExplNode,BugReporter & BReporter) const69*e5dd7070Spatrick void MPIBugReporter::reportUnmatchedWait(
70*e5dd7070Spatrick     const CallEvent &CE, const clang::ento::MemRegion *const RequestRegion,
71*e5dd7070Spatrick     const ExplodedNode *const ExplNode,
72*e5dd7070Spatrick     BugReporter &BReporter) const {
73*e5dd7070Spatrick   std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
74*e5dd7070Spatrick                         " has no matching nonblocking call. "};
75*e5dd7070Spatrick 
76*e5dd7070Spatrick   auto Report = std::make_unique<PathSensitiveBugReport>(*UnmatchedWaitBugType,
77*e5dd7070Spatrick                                                          ErrorText, ExplNode);
78*e5dd7070Spatrick 
79*e5dd7070Spatrick   Report->addRange(CE.getSourceRange());
80*e5dd7070Spatrick   SourceRange Range = RequestRegion->sourceRange();
81*e5dd7070Spatrick   if (Range.isValid())
82*e5dd7070Spatrick     Report->addRange(Range);
83*e5dd7070Spatrick 
84*e5dd7070Spatrick   BReporter.emitReport(std::move(Report));
85*e5dd7070Spatrick }
86*e5dd7070Spatrick 
87*e5dd7070Spatrick PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)88*e5dd7070Spatrick MPIBugReporter::RequestNodeVisitor::VisitNode(const ExplodedNode *N,
89*e5dd7070Spatrick                                               BugReporterContext &BRC,
90*e5dd7070Spatrick                                               PathSensitiveBugReport &BR) {
91*e5dd7070Spatrick 
92*e5dd7070Spatrick   if (IsNodeFound)
93*e5dd7070Spatrick     return nullptr;
94*e5dd7070Spatrick 
95*e5dd7070Spatrick   const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
96*e5dd7070Spatrick   assert(Req && "The region must be tracked and alive, given that we've "
97*e5dd7070Spatrick                 "just emitted a report against it");
98*e5dd7070Spatrick   const Request *const PrevReq =
99*e5dd7070Spatrick       N->getFirstPred()->getState()->get<RequestMap>(RequestRegion);
100*e5dd7070Spatrick 
101*e5dd7070Spatrick   // Check if request was previously unused or in a different state.
102*e5dd7070Spatrick   if (!PrevReq || (Req->CurrentState != PrevReq->CurrentState)) {
103*e5dd7070Spatrick     IsNodeFound = true;
104*e5dd7070Spatrick 
105*e5dd7070Spatrick     ProgramPoint P = N->getFirstPred()->getLocation();
106*e5dd7070Spatrick     PathDiagnosticLocation L =
107*e5dd7070Spatrick         PathDiagnosticLocation::create(P, BRC.getSourceManager());
108*e5dd7070Spatrick 
109*e5dd7070Spatrick     return std::make_shared<PathDiagnosticEventPiece>(L, ErrorText);
110*e5dd7070Spatrick   }
111*e5dd7070Spatrick 
112*e5dd7070Spatrick   return nullptr;
113*e5dd7070Spatrick }
114*e5dd7070Spatrick 
115*e5dd7070Spatrick } // end of namespace: mpi
116*e5dd7070Spatrick } // end of namespace: ento
117*e5dd7070Spatrick } // end of namespace: clang
118