Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== ConversionChecker.cpp -------------------------------------*- 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
// Check that there is no loss of sign/precision in assignments, comparisons
10
// and multiplications.
11
//
12
// ConversionChecker uses path sensitive analysis to determine possible values
13
// of expressions. A warning is reported when:
14
// * a negative value is implicitly converted to an unsigned value in an
15
//   assignment, comparison or multiplication.
16
// * assignment / initialization when the source value is greater than the max
17
//   value of the target integer type
18
// * assignment / initialization when the source integer is above the range
19
//   where the target floating point type can represent all integers
20
//
21
// Many compilers and tools have similar checks that are based on semantic
22
// analysis. Those checks are sound but have poor precision. ConversionChecker
23
// is an alternative to those checks.
24
//
25
//===----------------------------------------------------------------------===//
26
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
27
#include "clang/AST/ParentMap.h"
28
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
29
#include "clang/StaticAnalyzer/Core/Checker.h"
30
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
31
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
32
#include "llvm/ADT/APFloat.h"
33
34
#include <climits>
35
36
using namespace clang;
37
using namespace ento;
38
39
namespace {
40
class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
41
public:
42
  void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;
43
44
private:
45
  mutable std::unique_ptr<BuiltinBug> BT;
46
47
  bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
48
                         CheckerContext &C) const;
49
50
  bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
51
52
  void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
53
};
54
}
55
56
void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
57
9.92k
                                     CheckerContext &C) const {
58
9.92k
  // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
59
9.92k
  // calculations also.
60
9.92k
  if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
61
2.80k
    return;
62
7.11k
63
7.11k
  // Don't warn for loss of sign/precision in macros.
64
7.11k
  if (Cast->getExprLoc().isMacroID())
65
36
    return;
66
7.07k
67
7.07k
  // Get Parent.
68
7.07k
  const ParentMap &PM = C.getLocationContext()->getParentMap();
69
7.07k
  const Stmt *Parent = PM.getParent(Cast);
70
7.07k
  if (!Parent)
71
4
    return;
72
7.07k
73
7.07k
  bool LossOfSign = false;
74
7.07k
  bool LossOfPrecision = false;
75
7.07k
76
7.07k
  // Loss of sign/precision in binary operation.
77
7.07k
  if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
78
2.30k
    BinaryOperator::Opcode Opc = B->getOpcode();
79
2.30k
    if (Opc == BO_Assign) {
80
457
      LossOfSign = isLossOfSign(Cast, C);
81
457
      LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
82
1.85k
    } else if (Opc == BO_AddAssign || 
Opc == BO_SubAssign1.84k
) {
83
11
      // No loss of sign.
84
11
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
85
1.84k
    } else if (Opc == BO_MulAssign) {
86
23
      LossOfSign = isLossOfSign(Cast, C);
87
23
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
88
1.81k
    } else if (Opc == BO_DivAssign || 
Opc == BO_RemAssign1.81k
) {
89
6
      LossOfSign = isLossOfSign(Cast, C);
90
6
      // No loss of precision.
91
1.81k
    } else if (Opc == BO_AndAssign) {
92
5
      LossOfSign = isLossOfSign(Cast, C);
93
5
      // No loss of precision.
94
1.80k
    } else if (Opc == BO_OrAssign || 
Opc == BO_XorAssign1.80k
) {
95
4
      LossOfSign = isLossOfSign(Cast, C);
96
4
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
97
1.80k
    } else if (B->isRelationalOp() || 
B->isMultiplicativeOp()1.20k
) {
98
750
      LossOfSign = isLossOfSign(Cast, C);
99
750
    }
100
4.76k
  } else if (isa<DeclStmt>(Parent)) {
101
55
    LossOfSign = isLossOfSign(Cast, C);
102
55
    LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
103
55
  }
104
7.07k
105
7.07k
  if (LossOfSign || 
LossOfPrecision7.06k
) {
106
20
    // Generate an error node.
107
20
    ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
108
20
    if (!N)
109
0
      return;
110
20
    if (LossOfSign)
111
10
      reportBug(N, C, "Loss of sign in implicit conversion");
112
20
    if (LossOfPrecision)
113
10
      reportBug(N, C, "Loss of precision in implicit conversion");
114
20
  }
115
7.07k
}
116
117
void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
118
20
                                  const char Msg[]) const {
119
20
  if (!BT)
120
1
    BT.reset(
121
1
        new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
122
20
123
20
  // Generate a report for this bug.
124
20
  auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
125
20
  C.emitReport(std::move(R));
126
20
}
127
128
bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
129
                                          QualType DestType,
130
550
                                          CheckerContext &C) const {
131
550
  // Don't warn about explicit loss of precision.
132
550
  if (Cast->isEvaluatable(C.getASTContext()))
133
68
    return false;
134
482
135
482
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
136
482
137
482
  if (!DestType->isRealType() || 
!SubType->isIntegerType()397
)
138
95
    return false;
139
387
140
387
  const bool isFloat = DestType->isFloatingType();
141
387
142
387
  const auto &AC = C.getASTContext();
143
387
144
387
  // We will find the largest RepresentsUntilExp value such that the DestType
145
387
  // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
146
387
  unsigned RepresentsUntilExp;
147
387
148
387
  if (isFloat) {
149
7
    const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
150
7
    RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
151
380
  } else {
152
380
    RepresentsUntilExp = AC.getIntWidth(DestType);
153
380
    if (RepresentsUntilExp == 1) {
154
0
      // This is just casting a number to bool, probably not a bug.
155
0
      return false;
156
0
    }
157
380
    if (DestType->isSignedIntegerType())
158
365
      RepresentsUntilExp--;
159
380
  }
160
387
161
387
  if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
162
6
    // Avoid overflow in our later calculations.
163
6
    return false;
164
6
  }
165
381
166
381
  unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
167
381
  if (SubType->isSignedIntegerType())
168
369
    CorrectedSrcWidth--;
169
381
170
381
  if (RepresentsUntilExp >= CorrectedSrcWidth) {
171
140
    // Simple case: the destination can store all values of the source type.
172
140
    return false;
173
140
  }
174
241
175
241
  unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
176
241
  if (isFloat) {
177
5
    // If this is a floating point type, it can also represent MaxVal exactly.
178
5
    MaxVal++;
179
5
  }
180
241
  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
181
241
  // TODO: maybe also check negative values with too large magnitude.
182
241
}
183
184
bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
185
1.30k
                                     CheckerContext &C) const {
186
1.30k
  QualType CastType = Cast->getType();
187
1.30k
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
188
1.30k
189
1.30k
  if (!CastType->isUnsignedIntegerType() || 
!SubType->isSignedIntegerType()232
)
190
1.28k
    return false;
191
19
192
19
  return C.isNegative(Cast->getSubExpr());
193
19
}
194
195
70
void ento::registerConversionChecker(CheckerManager &mgr) {
196
70
  mgr.registerChecker<ConversionChecker>();
197
70
}
198
199
70
bool ento::shouldRegisterConversionChecker(const LangOptions &LO) {
200
70
  return true;
201
70
}