xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp (revision 647cbc5de815c5651677bf8582797f716ec7b48d)
10b57cec5SDimitry Andric //===-- MPIBugReporter.cpp - bug reporter -----------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file defines prefabricated reports which are emitted in
110b57cec5SDimitry Andric /// case of MPI related bugs, detected by path-sensitive analysis.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "MPIBugReporter.h"
160b57cec5SDimitry Andric #include "MPIChecker.h"
170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace clang {
200b57cec5SDimitry Andric namespace ento {
210b57cec5SDimitry Andric namespace mpi {
220b57cec5SDimitry Andric 
reportDoubleNonblocking(const CallEvent & MPICallEvent,const ento::mpi::Request & Req,const MemRegion * const RequestRegion,const ExplodedNode * const ExplNode,BugReporter & BReporter) const230b57cec5SDimitry Andric void MPIBugReporter::reportDoubleNonblocking(
240b57cec5SDimitry Andric     const CallEvent &MPICallEvent, const ento::mpi::Request &Req,
250b57cec5SDimitry Andric     const MemRegion *const RequestRegion,
260b57cec5SDimitry Andric     const ExplodedNode *const ExplNode,
270b57cec5SDimitry Andric     BugReporter &BReporter) const {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   std::string ErrorText;
300b57cec5SDimitry Andric   ErrorText = "Double nonblocking on request " +
310b57cec5SDimitry Andric               RequestRegion->getDescriptiveName() + ". ";
320b57cec5SDimitry Andric 
33a7dea167SDimitry Andric   auto Report = std::make_unique<PathSensitiveBugReport>(
34*647cbc5dSDimitry Andric       DoubleNonblockingBugType, ErrorText, ExplNode);
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   Report->addRange(MPICallEvent.getSourceRange());
370b57cec5SDimitry Andric   SourceRange Range = RequestRegion->sourceRange();
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   if (Range.isValid())
400b57cec5SDimitry Andric     Report->addRange(Range);
410b57cec5SDimitry Andric 
42a7dea167SDimitry Andric   Report->addVisitor(std::make_unique<RequestNodeVisitor>(
430b57cec5SDimitry Andric       RequestRegion, "Request is previously used by nonblocking call here. "));
440b57cec5SDimitry Andric   Report->markInteresting(RequestRegion);
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   BReporter.emitReport(std::move(Report));
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
reportMissingWait(const ento::mpi::Request & Req,const MemRegion * const RequestRegion,const ExplodedNode * const ExplNode,BugReporter & BReporter) const490b57cec5SDimitry Andric void MPIBugReporter::reportMissingWait(
500b57cec5SDimitry Andric     const ento::mpi::Request &Req, const MemRegion *const RequestRegion,
510b57cec5SDimitry Andric     const ExplodedNode *const ExplNode,
520b57cec5SDimitry Andric     BugReporter &BReporter) const {
530b57cec5SDimitry Andric   std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
540b57cec5SDimitry Andric                         " has no matching wait. "};
550b57cec5SDimitry Andric 
56*647cbc5dSDimitry Andric   auto Report = std::make_unique<PathSensitiveBugReport>(MissingWaitBugType,
57a7dea167SDimitry Andric                                                          ErrorText, ExplNode);
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   SourceRange Range = RequestRegion->sourceRange();
600b57cec5SDimitry Andric   if (Range.isValid())
610b57cec5SDimitry Andric     Report->addRange(Range);
62a7dea167SDimitry Andric   Report->addVisitor(std::make_unique<RequestNodeVisitor>(
630b57cec5SDimitry Andric       RequestRegion, "Request is previously used by nonblocking call here. "));
640b57cec5SDimitry Andric   Report->markInteresting(RequestRegion);
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   BReporter.emitReport(std::move(Report));
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
reportUnmatchedWait(const CallEvent & CE,const clang::ento::MemRegion * const RequestRegion,const ExplodedNode * const ExplNode,BugReporter & BReporter) const690b57cec5SDimitry Andric void MPIBugReporter::reportUnmatchedWait(
700b57cec5SDimitry Andric     const CallEvent &CE, const clang::ento::MemRegion *const RequestRegion,
710b57cec5SDimitry Andric     const ExplodedNode *const ExplNode,
720b57cec5SDimitry Andric     BugReporter &BReporter) const {
730b57cec5SDimitry Andric   std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
740b57cec5SDimitry Andric                         " has no matching nonblocking call. "};
750b57cec5SDimitry Andric 
76*647cbc5dSDimitry Andric   auto Report = std::make_unique<PathSensitiveBugReport>(UnmatchedWaitBugType,
77a7dea167SDimitry Andric                                                          ErrorText, ExplNode);
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   Report->addRange(CE.getSourceRange());
800b57cec5SDimitry Andric   SourceRange Range = RequestRegion->sourceRange();
810b57cec5SDimitry Andric   if (Range.isValid())
820b57cec5SDimitry Andric     Report->addRange(Range);
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   BReporter.emitReport(std::move(Report));
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
87a7dea167SDimitry Andric PathDiagnosticPieceRef
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)880b57cec5SDimitry Andric MPIBugReporter::RequestNodeVisitor::VisitNode(const ExplodedNode *N,
890b57cec5SDimitry Andric                                               BugReporterContext &BRC,
90a7dea167SDimitry Andric                                               PathSensitiveBugReport &BR) {
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   if (IsNodeFound)
930b57cec5SDimitry Andric     return nullptr;
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
96a7dea167SDimitry Andric   assert(Req && "The region must be tracked and alive, given that we've "
97a7dea167SDimitry Andric                 "just emitted a report against it");
980b57cec5SDimitry Andric   const Request *const PrevReq =
990b57cec5SDimitry Andric       N->getFirstPred()->getState()->get<RequestMap>(RequestRegion);
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   // Check if request was previously unused or in a different state.
102a7dea167SDimitry Andric   if (!PrevReq || (Req->CurrentState != PrevReq->CurrentState)) {
1030b57cec5SDimitry Andric     IsNodeFound = true;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric     ProgramPoint P = N->getFirstPred()->getLocation();
1060b57cec5SDimitry Andric     PathDiagnosticLocation L =
1070b57cec5SDimitry Andric         PathDiagnosticLocation::create(P, BRC.getSourceManager());
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric     return std::make_shared<PathDiagnosticEventPiece>(L, ErrorText);
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   return nullptr;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric } // end of namespace: mpi
1160b57cec5SDimitry Andric } // end of namespace: ento
1170b57cec5SDimitry Andric } // end of namespace: clang
118