Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==//
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
// This defines TestAfterDivZeroChecker, a builtin check that performs checks
10
//  for division by zero where the division occurs before comparison with zero.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16
#include "clang/StaticAnalyzer/Core/Checker.h"
17
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19
#include "llvm/ADT/FoldingSet.h"
20
21
using namespace clang;
22
using namespace ento;
23
24
namespace {
25
26
class ZeroState {
27
private:
28
  SymbolRef ZeroSymbol;
29
  unsigned BlockID;
30
  const StackFrameContext *SFC;
31
32
public:
33
  ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC)
34
446
      : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
35
36
48
  const StackFrameContext *getStackFrameContext() const { return SFC; }
37
38
119
  bool operator==(const ZeroState &X) const {
39
119
    return BlockID == X.BlockID && 
SFC == X.SFC96
&&
ZeroSymbol == X.ZeroSymbol92
;
40
119
  }
41
42
42
  bool operator<(const ZeroState &X) const {
43
42
    if (BlockID != X.BlockID)
44
23
      return BlockID < X.BlockID;
45
19
    if (SFC != X.SFC)
46
4
      return SFC < X.SFC;
47
15
    return ZeroSymbol < X.ZeroSymbol;
48
15
  }
49
50
74
  void Profile(llvm::FoldingSetNodeID &ID) const {
51
74
    ID.AddInteger(BlockID);
52
74
    ID.AddPointer(SFC);
53
74
    ID.AddPointer(ZeroSymbol);
54
74
  }
55
};
56
57
class DivisionBRVisitor : public BugReporterVisitor {
58
private:
59
  SymbolRef ZeroSymbol;
60
  const StackFrameContext *SFC;
61
  bool Satisfied;
62
63
public:
64
  DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC)
65
30
      : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(false) {}
66
67
30
  void Profile(llvm::FoldingSetNodeID &ID) const override {
68
30
    ID.Add(ZeroSymbol);
69
30
    ID.Add(SFC);
70
30
  }
71
72
  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
73
                                                 BugReporterContext &BRC,
74
                                                 BugReport &BR) override;
75
};
76
77
class TestAfterDivZeroChecker
78
    : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
79
                     check::EndFunction> {
80
  mutable std::unique_ptr<BuiltinBug> DivZeroBug;
81
  void reportBug(SVal Val, CheckerContext &C) const;
82
83
public:
84
  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
85
  void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
86
  void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
87
  void setDivZeroMap(SVal Var, CheckerContext &C) const;
88
  bool hasDivZeroMap(SVal Var, const CheckerContext &C) const;
89
  bool isZero(SVal S, CheckerContext &C) const;
90
};
91
} // end anonymous namespace
92
93
REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
94
95
std::shared_ptr<PathDiagnosticPiece>
96
DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, 
97
907
                             BugReporterContext &BRC, BugReport &BR) {
98
907
  if (Satisfied)
99
422
    return nullptr;
100
485
101
485
  const Expr *E = nullptr;
102
485
103
485
  if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
104
419
    if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
105
144
      BinaryOperator::Opcode Op = BO->getOpcode();
106
144
      if (Op == BO_Div || 
Op == BO_Rem112
||
Op == BO_DivAssign112
||
107
144
          
Op == BO_RemAssign112
) {
108
32
        E = BO->getRHS();
109
32
      }
110
144
    }
111
485
112
485
  if (!E)
113
453
    return nullptr;
114
32
115
32
  SVal S = Succ->getSVal(E);
116
32
  if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) {
117
30
    Satisfied = true;
118
30
119
30
    // Construct a new PathDiagnosticPiece.
120
30
    ProgramPoint P = Succ->getLocation();
121
30
    PathDiagnosticLocation L =
122
30
        PathDiagnosticLocation::create(P, BRC.getSourceManager());
123
30
124
30
    if (!L.isValid() || !L.asLocation().isValid())
125
0
      return nullptr;
126
30
127
30
    return std::make_shared<PathDiagnosticEventPiece>(
128
30
        L, "Division with compared value made here");
129
30
  }
130
2
131
2
  return nullptr;
132
2
}
133
134
99
bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
135
99
  Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
136
99
137
99
  if (!DSV)
138
2
    return false;
139
97
140
97
  ConstraintManager &CM = C.getConstraintManager();
141
97
  return !CM.assume(C.getState(), *DSV, true);
142
97
}
143
144
93
void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const {
145
93
  SymbolRef SR = Var.getAsSymbol();
146
93
  if (!SR)
147
25
    return;
148
68
149
68
  ProgramStateRef State = C.getState();
150
68
  State =
151
68
      State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame()));
