Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/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
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file defines the main class of MPI-Checker which serves as an entry
12
/// point. It is created once for each translation unit analysed.
13
/// The checker defines path-sensitive checks, to verify correct usage of the
14
/// MPI API.
15
///
16
//===----------------------------------------------------------------------===//
17
18
#include "MPIChecker.h"
19
#include "../ClangSACheckers.h"
20
21
namespace clang {
22
namespace ento {
23
namespace mpi {
24
25
void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
26
131
                                        CheckerContext &Ctx) const {
27
131
  if (
!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())131
) {
28
83
    return;
29
83
  }
30
48
  const MemRegion *const MR =
31
48
      PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
32
48
  if (!MR)
33
0
    return;
34
48
  const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
35
48
36
48
  // The region must be typed, in order to reason about it.
37
48
  if (
!isa<TypedRegion>(MR) || 48
(ER && 48
!isa<TypedRegion>(ER->getSuperRegion())11
))
38
0
    return;
39
48
40
48
  ProgramStateRef State = Ctx.getState();
41
48
  const Request *const Req = State->get<RequestMap>(MR);
42
48
43
48
  // double nonblocking detected
44
48
  if (
Req && 48
Req->CurrentState == Request::State::Nonblocking11
) {
45
9
    ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
46
9
    BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
47
9
                                      Ctx.getBugReporter());
48
9
    Ctx.addTransition(ErrorNode->getState(), ErrorNode);
49
9
  }
50
48
  // no error
51
39
  else {
52
39
    State = State->set<RequestMap>(MR, Request::State::Nonblocking);
53
39
    Ctx.addTransition(State);
54
39
  }
55
131
}
56
57
void MPIChecker::checkUnmatchedWaits(const CallEvent &PreCallEvent,
58
131
                                     CheckerContext &Ctx) const {
59
131
  if (!FuncClassifier->isWaitType(PreCallEvent.getCalleeIdentifier()))
60
86
    return;
61
45
  const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
62
45
  if (!MR)
63
0
    return;
64
45
  const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
65
45
66
45
  // The region must be typed, in order to reason about it.
67
45
  if (
!isa<TypedRegion>(MR) || 45
(ER && 45
!isa<TypedRegion>(ER->getSuperRegion())15
))
68
0
    return;
69
45
70
45
  llvm::SmallVector<const MemRegion *, 2> ReqRegions;
71
45
  allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
72
45
  if (ReqRegions.empty())
73
0
    return;
74
45
75
45
  ProgramStateRef State = Ctx.getState();
76
45
  static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait");
77
45
  ExplodedNode *ErrorNode{nullptr};
78
45
79
45
  // Check all request regions used by the wait function.
80
58
  for (const auto &ReqRegion : ReqRegions) {
81
58
    const Request *const Req = State->get<RequestMap>(ReqRegion);
82
58
    State = State->set<RequestMap>(ReqRegion, Request::State::Wait);
83
58
    if (
!Req58
) {
84
21
      if (
!ErrorNode21
) {
85
16
        ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
86
16
        State = ErrorNode->getState();
87
16
      }
88
21
      // A wait has no matching nonblocking call.
89
21
      BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode,
90
21
                                    Ctx.getBugReporter());
91
21
    }
92
58
  }
93
45
94
45
  if (
!ErrorNode45
) {
95
29
    Ctx.addTransition(State);
96
45
  } else {
97
16
    Ctx.addTransition(State, ErrorNode);
98
16
  }
99
131
}
100
101
void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
102
127
                                   CheckerContext &Ctx) const {
103
127
  if (!SymReaper.hasDeadSymbols())
104
0
    return;
105
127
106
127
  ProgramStateRef State = Ctx.getState();
107
127
  const auto &Requests = State->get<RequestMap>();
108
127
  if (Requests.isEmpty())
109
31
    return;
110
96
111
96
  static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait");
112
96
  ExplodedNode *ErrorNode{nullptr};
113
96
114
96
  auto ReqMap = State->get<RequestMap>();
115
146
  for (const auto &Req : ReqMap) {
116
146
    if (
!SymReaper.isLiveRegion(Req.first)146
) {
117
56
      if (
Req.second.CurrentState == Request::State::Nonblocking56
) {
118
4
119
4
        if (
!ErrorNode4
) {
120
4
          ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
121
4
          State = ErrorNode->getState();
122
4
        }
123
4
        BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,
124
4
                                    Ctx.getBugReporter());
125
4
      }
126
56
      State = State->remove<RequestMap>(Req.first);
127
56
    }
128
146
  }
129
96
130
96
  // Transition to update the state regarding removed requests.
131
96
  if (
!ErrorNode96
) {
132
92
    Ctx.addTransition(State);
133
96
  } else {
134
4
    Ctx.addTransition(State, ErrorNode);
135
4
  }
136
127
}
137
138
45
const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const {
139
45
140
45
  if (
FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())45
) {
141
39
    return CE.getArgSVal(0).getAsRegion();
142
6
  } else 
if (6
FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())6
) {
143
6
    return CE.getArgSVal(1).getAsRegion();
144
0
  } else {
145
0
    return (const MemRegion *)nullptr;
146
0
  }
147
0
}
148
149
void MPIChecker::allRegionsUsedByWait(
150
    llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
151
45
    const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {
152
45
153
45
  MemRegionManager *const RegionManager = MR->getMemRegionManager();
154
45
155
45
  if (
FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())45
) {
156
6
    const SubRegion *SuperRegion{nullptr};
157
6
    if (const ElementRegion *const 
ER6
= MR->getAs<ElementRegion>()) {
158
5
      SuperRegion = cast<SubRegion>(ER->getSuperRegion());
159
5
    }
160
6
161
6
    // A single request is passed to MPI_Waitall.
162
6
    if (
!SuperRegion6
) {
163
1
      ReqRegions.push_back(MR);
164
1
      return;
165
1
    }
166
5
167
5
    const auto &Size = Ctx.getStoreManager().getSizeInElements(
168
5
        Ctx.getState(), SuperRegion,
169
5
        CE.getArgExpr(1)->getType()->getPointeeType());
170
5
    const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();
171
5
172
23
    for (size_t i = 0; 
i < ArrSize23
;
++i18
) {
173
18
      const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
174
18
175
18
      const ElementRegion *const ER = RegionManager->getElementRegion(
176
18
          CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
177
18
          Ctx.getASTContext());
178
18
179
18
      ReqRegions.push_back(ER->getAs<MemRegion>());
180
18
    }
181
45
  } else 
if (39
FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())39
) {
182
39
    ReqRegions.push_back(MR);
183
39
  }
184
45
}
185
186
} // end of namespace: mpi
187
} // end of namespace: ento
188
} // end of namespace: clang
189
190
// Registers the checker for static analysis.
191
3
void clang::ento::registerMPIChecker(CheckerManager &MGR) {
192
3
  MGR.registerChecker<clang::ento::mpi::MPIChecker>();
193
3
}