xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.h (revision e5dd70708596ae51455a0ffa086a00c5b29f8583)
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