summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
new file mode 100644
index 00000000000..19bc716e878
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
@@ -0,0 +1,190 @@
+//===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the main class of MPI-Checker which serves as an entry
+/// point. It is created once for each translation unit analysed.
+/// The checker defines path-sensitive checks, to verify correct usage of the
+/// MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPIChecker.h"
+#include "../ClangSACheckers.h"
+
+namespace clang {
+namespace ento {
+namespace mpi {
+
+void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
+ CheckerContext &Ctx) const {
+ if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
+ return;
+ }
+ const MemRegion *const MR =
+ PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
+ if (!MR)
+ return;
+ const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
+
+ // The region must be typed, in order to reason about it.
+ if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
+ return;
+
+ ProgramStateRef State = Ctx.getState();
+ const Request *const Req = State->get<RequestMap>(MR);
+
+ // double nonblocking detected
+ if (Req && Req->CurrentState == Request::State::Nonblocking) {
+ ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
+ BReporter->reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode);
+ Ctx.addTransition(ErrorNode->getState(), ErrorNode);
+ }
+ // no error
+ else {
+ State = State->set<RequestMap>(MR, Request::State::Nonblocking);
+ Ctx.addTransition(State);
+ }
+}
+
+void MPIChecker::checkUnmatchedWaits(const CallEvent &PreCallEvent,
+ CheckerContext &Ctx) const {
+ if (!FuncClassifier->isWaitType(PreCallEvent.getCalleeIdentifier()))
+ return;
+ const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
+ if (!MR)
+ return;
+ const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
+
+ // The region must be typed, in order to reason about it.
+ if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
+ return;
+
+ llvm::SmallVector<const MemRegion *, 2> ReqRegions;
+ allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
+ if (ReqRegions.empty())
+ return;
+
+ ProgramStateRef State = Ctx.getState();
+ static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait");
+ ExplodedNode *ErrorNode{nullptr};
+
+ // Check all request regions used by the wait function.
+ for (const auto &ReqRegion : ReqRegions) {
+ const Request *const Req = State->get<RequestMap>(ReqRegion);
+ State = State->set<RequestMap>(ReqRegion, Request::State::Wait);
+ if (!Req) {
+ if (!ErrorNode) {
+ ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
+ State = ErrorNode->getState();
+ }
+ // A wait has no matching nonblocking call.
+ BReporter->reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode);
+ }
+ }
+
+ if (!ErrorNode) {
+ Ctx.addTransition(State);
+ } else {
+ Ctx.addTransition(State, ErrorNode);
+ }
+}
+
+void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
+ CheckerContext &Ctx) const {
+ if (!SymReaper.hasDeadSymbols())
+ return;
+
+ ProgramStateRef State = Ctx.getState();
+ const auto &Requests = State->get<RequestMap>();
+ if (Requests.isEmpty())
+ return;
+
+ static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait");
+ ExplodedNode *ErrorNode{nullptr};
+
+ auto ReqMap = State->get<RequestMap>();
+ for (const auto &Req : ReqMap) {
+ if (!SymReaper.isLiveRegion(Req.first)) {
+ if (Req.second.CurrentState == Request::State::Nonblocking) {
+
+ if (!ErrorNode) {
+ ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
+ State = ErrorNode->getState();
+ }
+ BReporter->reportMissingWait(Req.second, Req.first, ErrorNode);
+ }
+ State = State->remove<RequestMap>(Req.first);
+ }
+ }
+
+ // Transition to update the state regarding removed requests.
+ if (!ErrorNode) {
+ Ctx.addTransition(State);
+ } else {
+ Ctx.addTransition(State, ErrorNode);
+ }
+}
+
+const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const {
+
+ if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
+ return CE.getArgSVal(0).getAsRegion();
+ } else if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
+ return CE.getArgSVal(1).getAsRegion();
+ } else {
+ return (const MemRegion *)nullptr;
+ }
+}
+
+void MPIChecker::allRegionsUsedByWait(
+ llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
+ const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {
+
+ MemRegionManager *const RegionManager = MR->getMemRegionManager();
+
+ if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
+ const MemRegion *SuperRegion{nullptr};
+ if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
+ SuperRegion = ER->getSuperRegion();
+ }
+
+ // A single request is passed to MPI_Waitall.
+ if (!SuperRegion) {
+ ReqRegions.push_back(MR);
+ return;
+ }
+
+ const auto &Size = Ctx.getStoreManager().getSizeInElements(
+ Ctx.getState(), SuperRegion,
+ CE.getArgExpr(1)->getType()->getPointeeType());
+ const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();
+
+ for (size_t i = 0; i < ArrSize; ++i) {
+ const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
+
+ const ElementRegion *const ER = RegionManager->getElementRegion(
+ CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
+ Ctx.getASTContext());
+
+ ReqRegions.push_back(ER->getAs<MemRegion>());
+ }
+ } else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
+ ReqRegions.push_back(MR);
+ }
+}
+
+} // end of namespace: mpi
+} // end of namespace: ento
+} // end of namespace: clang
+
+// Registers the checker for static analysis.
+void clang::ento::registerMPIChecker(CheckerManager &MGR) {
+ MGR.registerChecker<clang::ento::mpi::MPIChecker>();
+}
OpenPOWER on IntegriCloud