/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 131 | CheckerContext &Ctx) const { |
27 | 131 | if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())131 ) { |
28 | 83 | return; |
29 | 83 | } |
30 | 48 | const MemRegion *const MR = |
31 | 48 | PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion(); |
32 | 48 | if (!MR) |
33 | 0 | return; |
34 | 48 | const ElementRegion *const ER = dyn_cast<ElementRegion>(MR); |
35 | 48 | |
36 | 48 | // The region must be typed, in order to reason about it. |
37 | 48 | if (!isa<TypedRegion>(MR) || 48 (ER && 48 !isa<TypedRegion>(ER->getSuperRegion())11 )) |
38 | 0 | return; |
39 | 48 | |
40 | 48 | ProgramStateRef State = Ctx.getState(); |
41 | 48 | const Request *const Req = State->get<RequestMap>(MR); |
42 | 48 | |
43 | 48 | // double nonblocking detected |
44 | 48 | if (Req && 48 Req->CurrentState == Request::State::Nonblocking11 ) { |
45 | 9 | ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode(); |
46 | 9 | BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode, |
47 | 9 | Ctx.getBugReporter()); |
48 | 9 | Ctx.addTransition(ErrorNode->getState(), ErrorNode); |
49 | 9 | } |
50 | 48 | // no error |
51 | 39 | else { |
52 | 39 | State = State->set<RequestMap>(MR, Request::State::Nonblocking); |
53 | 39 | Ctx.addTransition(State); |
54 | 39 | } |
55 | 131 | } |
56 | | |
57 | | void MPIChecker::checkUnmatchedWaits(const CallEvent &PreCallEvent, |
58 | 131 | CheckerContext &Ctx) const { |
59 | 131 | if (!FuncClassifier->isWaitType(PreCallEvent.getCalleeIdentifier())) |
60 | 86 | return; |
61 | 45 | const MemRegion *const MR = topRegionUsedByWait(PreCallEvent); |
62 | 45 | if (!MR) |
63 | 0 | return; |
64 | 45 | const ElementRegion *const ER = dyn_cast<ElementRegion>(MR); |
65 | 45 | |
66 | 45 | // The region must be typed, in order to reason about it. |
67 | 45 | if (!isa<TypedRegion>(MR) || 45 (ER && 45 !isa<TypedRegion>(ER->getSuperRegion())15 )) |
68 | 0 | return; |
69 | 45 | |
70 | 45 | llvm::SmallVector<const MemRegion *, 2> ReqRegions; |
71 | 45 | allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx); |
72 | 45 | if (ReqRegions.empty()) |
73 | 0 | return; |
74 | 45 | |
75 | 45 | ProgramStateRef State = Ctx.getState(); |
76 | 45 | static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait"); |
77 | 45 | ExplodedNode *ErrorNode{nullptr}; |
78 | 45 | |
79 | 45 | // Check all request regions used by the wait function. |
80 | 58 | for (const auto &ReqRegion : ReqRegions) { |
81 | 58 | const Request *const Req = State->get<RequestMap>(ReqRegion); |
82 | 58 | State = State->set<RequestMap>(ReqRegion, Request::State::Wait); |
83 | 58 | if (!Req58 ) { |
84 | 21 | if (!ErrorNode21 ) { |
85 | 16 | ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag); |
86 | 16 | State = ErrorNode->getState(); |
87 | 16 | } |
88 | 21 | // A wait has no matching nonblocking call. |
89 | 21 | BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode, |
90 | 21 | Ctx.getBugReporter()); |
91 | 21 | } |
92 | 58 | } |
93 | 45 | |
94 | 45 | if (!ErrorNode45 ) { |
95 | 29 | Ctx.addTransition(State); |
96 | 45 | } else { |
97 | 16 | Ctx.addTransition(State, ErrorNode); |
98 | 16 | } |
99 | 131 | } |
100 | | |
101 | | void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper, |
102 | 127 | CheckerContext &Ctx) const { |
103 | 127 | if (!SymReaper.hasDeadSymbols()) |
104 | 0 | return; |
105 | 127 | |
106 | 127 | ProgramStateRef State = Ctx.getState(); |
107 | 127 | const auto &Requests = State->get<RequestMap>(); |
108 | 127 | if (Requests.isEmpty()) |
109 | 31 | return; |
110 | 96 | |
111 | 96 | static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait"); |
112 | 96 | ExplodedNode *ErrorNode{nullptr}; |
113 | 96 | |
114 | 96 | auto ReqMap = State->get<RequestMap>(); |
115 | 146 | for (const auto &Req : ReqMap) { |
116 | 146 | if (!SymReaper.isLiveRegion(Req.first)146 ) { |
117 | 56 | if (Req.second.CurrentState == Request::State::Nonblocking56 ) { |
118 | 4 | |
119 | 4 | if (!ErrorNode4 ) { |
120 | 4 | ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag); |
121 | 4 | State = ErrorNode->getState(); |
122 | 4 | } |
123 | 4 | BReporter.reportMissingWait(Req.second, Req.first, ErrorNode, |
124 | 4 | Ctx.getBugReporter()); |
125 | 4 | } |
126 | 56 | State = State->remove<RequestMap>(Req.first); |
127 | 56 | } |
128 | 146 | } |
129 | 96 | |
130 | 96 | // Transition to update the state regarding removed requests. |
131 | 96 | if (!ErrorNode96 ) { |
132 | 92 | Ctx.addTransition(State); |
133 | 96 | } else { |
134 | 4 | Ctx.addTransition(State, ErrorNode); |
135 | 4 | } |
136 | 127 | } |
137 | | |
138 | 45 | const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const { |
139 | 45 | |
140 | 45 | if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())45 ) { |
141 | 39 | return CE.getArgSVal(0).getAsRegion(); |
142 | 6 | } else if (6 FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())6 ) { |
143 | 6 | return CE.getArgSVal(1).getAsRegion(); |
144 | 0 | } else { |
145 | 0 | return (const MemRegion *)nullptr; |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | | void MPIChecker::allRegionsUsedByWait( |
150 | | llvm::SmallVector<const MemRegion *, 2> &ReqRegions, |
151 | 45 | const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const { |
152 | 45 | |
153 | 45 | MemRegionManager *const RegionManager = MR->getMemRegionManager(); |
154 | 45 | |
155 | 45 | if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())45 ) { |
156 | 6 | const SubRegion *SuperRegion{nullptr}; |
157 | 6 | if (const ElementRegion *const ER6 = MR->getAs<ElementRegion>()) { |
158 | 5 | SuperRegion = cast<SubRegion>(ER->getSuperRegion()); |
159 | 5 | } |
160 | 6 | |
161 | 6 | // A single request is passed to MPI_Waitall. |
162 | 6 | if (!SuperRegion6 ) { |
163 | 1 | ReqRegions.push_back(MR); |
164 | 1 | return; |
165 | 1 | } |
166 | 5 | |
167 | 5 | const auto &Size = Ctx.getStoreManager().getSizeInElements( |
168 | 5 | Ctx.getState(), SuperRegion, |
169 | 5 | CE.getArgExpr(1)->getType()->getPointeeType()); |
170 | 5 | const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue(); |
171 | 5 | |
172 | 23 | for (size_t i = 0; i < ArrSize23 ; ++i18 ) { |
173 | 18 | const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i); |
174 | 18 | |
175 | 18 | const ElementRegion *const ER = RegionManager->getElementRegion( |
176 | 18 | CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion, |
177 | 18 | Ctx.getASTContext()); |
178 | 18 | |
179 | 18 | ReqRegions.push_back(ER->getAs<MemRegion>()); |
180 | 18 | } |
181 | 45 | } else if (39 FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())39 ) { |
182 | 39 | ReqRegions.push_back(MR); |
183 | 39 | } |
184 | 45 | } |
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 | 3 | void clang::ento::registerMPIChecker(CheckerManager &MGR) { |
192 | 3 | MGR.registerChecker<clang::ento::mpi::MPIChecker>(); |
193 | 3 | } |