152
68
  C.addTransition(State);
153
68
}
154
155
bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
156
985
                                            const CheckerContext &C) const {
157
985
  SymbolRef SR = Var.getAsSymbol();
158
985
  if (!SR)
159
607
    return false;
160
378
161
378
  ZeroState ZS(SR, C.getBlockID(), C.getStackFrame());
162
378
  return C.getState()->contains<DivZeroMap>(ZS);
163
378
}
164
165
30
void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
166
30
  if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
167
30
    if (!DivZeroBug)
168
2
      DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
169
30
170
30
    auto R = llvm::make_unique<BugReport>(
171
30
        *DivZeroBug, "Value being compared against zero has already been used "
172
30
                     "for division",
173
30
        N);
174
30
175
30
    R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),
176
30
                                                       C.getStackFrame()));
177
30
    C.emitReport(std::move(R));
178
30
  }
179
30
}
180
181
void TestAfterDivZeroChecker::checkEndFunction(const ReturnStmt *,
182
1.61k
                                               CheckerContext &C) const {
183
1.61k
  ProgramStateRef State = C.getState();
184
1.61k
185
1.61k
  DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
186
1.61k
  if (DivZeroes.isEmpty())
187
1.57k
    return;
188
46
189
46
  DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>();
190
46
  for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
191
46
                                               E = DivZeroes.end();
192
94
       I != E; 
++I48
) {
193
48
    ZeroState ZS = *I;
194
48
    if (ZS.getStackFrameContext() == C.getStackFrame())
195
44
      DivZeroes = F.remove(DivZeroes, ZS);
196
48
  }
197
46
  C.addTransition(State->set<DivZeroMap>(DivZeroes));
198
46
}
199
200
void TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B,
201
2.15k
                                           CheckerContext &C) const {
202
2.15k
  BinaryOperator::Opcode Op = B->getOpcode();
203
2.15k
  if (Op == BO_Div || 
Op == BO_Rem2.08k
||
Op == BO_DivAssign2.06k
||
204
2.15k
      
Op == BO_RemAssign2.05k
) {
205
99
    SVal S = C.getSVal(B->getRHS());
206
99
207
99
    if (!isZero(S, C))
208
93
      setDivZeroMap(S, C);
209
99
  }
210
2.15k
}
211
212
void TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition,
213
1.45k
                                                   CheckerContext &C) const {
214
1.45k
  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) {
215
874
    if (B->isComparisonOp()) {
216
852
      const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS());
217
852
      bool LRHS = true;
218
852
      if (!IntLiteral) {
219
544
        IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS());
220
544
        LRHS = false;
221
544
      }
222
852
223
852
      if (!IntLiteral || 
IntLiteral->getValue() != 0320
)
224
742
        return;
225
110
226
110
      SVal Val = C.getSVal(LRHS ? 
B->getLHS()98
:
B->getRHS()12
);
227
110
      if (hasDivZeroMap(Val, C))
228
20
        reportBug(Val, C);
229
110
    }
230
874
  } else 
if (const UnaryOperator *583
U583
= dyn_cast<UnaryOperator>(Condition)) {
231
220
    if (U->getOpcode() == UO_LNot) {
232
220
      SVal Val;
233
220
      if (const ImplicitCastExpr *I =
234
131
              dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
235
131
        Val = C.getSVal(I->getSubExpr());
236
220
237
220
      if (hasDivZeroMap(Val, C))
238
4
        reportBug(Val, C);
239
216
      else {
240
216
        Val = C.getSVal(U->getSubExpr());
241
216
        if (hasDivZeroMap(Val, C))
242
4
          reportBug(Val, C);
243
216
      }
244
220
    }
245
363
  } else if (const ImplicitCastExpr *IE =
246
220
                 dyn_cast<ImplicitCastExpr>(Condition)) {
247
220
    SVal Val = C.getSVal(IE->getSubExpr());
248
220
249
220
    if (hasDivZeroMap(Val, C))
250
1
      reportBug(Val, C);
251
219
    else {
252
219
      SVal Val = C.getSVal(Condition);
253
219
254
219
      if (hasDivZeroMap(Val, C))
255
1
        reportBug(Val, C);
256
219
    }
257
220
  }
258
1.45k
}
259
260
71
void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) {
261
71
  mgr.registerChecker<TestAfterDivZeroChecker>();
262
71
}
263
264
71
bool ento::shouldRegisterTestAfterDivZeroChecker(const LangOptions &LO) {
265
71
  return true;
266
71
}