brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.4 KiB · 2932cc1 Raw
194 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file defines the main class of MPI-Checker which serves as an entry11/// point. It is created once for each translation unit analysed.12/// The checker defines path-sensitive checks, to verify correct usage of the13/// MPI API.14///15//===----------------------------------------------------------------------===//16 17#include "MPIChecker.h"18#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"20 21namespace clang {22namespace ento {23namespace mpi {24 25void 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 detected44  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 error51  else {52    State = State->set<RequestMap>(MR, Request::State::Nonblocking);53    Ctx.addTransition(State);54  }55}56 57void 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  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);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 100void 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  ExplodedNode *ErrorNode{nullptr};108 109  auto ReqMap = State->get<RequestMap>();110  for (const auto &Req : ReqMap) {111    if (!SymReaper.isLiveRegion(Req.first)) {112      if (Req.second.CurrentState == Request::State::Nonblocking) {113 114        if (!ErrorNode) {115          ErrorNode = Ctx.generateNonFatalErrorNode(State);116          State = ErrorNode->getState();117        }118        BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,119                                    Ctx.getBugReporter());120      }121      State = State->remove<RequestMap>(Req.first);122    }123  }124 125  // Transition to update the state regarding removed requests.126  if (!ErrorNode) {127    Ctx.addTransition(State);128  } else {129    Ctx.addTransition(State, ErrorNode);130  }131}132 133const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const {134 135  if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {136    return CE.getArgSVal(0).getAsRegion();137  } else if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {138    return CE.getArgSVal(1).getAsRegion();139  } else {140    return (const MemRegion *)nullptr;141  }142}143 144void MPIChecker::allRegionsUsedByWait(145    llvm::SmallVector<const MemRegion *, 2> &ReqRegions,146    const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {147 148  MemRegionManager &RegionManager = MR->getMemRegionManager();149 150  if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {151    const SubRegion *SuperRegion{nullptr};152    if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {153      SuperRegion = cast<SubRegion>(ER->getSuperRegion());154    }155 156    // A single request is passed to MPI_Waitall.157    if (!SuperRegion) {158      ReqRegions.push_back(MR);159      return;160    }161 162    DefinedOrUnknownSVal ElementCount = getDynamicElementCount(163        Ctx.getState(), SuperRegion, Ctx.getSValBuilder(),164        CE.getArgExpr(1)->getType()->getPointeeType());165    const llvm::APSInt &ArrSize =166        ElementCount.castAs<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: mpi183} // end of namespace: ento184} // end of namespace: clang185 186// Registers the checker for static analysis.187void clang::ento::registerMPIChecker(CheckerManager &MGR) {188  MGR.registerChecker<clang::ento::mpi::MPIChecker>();189}190 191bool clang::ento::shouldRegisterMPIChecker(const CheckerManager &mgr) {192  return true;193}194