]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
Update clang to trunk r290819 and resolve conflicts.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / MPI-Checker / MPIChecker.cpp
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
25 void 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();
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
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.
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
101 void 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         }
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(
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())) {
156     const MemRegion *SuperRegion{nullptr};
157     if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
158       SuperRegion = 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) {
192   MGR.registerChecker<clang::ento::mpi::MPIChecker>();
193 }