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<BugReport>(*DoubleNonblockingBugType,
34                                              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 =
57       std::make_unique<BugReport>(*MissingWaitBugType, 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 =
77       std::make_unique<BugReport>(*UnmatchedWaitBugType, 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 MPIBugReporter::RequestNodeVisitor::VisitNode(
88     const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) {
89 
90   if (IsNodeFound)
91     return nullptr;
92 
93   const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
94   const Request *const PrevReq =
95       N->getFirstPred()->getState()->get<RequestMap>(RequestRegion);
96 
97   // Check if request was previously unused or in a different state.
98   if ((Req && !PrevReq) || (Req->CurrentState != PrevReq->CurrentState)) {
99     IsNodeFound = true;
100 
101     ProgramPoint P = N->getFirstPred()->getLocation();
102     PathDiagnosticLocation L =
103         PathDiagnosticLocation::create(P, BRC.getSourceManager());
104 
105     return std::make_shared<PathDiagnosticEventPiece>(L, ErrorText);
106   }
107 
108   return nullptr;
109 }
110 
111 } // end of namespace: mpi
112 } // end of namespace: ento
113 } // end of namespace: clang
114