clang  6.0.0svn
MPIChecker.cpp
Go to the documentation of this file.
1 //===-- 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 
21 namespace clang {
22 namespace ento {
23 namespace mpi {
24 
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 
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();
46  BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
47  Ctx.getBugReporter());
48  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 
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);
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 
71  allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
72  if (ReqRegions.empty())
73  return;
74 
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.
89  BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode,
90  Ctx.getBugReporter());
91  }
92  }
93 
94  if (!ErrorNode) {
95  Ctx.addTransition(State);
96  } else {
97  Ctx.addTransition(State, ErrorNode);
98  }
99 }
100 
102  CheckerContext &Ctx) const {
103  if (!SymReaper.hasDeadSymbols())
104  return;
105 
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  }
123  BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,
124  Ctx.getBugReporter());
125  }
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 
138 const 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 
149 void MPIChecker::allRegionsUsedByWait(
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())) {
156  const SubRegion *SuperRegion{nullptr};
157  if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
158  SuperRegion = cast<SubRegion>(ER->getSuperRegion());
159  }
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.
191 void clang::ento::registerMPIChecker(CheckerManager &MGR) {
193 }
virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, const MemRegion *region, QualType EleTy)
Definition: Store.h:129
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:415
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:352
NonLoc makeArrayIndex(uint64_t idx)
Definition: SValBuilder.h:248
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:25
const MemRegion * getSuperRegion() const
Definition: MemRegion.h:430
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:275
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:1174
const State CurrentState
Definition: MPITypes.h:42
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:335
static SVal getValue(SVal val, SValBuilder &svalBuilder)
QualType getType() const
Definition: Expr.h:128
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:100
CHECKER * registerChecker()
Used to register checkers.
StoreManager & getStoreManager()
const MemRegion * getAsRegion() const
Definition: SVals.cpp:140
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:923
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:140
virtual MemRegionManager * getMemRegionManager() const =0
SubRegion - A region that subsets another larger region.
Definition: MemRegion.h:419
const ProgramStateRef & getState() const
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SValBuilder & getSValBuilder()
ElementRegin is used to represent both array elements and casts.
Definition: MemRegion.h:1066
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:57
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
Definition: CallEvent.cpp:226
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
Definition: Checker.h:493
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:101