Coverage Report

Created: 2019-07-24 05:18

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