clang  9.0.0svn
MPIChecker.cpp
Go to the documentation of this file.
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 //===----------------------------------------------------------------------===//
16 
17 #include "MPIChecker.h"
19 
20 namespace clang {
21 namespace ento {
22 namespace mpi {
23 
25  CheckerContext &Ctx) const {
26  if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
27  return;
28  }
29  const MemRegion *const MR =
30  PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
31  if (!MR)
32  return;
33  const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
34 
35  // The region must be typed, in order to reason about it.
36  if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
37  return;
38 
40  const Request *const Req = State->get<RequestMap>(MR);
41 
42  // double nonblocking detected
43  if (Req && Req->CurrentState == Request::State::Nonblocking) {
44  ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
45  BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
46  Ctx.getBugReporter());
47  Ctx.addTransition(ErrorNode->getState(), ErrorNode);
48  }
49  // no error
50  else {
51  State = State->set<RequestMap>(MR, Request::State::Nonblocking);
52  Ctx.addTransition(State);
53  }
54 }
55 
56 void MPIChecker::checkUnmatchedWaits(const CallEvent &PreCallEvent,
57  CheckerContext &Ctx) const {
58  if (!FuncClassifier->isWaitType(PreCallEvent.getCalleeIdentifier()))
59  return;
60  const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
61  if (!MR)
62  return;
63  const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
64 
65  // The region must be typed, in order to reason about it.
66  if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
67  return;
68 
70  allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
71  if (ReqRegions.empty())
72  return;
73 
75  static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait");
76  ExplodedNode *ErrorNode{nullptr};
77 
78  // Check all request regions used by the wait function.
79  for (const auto &ReqRegion : ReqRegions) {
80  const Request *const Req = State->get<RequestMap>(ReqRegion);
81  State = State->set<RequestMap>(ReqRegion, Request::State::Wait);
82  if (!Req) {
83  if (!ErrorNode) {
84  ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
85  State = ErrorNode->getState();
86  }
87  // A wait has no matching nonblocking call.
88  BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode,
89  Ctx.getBugReporter());
90  }
91  }
92 
93  if (!ErrorNode) {
94  Ctx.addTransition(State);
95  } else {
96  Ctx.addTransition(State, ErrorNode);
97  }
98 }
99 
101  CheckerContext &Ctx) const {
103  const auto &Requests = State->get<RequestMap>();
104  if (Requests.isEmpty())
105  return;
106 
107  static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait");
108  ExplodedNode *ErrorNode{nullptr};
109 
110  auto ReqMap = State->get<RequestMap>();
111  for (const auto &Req : ReqMap) {
112  if (!SymReaper.isLiveRegion(Req.first)) {
113  if (Req.second.CurrentState == Request::State::Nonblocking) {
114 
115  if (!ErrorNode) {
116  ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
117  State = ErrorNode->getState();
118  }
119  BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,
120  Ctx.getBugReporter());
121  }
122  State = State->remove<RequestMap>(Req.first);
123  }
124  }
125 
126  // Transition to update the state regarding removed requests.
127  if (!ErrorNode) {
128  Ctx.addTransition(State);
129  } else {
130  Ctx.addTransition(State, ErrorNode);
131  }
132 }
133 
134 const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const {
135 
136  if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
137  return CE.getArgSVal(0).getAsRegion();
138  } else if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
139  return CE.getArgSVal(1).getAsRegion();
140  } else {
141  return (const MemRegion *)nullptr;
142  }
143 }
144 
145 void MPIChecker::allRegionsUsedByWait(
147  const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {
148 
149  MemRegionManager *const RegionManager = MR->getMemRegionManager();
150 
151  if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
152  const SubRegion *SuperRegion{nullptr};
153  if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
154  SuperRegion = cast<SubRegion>(ER->getSuperRegion());
155  }
156 
157  // A single request is passed to MPI_Waitall.
158  if (!SuperRegion) {
159  ReqRegions.push_back(MR);
160  return;
161  }
162 
163  const auto &Size = Ctx.getStoreManager().getSizeInElements(
164  Ctx.getState(), SuperRegion,
165  CE.getArgExpr(1)->getType()->getPointeeType());
166  const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();
167 
168  for (size_t i = 0; i < ArrSize; ++i) {
169  const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
170 
171  const ElementRegion *const ER = RegionManager->getElementRegion(
172  CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
173  Ctx.getASTContext());
174 
175  ReqRegions.push_back(ER->getAs<MemRegion>());
176  }
177  } else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
178  ReqRegions.push_back(MR);
179  }
180 }
181 
182 } // end of namespace: mpi
183 } // end of namespace: ento
184 } // end of namespace: clang
185 
186 // Registers the checker for static analysis.
187 void clang::ento::registerMPIChecker(CheckerManager &MGR) {
189 }
190 
191 bool clang::ento::shouldRegisterMPIChecker(const LangOptions &LO) {
192  return true;
193 }
virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, const MemRegion *region, QualType EleTy)
Definition: Store.h:153
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:94
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:505
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
const ProgramStateRef & getState() const
Value representing integer constant.
Definition: SVals.h:379
NonLoc makeArrayIndex(uint64_t idx)
Definition: SValBuilder.h:272
void checkDoubleNonblocking(const clang::ento::CallEvent &PreCallEvent, clang::ento::CheckerContext &Ctx) const
Checks if a request is used by nonblocking calls multiple times in sequence without intermediate wait...
Definition: MPIChecker.cpp:24
long i
Definition: xmmintrin.h:1456
const MemRegion * getSuperRegion() const
Definition: MemRegion.h:447
void reportDoubleNonblocking(const CallEvent &MPICallEvent, const Request &Req, const MemRegion *const RequestRegion, const ExplodedNode *const ExplNode, BugReporter &BReporter) const
Report duplicate request use by nonblocking calls without intermediate wait.
LineState State
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
Definition: CallEvent.h:272
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
BugReporter & getBugReporter()
void reportUnmatchedWait(const CallEvent &CE, const MemRegion *const RequestRegion, const ExplodedNode *const ExplNode, BugReporter &BReporter) const
Report a wait on a request that has not been used at all before.
bool isLiveRegion(const MemRegion *region)
void reportMissingWait(const Request &Req, const MemRegion *const RequestRegion, const ExplodedNode *const ExplNode, BugReporter &BReporter) const
Report a missing wait for a nonblocking call.
const RegionTy * getAs() const
Definition: MemRegion.h:1227
const State CurrentState
Definition: MPITypes.h:41
This file defines the main class of MPI-Checker which serves as an entry point.
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
Definition: CallEvent.h:332
static SVal getValue(SVal val, SValBuilder &svalBuilder)
QualType getType() const
Definition: Expr.h:137
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:111
StoreManager & getStoreManager()
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const MemRegion * getAsRegion() const
Definition: SVals.cpp:151
A class responsible for cleaning up unused symbols.
Dataflow Directional Tag Classes.
const ElementRegion * getElementRegion(QualType elementType, NonLoc Idx, const SubRegion *superRegion, ASTContext &Ctx)
getElementRegion - Retrieve the memory region associated with the associated element type...
Definition: MemRegion.cpp:989
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:138
virtual MemRegionManager * getMemRegionManager() const =0
SubRegion - A region that subsets another larger region.
Definition: MemRegion.h:435
const ProgramStateRef & getState() const
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SValBuilder & getSValBuilder()
ElementRegion is used to represent both array elements and casts.
Definition: MemRegion.h:1082
void checkUnmatchedWaits(const clang::ento::CallEvent &PreCallEvent, clang::ento::CheckerContext &Ctx) const
Checks if the request used by the wait function was not used at all before.
Definition: MPIChecker.cpp:56
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
Definition: CallEvent.cpp:411
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
Definition: Checker.h:510
void checkMissingWaits(clang::ento::SymbolReaper &SymReaper, clang::ento::CheckerContext &Ctx) const
Check if a nonblocking call is not matched by a wait.
Definition: MPIChecker.cpp:100