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