123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- //===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// \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 "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.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.getBugReporter());
- 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,
- Ctx.getBugReporter());
- }
- }
- if (!ErrorNode) {
- Ctx.addTransition(State);
- } else {
- Ctx.addTransition(State, ErrorNode);
- }
- }
- void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
- CheckerContext &Ctx) const {
- 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,
- Ctx.getBugReporter());
- }
- 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 &RegionManager = MR->getMemRegionManager();
- if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
- const SubRegion *SuperRegion{nullptr};
- if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
- SuperRegion = cast<SubRegion>(ER->getSuperRegion());
- }
- // A single request is passed to MPI_Waitall.
- if (!SuperRegion) {
- ReqRegions.push_back(MR);
- return;
- }
- DefinedOrUnknownSVal ElementCount = getDynamicElementCount(
- Ctx.getState(), SuperRegion, Ctx.getSValBuilder(),
- CE.getArgExpr(1)->getType()->getPointeeType());
- const llvm::APSInt &ArrSize =
- ElementCount.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>();
- }
- bool clang::ento::shouldRegisterMPIChecker(const CheckerManager &mgr) {
- return true;
- }
|