1*e5dd7070Spatrick //===-- MPIChecker.h - Verify MPI API usage- --------------------*- C++ -*-===// 2*e5dd7070Spatrick // 3*e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5*e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*e5dd7070Spatrick // 7*e5dd7070Spatrick //===----------------------------------------------------------------------===// 8*e5dd7070Spatrick /// 9*e5dd7070Spatrick /// \file 10*e5dd7070Spatrick /// This file defines the main class of MPI-Checker which serves as an entry 11*e5dd7070Spatrick /// point. It is created once for each translation unit analysed. 12*e5dd7070Spatrick /// The checker defines path-sensitive checks, to verify correct usage of the 13*e5dd7070Spatrick /// MPI API. 14*e5dd7070Spatrick /// 15*e5dd7070Spatrick //===----------------------------------------------------------------------===// 16*e5dd7070Spatrick 17*e5dd7070Spatrick #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKER_H 18*e5dd7070Spatrick #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKER_H 19*e5dd7070Spatrick 20*e5dd7070Spatrick #include "MPIBugReporter.h" 21*e5dd7070Spatrick #include "MPITypes.h" 22*e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h" 23*e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 24*e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25*e5dd7070Spatrick 26*e5dd7070Spatrick namespace clang { 27*e5dd7070Spatrick namespace ento { 28*e5dd7070Spatrick namespace mpi { 29*e5dd7070Spatrick 30*e5dd7070Spatrick class MPIChecker : public Checker<check::PreCall, check::DeadSymbols> { 31*e5dd7070Spatrick public: MPIChecker()32*e5dd7070Spatrick MPIChecker() : BReporter(*this) {} 33*e5dd7070Spatrick 34*e5dd7070Spatrick // path-sensitive callbacks checkPreCall(const CallEvent & CE,CheckerContext & Ctx)35*e5dd7070Spatrick void checkPreCall(const CallEvent &CE, CheckerContext &Ctx) const { 36*e5dd7070Spatrick dynamicInit(Ctx); 37*e5dd7070Spatrick checkUnmatchedWaits(CE, Ctx); 38*e5dd7070Spatrick checkDoubleNonblocking(CE, Ctx); 39*e5dd7070Spatrick } 40*e5dd7070Spatrick checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & Ctx)41*e5dd7070Spatrick void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &Ctx) const { 42*e5dd7070Spatrick dynamicInit(Ctx); 43*e5dd7070Spatrick checkMissingWaits(SymReaper, Ctx); 44*e5dd7070Spatrick } 45*e5dd7070Spatrick dynamicInit(CheckerContext & Ctx)46*e5dd7070Spatrick void dynamicInit(CheckerContext &Ctx) const { 47*e5dd7070Spatrick if (FuncClassifier) 48*e5dd7070Spatrick return; 49*e5dd7070Spatrick const_cast<std::unique_ptr<MPIFunctionClassifier> &>(FuncClassifier) 50*e5dd7070Spatrick .reset(new MPIFunctionClassifier{Ctx.getASTContext()}); 51*e5dd7070Spatrick } 52*e5dd7070Spatrick 53*e5dd7070Spatrick /// Checks if a request is used by nonblocking calls multiple times 54*e5dd7070Spatrick /// in sequence without intermediate wait. The check contains a guard, 55*e5dd7070Spatrick /// in order to only inspect nonblocking functions. 56*e5dd7070Spatrick /// 57*e5dd7070Spatrick /// \param PreCallEvent MPI call to verify 58*e5dd7070Spatrick void checkDoubleNonblocking(const clang::ento::CallEvent &PreCallEvent, 59*e5dd7070Spatrick clang::ento::CheckerContext &Ctx) const; 60*e5dd7070Spatrick 61*e5dd7070Spatrick /// Checks if the request used by the wait function was not used at all 62*e5dd7070Spatrick /// before. The check contains a guard, in order to only inspect wait 63*e5dd7070Spatrick /// functions. 64*e5dd7070Spatrick /// 65*e5dd7070Spatrick /// \param PreCallEvent MPI call to verify 66*e5dd7070Spatrick void checkUnmatchedWaits(const clang::ento::CallEvent &PreCallEvent, 67*e5dd7070Spatrick clang::ento::CheckerContext &Ctx) const; 68*e5dd7070Spatrick 69*e5dd7070Spatrick /// Check if a nonblocking call is not matched by a wait. 70*e5dd7070Spatrick /// If a memory region is not alive and the last function using the 71*e5dd7070Spatrick /// request was a nonblocking call, this is rated as a missing wait. 72*e5dd7070Spatrick void checkMissingWaits(clang::ento::SymbolReaper &SymReaper, 73*e5dd7070Spatrick clang::ento::CheckerContext &Ctx) const; 74*e5dd7070Spatrick 75*e5dd7070Spatrick private: 76*e5dd7070Spatrick /// Collects all memory regions of a request(array) used by a wait 77*e5dd7070Spatrick /// function. If the wait function uses a single request, this is a single 78*e5dd7070Spatrick /// region. For wait functions using multiple requests, multiple regions 79*e5dd7070Spatrick /// representing elements in the array are collected. 80*e5dd7070Spatrick /// 81*e5dd7070Spatrick /// \param ReqRegions vector the regions get pushed into 82*e5dd7070Spatrick /// \param MR top most region to iterate 83*e5dd7070Spatrick /// \param CE MPI wait call using the request(s) 84*e5dd7070Spatrick void allRegionsUsedByWait( 85*e5dd7070Spatrick llvm::SmallVector<const clang::ento::MemRegion *, 2> &ReqRegions, 86*e5dd7070Spatrick const clang::ento::MemRegion *const MR, const clang::ento::CallEvent &CE, 87*e5dd7070Spatrick clang::ento::CheckerContext &Ctx) const; 88*e5dd7070Spatrick 89*e5dd7070Spatrick /// Returns the memory region used by a wait function. 90*e5dd7070Spatrick /// Distinguishes between MPI_Wait and MPI_Waitall. 91*e5dd7070Spatrick /// 92*e5dd7070Spatrick /// \param CE MPI wait call 93*e5dd7070Spatrick const clang::ento::MemRegion * 94*e5dd7070Spatrick topRegionUsedByWait(const clang::ento::CallEvent &CE) const; 95*e5dd7070Spatrick 96*e5dd7070Spatrick const std::unique_ptr<MPIFunctionClassifier> FuncClassifier; 97*e5dd7070Spatrick MPIBugReporter BReporter; 98*e5dd7070Spatrick }; 99*e5dd7070Spatrick 100*e5dd7070Spatrick } // end of namespace: mpi 101*e5dd7070Spatrick } // end of namespace: ento 102*e5dd7070Spatrick } // end of namespace: clang 103*e5dd7070Spatrick 104*e5dd7070Spatrick #endif 105