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