1 //===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
15 //===----------------------------------------------------------------------===//
17 #include "MPIChecker.h"
18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
25 void MPIChecker::checkDoubleNonblocking(const CallEvent
&PreCallEvent
,
26 CheckerContext
&Ctx
) const {
27 if (!FuncClassifier
->isNonBlockingType(PreCallEvent
.getCalleeIdentifier())) {
30 const MemRegion
*const MR
=
31 PreCallEvent
.getArgSVal(PreCallEvent
.getNumArgs() - 1).getAsRegion();
34 const ElementRegion
*const ER
= dyn_cast
<ElementRegion
>(MR
);
36 // The region must be typed, in order to reason about it.
37 if (!isa
<TypedRegion
>(MR
) || (ER
&& !isa
<TypedRegion
>(ER
->getSuperRegion())))
40 ProgramStateRef State
= Ctx
.getState();
41 const Request
*const Req
= State
->get
<RequestMap
>(MR
);
43 // double nonblocking detected
44 if (Req
&& Req
->CurrentState
== Request::State::Nonblocking
) {
45 ExplodedNode
*ErrorNode
= Ctx
.generateNonFatalErrorNode();
46 BReporter
.reportDoubleNonblocking(PreCallEvent
, *Req
, MR
, ErrorNode
,
47 Ctx
.getBugReporter());
48 Ctx
.addTransition(ErrorNode
->getState(), ErrorNode
);
52 State
= State
->set
<RequestMap
>(MR
, Request::State::Nonblocking
);
53 Ctx
.addTransition(State
);
57 void MPIChecker::checkUnmatchedWaits(const CallEvent
&PreCallEvent
,
58 CheckerContext
&Ctx
) const {
59 if (!FuncClassifier
->isWaitType(PreCallEvent
.getCalleeIdentifier()))
61 const MemRegion
*const MR
= topRegionUsedByWait(PreCallEvent
);
64 const ElementRegion
*const ER
= dyn_cast
<ElementRegion
>(MR
);
66 // The region must be typed, in order to reason about it.
67 if (!isa
<TypedRegion
>(MR
) || (ER
&& !isa
<TypedRegion
>(ER
->getSuperRegion())))
70 llvm::SmallVector
<const MemRegion
*, 2> ReqRegions
;
71 allRegionsUsedByWait(ReqRegions
, MR
, PreCallEvent
, Ctx
);
72 if (ReqRegions
.empty())
75 ProgramStateRef State
= Ctx
.getState();
76 static CheckerProgramPointTag
Tag("MPI-Checker", "UnmatchedWait");
77 ExplodedNode
*ErrorNode
{nullptr};
79 // Check all request regions used by the wait function.
80 for (const auto &ReqRegion
: ReqRegions
) {
81 const Request
*const Req
= State
->get
<RequestMap
>(ReqRegion
);
82 State
= State
->set
<RequestMap
>(ReqRegion
, Request::State::Wait
);
85 ErrorNode
= Ctx
.generateNonFatalErrorNode(State
, &Tag
);
86 State
= ErrorNode
->getState();
88 // A wait has no matching nonblocking call.
89 BReporter
.reportUnmatchedWait(PreCallEvent
, ReqRegion
, ErrorNode
,
90 Ctx
.getBugReporter());
95 Ctx
.addTransition(State
);
97 Ctx
.addTransition(State
, ErrorNode
);
101 void MPIChecker::checkMissingWaits(SymbolReaper
&SymReaper
,
102 CheckerContext
&Ctx
) const {
103 ProgramStateRef State
= Ctx
.getState();
104 const auto &Requests
= State
->get
<RequestMap
>();
105 if (Requests
.isEmpty())
108 static CheckerProgramPointTag
Tag("MPI-Checker", "MissingWait");
109 ExplodedNode
*ErrorNode
{nullptr};
111 auto ReqMap
= State
->get
<RequestMap
>();
112 for (const auto &Req
: ReqMap
) {
113 if (!SymReaper
.isLiveRegion(Req
.first
)) {
114 if (Req
.second
.CurrentState
== Request::State::Nonblocking
) {
117 ErrorNode
= Ctx
.generateNonFatalErrorNode(State
, &Tag
);
118 State
= ErrorNode
->getState();
120 BReporter
.reportMissingWait(Req
.second
, Req
.first
, ErrorNode
,
121 Ctx
.getBugReporter());
123 State
= State
->remove
<RequestMap
>(Req
.first
);
127 // Transition to update the state regarding removed requests.
129 Ctx
.addTransition(State
);
131 Ctx
.addTransition(State
, ErrorNode
);
135 const MemRegion
*MPIChecker::topRegionUsedByWait(const CallEvent
&CE
) const {
137 if (FuncClassifier
->isMPI_Wait(CE
.getCalleeIdentifier())) {
138 return CE
.getArgSVal(0).getAsRegion();
139 } else if (FuncClassifier
->isMPI_Waitall(CE
.getCalleeIdentifier())) {
140 return CE
.getArgSVal(1).getAsRegion();
142 return (const MemRegion
*)nullptr;
146 void MPIChecker::allRegionsUsedByWait(
147 llvm::SmallVector
<const MemRegion
*, 2> &ReqRegions
,
148 const MemRegion
*const MR
, const CallEvent
&CE
, CheckerContext
&Ctx
) const {
150 MemRegionManager
&RegionManager
= MR
->getMemRegionManager();
152 if (FuncClassifier
->isMPI_Waitall(CE
.getCalleeIdentifier())) {
153 const SubRegion
*SuperRegion
{nullptr};
154 if (const ElementRegion
*const ER
= MR
->getAs
<ElementRegion
>()) {
155 SuperRegion
= cast
<SubRegion
>(ER
->getSuperRegion());
158 // A single request is passed to MPI_Waitall.
160 ReqRegions
.push_back(MR
);
164 DefinedOrUnknownSVal ElementCount
= getDynamicElementCount(
165 Ctx
.getState(), SuperRegion
, Ctx
.getSValBuilder(),
166 CE
.getArgExpr(1)->getType()->getPointeeType());
167 const llvm::APSInt
&ArrSize
=
168 ElementCount
.castAs
<nonloc::ConcreteInt
>().getValue();
170 for (size_t i
= 0; i
< ArrSize
; ++i
) {
171 const NonLoc Idx
= Ctx
.getSValBuilder().makeArrayIndex(i
);
173 const ElementRegion
*const ER
= RegionManager
.getElementRegion(
174 CE
.getArgExpr(1)->getType()->getPointeeType(), Idx
, SuperRegion
,
175 Ctx
.getASTContext());
177 ReqRegions
.push_back(ER
->getAs
<MemRegion
>());
179 } else if (FuncClassifier
->isMPI_Wait(CE
.getCalleeIdentifier())) {
180 ReqRegions
.push_back(MR
);
184 } // end of namespace: mpi
185 } // end of namespace: ento
186 } // end of namespace: clang
188 // Registers the checker for static analysis.
189 void clang::ento::registerMPIChecker(CheckerManager
&MGR
) {
190 MGR
.registerChecker
<clang::ento::mpi::MPIChecker
>();
193 bool clang::ento::shouldRegisterMPIChecker(const CheckerManager
&mgr
) {