clang 10.0.0git

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"
18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19
20 namespace clang {
21 namespace ento {
22 namespace mpi {
23
24 void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
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
39 ProgramStateRef State = Ctx.getState();
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
69 llvm::SmallVector<const MemRegion *, 2> ReqRegions;
70 allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
71 if (ReqRegions.empty())
72 return;
73
74 ProgramStateRef State = Ctx.getState();
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
100 void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
101 CheckerContext &Ctx) const {
102 ProgramStateRef State = Ctx.getState();
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(
146 llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
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) {
188 MGR.registerChecker<clang::ento::mpi::MPIChecker>();
189 }
190
191 bool clang::ento::shouldRegisterMPIChecker(const LangOptions &LO) {
192 return true;
193 }
ento
clang::ento::StoreManager::getSizeInElements
virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, const MemRegion *region, QualType EleTy)
Definition: Store.h:153
clang::ento::mpi::RequestMap
Definition: MPITypes.h:48
clang::ento::MemRegion
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:94
clang::Type::getPointeeType
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:557
clang::ento::CheckerContext::addTransition
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Definition: CheckerContext.h:164
clang::ento::ExplodedNode::getState
const ProgramStateRef & getState() const
Definition: ExplodedGraph.h:169
clang::ento::nonloc::ConcreteInt
Value representing integer constant.
Definition: SVals.h:379
clang::ento::SValBuilder::makeArrayIndex
NonLoc makeArrayIndex(uint64_t idx)
Definition: SValBuilder.h:272
clang::ento::mpi::MPIChecker::checkDoubleNonblocking
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
clang::ento::CheckerManager
Definition: CheckerManager.h:123
clang::ento::SubRegion::getSuperRegion
const MemRegion * getSuperRegion() const
Definition: MemRegion.h:448
clang::ento::mpi::MPIBugReporter::reportDoubleNonblocking
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.
Definition: MPIBugReporter.cpp:23
State
LineState State
Definition: UnwrappedLineFormatter.cpp:932
clang::ento::CallEvent::getArgExpr
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
Definition: CallEvent.h:272
clang::ento::ExplodedNode
Definition: ExplodedGraph.h:65
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:53
clang::ento::CheckerContext::getBugReporter
BugReporter & getBugReporter()
Definition: CheckerContext.h:102
clang::ento::mpi::MPIChecker
Definition: MPIChecker.h:30
clang::ento::mpi::MPIBugReporter::reportUnmatchedWait
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.
Definition: MPIBugReporter.cpp:69
clang::ento::CheckerContext
Definition: CheckerContext.h:23
clang::ento::SymbolReaper::isLiveRegion
bool isLiveRegion(const MemRegion *region)
Definition: SymbolManager.cpp:427
clang::ento::mpi::MPIBugReporter::reportMissingWait
void reportMissingWait(const Request &Req, const MemRegion *const RequestRegion, const ExplodedNode *const ExplNode, BugReporter &BReporter) const
Report a missing wait for a nonblocking call.
Definition: MPIBugReporter.cpp:49
clang::ento::MemRegion::getAs
const RegionTy * getAs() const
Definition: MemRegion.h:1228
clang::ento::mpi::Request::CurrentState
const State CurrentState
Definition: MPITypes.h:41
MPIChecker.h
This file defines the main class of MPI-Checker which serves as an entry point.
clang::ento::CallEvent::getCalleeIdentifier
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
Definition: CallEvent.h:332
getValue
static SVal getValue(SVal val, SValBuilder &svalBuilder)
Definition: ArrayBoundCheckerV2.cpp:277
clang::Expr::getType
QualType getType() const
Definition: Expr.h:137
clang::ento::mpi::Request
Definition: MPITypes.h:27
clang::ento::NonLoc
Definition: SVals.h:298
clang::ento::CheckerContext::generateNonFatalErrorNode
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Definition: CheckerContext.h:211
BuiltinCheckerRegistration.h
clang::ento::MemRegionManager
Definition: MemRegion.h:1244
llvm::IntrusiveRefCntPtr< const ProgramState >
clang::ento::CheckerContext::getStoreManager
StoreManager & getStoreManager()
Definition: CheckerContext.h:63
clang::ento::CheckerManager::registerChecker
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
Definition: CheckerManager.h:166
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:18
clang::ento::SVal::getAsRegion
const MemRegion * getAsRegion() const
Definition: SVals.cpp:151
llvm::SmallVector
Definition: LLVM.h:35
clang::ento::SymbolReaper
A class responsible for cleaning up unused symbols.
Definition: SymbolManager.h:548
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::ento::CheckerContext::getASTContext
ASTContext & getASTContext()
Definition: CheckerContext.h:83
clang::ento::MemRegionManager::getElementRegion
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
clang::ento::CallEvent
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:138
clang::ento::MemRegion::getMemRegionManager
virtual MemRegionManager * getMemRegionManager() const =0
clang::ento::SubRegion
SubRegion - A region that subsets another larger region.
Definition: MemRegion.h:436
clang::ento::CheckerContext::getState
const ProgramStateRef & getState() const
Definition: CheckerContext.h:71
clang::ento::CallEvent::getNumArgs
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
clang::ento::CheckerContext::getSValBuilder
SValBuilder & getSValBuilder()
Definition: CheckerContext.h:110
clang::ento::ElementRegion
ElementRegion is used to represent both array elements and casts.
Definition: MemRegion.h:1083
clang::ento::mpi::MPIChecker::checkUnmatchedWaits
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
clang::ento::CallEvent::getArgSVal
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
Definition: CallEvent.cpp:416
clang::ento::CheckerProgramPointTag
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
Definition: Checker.h:510
clang::ento::mpi::MPIChecker::checkMissingWaits
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