blob: 696cf39473d54b577ba50baf98c2df495184ef28 [file] [log] [blame]
Devin Coughlin160f19c2016-06-13 03:22:41 +00001//===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// This file defines the main class of MPI-Checker which serves as an entry
12/// point. It is created once for each translation unit analysed.
13/// The checker defines path-sensitive checks, to verify correct usage of the
14/// MPI API.
15///
16//===----------------------------------------------------------------------===//
17
18#include "MPIChecker.h"
19#include "../ClangSACheckers.h"
20
21namespace clang {
22namespace ento {
23namespace mpi {
24
25void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
26 CheckerContext &Ctx) const {
27 if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
28 return;
29 }
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);
35
36 // The region must be typed, in order to reason about it.
37 if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
38 return;
39
40 ProgramStateRef State = Ctx.getState();
41 const Request *const Req = State->get<RequestMap>(MR);
42
43 // double nonblocking detected
44 if (Req && Req->CurrentState == Request::State::Nonblocking) {
45 ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
Alexander Kornienkoc5e50932016-07-25 15:27:16 +000046 BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
47 Ctx.getBugReporter());
Devin Coughlin160f19c2016-06-13 03:22:41 +000048 Ctx.addTransition(ErrorNode->getState(), ErrorNode);
49 }
50 // no error
51 else {
52 State = State->set<RequestMap>(MR, Request::State::Nonblocking);
53 Ctx.addTransition(State);
54 }
55}
56
57void 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);
65
66 // The region must be typed, in order to reason about it.
67 if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
68 return;
69
70 llvm::SmallVector<const MemRegion *, 2> ReqRegions;
71 allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
72 if (ReqRegions.empty())
73 return;
74
75 ProgramStateRef State = Ctx.getState();
76 static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait");
77 ExplodedNode *ErrorNode{nullptr};
78
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();
87 }
88 // A wait has no matching nonblocking call.
Alexander Kornienkoc5e50932016-07-25 15:27:16 +000089 BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode,
90 Ctx.getBugReporter());
Devin Coughlin160f19c2016-06-13 03:22:41 +000091 }
92 }
93
94 if (!ErrorNode) {
95 Ctx.addTransition(State);
96 } else {
97 Ctx.addTransition(State, ErrorNode);
98 }
99}
100
101void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
102 CheckerContext &Ctx) const {
103 if (!SymReaper.hasDeadSymbols())
104 return;
105
106 ProgramStateRef State = Ctx.getState();
107 const auto &Requests = State->get<RequestMap>();
108 if (Requests.isEmpty())
109 return;
110
111 static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait");
112 ExplodedNode *ErrorNode{nullptr};
113
114 auto ReqMap = State->get<RequestMap>();
115 for (const auto &Req : ReqMap) {
116 if (!SymReaper.isLiveRegion(Req.first)) {
117 if (Req.second.CurrentState == Request::State::Nonblocking) {
118
119 if (!ErrorNode) {
120 ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
121 State = ErrorNode->getState();
122 }
Alexander Kornienkoc5e50932016-07-25 15:27:16 +0000123 BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,
124 Ctx.getBugReporter());
Devin Coughlin160f19c2016-06-13 03:22:41 +0000125 }
126 State = State->remove<RequestMap>(Req.first);
127 }
128 }
129
130 // Transition to update the state regarding removed requests.
131 if (!ErrorNode) {
132 Ctx.addTransition(State);
133 } else {
134 Ctx.addTransition(State, ErrorNode);
135 }
136}
137
138const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const {
139
140 if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
141 return CE.getArgSVal(0).getAsRegion();
142 } else if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
143 return CE.getArgSVal(1).getAsRegion();
144 } else {
145 return (const MemRegion *)nullptr;
146 }
147}
148
149void MPIChecker::allRegionsUsedByWait(
150 llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
151 const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {
152
153 MemRegionManager *const RegionManager = MR->getMemRegionManager();
154
155 if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
Artem Dergachev6dd11042017-04-13 09:56:07 +0000156 const SubRegion *SuperRegion{nullptr};
Devin Coughlin160f19c2016-06-13 03:22:41 +0000157 if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
Artem Dergachev6dd11042017-04-13 09:56:07 +0000158 SuperRegion = cast<SubRegion>(ER->getSuperRegion());
Devin Coughlin160f19c2016-06-13 03:22:41 +0000159 }
160
161 // A single request is passed to MPI_Waitall.
162 if (!SuperRegion) {
163 ReqRegions.push_back(MR);
164 return;
165 }
166
167 const auto &Size = Ctx.getStoreManager().getSizeInElements(
168 Ctx.getState(), SuperRegion,
169 CE.getArgExpr(1)->getType()->getPointeeType());
170 const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();
171
172 for (size_t i = 0; i < ArrSize; ++i) {
173 const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
174
175 const ElementRegion *const ER = RegionManager->getElementRegion(
176 CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
177 Ctx.getASTContext());
178
179 ReqRegions.push_back(ER->getAs<MemRegion>());
180 }
181 } else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
182 ReqRegions.push_back(MR);
183 }
184}
185
186} // end of namespace: mpi
187} // end of namespace: ento
188} // end of namespace: clang
189
190// Registers the checker for static analysis.
191void clang::ento::registerMPIChecker(CheckerManager &MGR) {
192 MGR.registerChecker<clang::ento::mpi::MPIChecker>();
193}