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