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