xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17 
18 namespace clang {
19 namespace ento {
20 namespace mpi {
21 
22 void MPIBugReporter::reportDoubleNonblocking(
23     const CallEvent &MPICallEvent, const ento::mpi::Request &Req,
24     const MemRegion *const RequestRegion,
25     const ExplodedNode *const ExplNode,
26     BugReporter &BReporter) const {
27 
28   std::string ErrorText;
29   ErrorText = "Double nonblocking on request " +
30               RequestRegion->getDescriptiveName() + ". ";
31 
32   auto Report = std::make_unique<PathSensitiveBugReport>(
33       DoubleNonblockingBugType, ErrorText, ExplNode);
34 
35   Report->addRange(MPICallEvent.getSourceRange());
36   SourceRange Range = RequestRegion->sourceRange();
37 
38   if (Range.isValid())
39     Report->addRange(Range);
40 
41   Report->addVisitor(std::make_unique<RequestNodeVisitor>(
42       RequestRegion, "Request is previously used by nonblocking call here. "));
43   Report->markInteresting(RequestRegion);
44 
45   BReporter.emitReport(std::move(Report));
46 }
47 
48 void MPIBugReporter::reportMissingWait(
49     const ento::mpi::Request &Req, const MemRegion *const RequestRegion,
50     const ExplodedNode *const ExplNode,
51     BugReporter &BReporter) const {
52   std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
53                         " has no matching wait. "};
54 
55   auto Report = std::make_unique<PathSensitiveBugReport>(MissingWaitBugType,
56                                                          ErrorText, ExplNode);
57 
58   SourceRange Range = RequestRegion->sourceRange();
59   if (Range.isValid())
60     Report->addRange(Range);
61   Report->addVisitor(std::make_unique<RequestNodeVisitor>(
62       RequestRegion, "Request is previously used by nonblocking call here. "));
63   Report->markInteresting(RequestRegion);
64 
65   BReporter.emitReport(std::move(Report));
66 }
67 
68 void MPIBugReporter::reportUnmatchedWait(
69     const CallEvent &CE, const clang::ento::MemRegion *const RequestRegion,
70     const ExplodedNode *const ExplNode,
71     BugReporter &BReporter) const {
72   std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
73                         " has no matching nonblocking call. "};
74 
75   auto Report = std::make_unique<PathSensitiveBugReport>(UnmatchedWaitBugType,
76                                                          ErrorText, ExplNode);
77 
78   Report->addRange(CE.getSourceRange());
79   SourceRange Range = RequestRegion->sourceRange();
80   if (Range.isValid())
81     Report->addRange(Range);
82 
83   BReporter.emitReport(std::move(Report));
84 }
85 
86 PathDiagnosticPieceRef
87 MPIBugReporter::RequestNodeVisitor::VisitNode(const ExplodedNode *N,
88                                               BugReporterContext &BRC,
89                                               PathSensitiveBugReport &BR) {
90 
91   if (IsNodeFound)
92     return nullptr;
93 
94   const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
95   assert(Req && "The region must be tracked and alive, given that we've "
96                 "just emitted a report against it");
97   const Request *const PrevReq =
98       N->getFirstPred()->getState()->get<RequestMap>(RequestRegion);
99 
100   // Check if request was previously unused or in a different state.
101   if (!PrevReq || (Req->CurrentState != PrevReq->CurrentState)) {
102     IsNodeFound = true;
103 
104     ProgramPoint P = N->getFirstPred()->getLocation();
105     PathDiagnosticLocation L =
106         PathDiagnosticLocation::create(P, BRC.getSourceManager());
107 
108     return std::make_shared<PathDiagnosticEventPiece>(L, ErrorText);
109   }
110 
111   return nullptr;
112 }
113 
114 } // end of namespace: mpi
115 } // end of namespace: ento
116 } // end of namespace: clang
117