[DFAJumpThreading] Remove incoming StartBlock from all phis when unfolding select...
[llvm-project.git] / clang / lib / StaticAnalyzer / Checkers / MPI-Checker / MPIChecker.cpp
blob4c0a8ba2c7c0948b0301711d80ee4e3f1af94886
1 //===-- MPIChecker.cpp - Checker Entry Point Class --------------*- 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 //===----------------------------------------------------------------------===//
17 #include "MPIChecker.h"
18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
21 namespace clang {
22 namespace ento {
23 namespace mpi {
25 void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
26 CheckerContext &Ctx) const {
27 if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
28 return;
30 const MemRegion *const MR =
31 PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
32 if (!MR)
33 return;
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())))
38 return;
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);
50 // no error
51 else {
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()))
60 return;
61 const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
62 if (!MR)
63 return;
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())))
68 return;
70 llvm::SmallVector<const MemRegion *, 2> ReqRegions;
71 allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
72 if (ReqRegions.empty())
73 return;
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);
83 if (!Req) {
84 if (!ErrorNode) {
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());
94 if (!ErrorNode) {
95 Ctx.addTransition(State);
96 } else {
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())
106 return;
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) {
116 if (!ErrorNode) {
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.
128 if (!ErrorNode) {
129 Ctx.addTransition(State);
130 } else {
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();
141 } else {
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.
159 if (!SuperRegion) {
160 ReqRegions.push_back(MR);
161 return;
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) {
194 return true;