Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/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, const Expr *E, CheckerContext &C,
53
                 const char Msg[]) const;
54
};
55
}
56
57
void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
58
9.88k
                                     CheckerContext &C) const {
59
  // Don't warn for implicit conversions to bool
60
9.88k
  if (Cast->getType()->isBooleanType())
61
201
    return;
62
63
  // Don't warn for loss of sign/precision in macros.
64
9.68k
  if (Cast->getExprLoc().isMacroID())
65
89
    return;
66
67
  // Get Parent.
68
9.59k
  const ParentMap &PM = C.getLocationContext()->getParentMap();
69
9.59k
  const Stmt *Parent = PM.getParent(Cast);
70
9.59k
  if (!Parent)
71
6
    return;
72
  // Dont warn if this is part of an explicit cast
73
9.58k
  if (isa<ExplicitCastExpr>(Parent))
74
165
    return;
75
76
9.42k
  bool LossOfSign = false;
77
9.42k
  bool LossOfPrecision = false;
78
79
  // Loss of sign/precision in binary operation.
80
9.42k
  if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
81
3.22k
    BinaryOperator::Opcode Opc = B->getOpcode();
82
3.22k
    if (Opc == BO_Assign) {
83
624
      if (!Cast->IgnoreParenImpCasts()->isEvaluatable(C.getASTContext())) {
84
510
        LossOfSign = isLossOfSign(Cast, C);
85
510
        LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
86
510
      }
87
2.60k
    } else if (Opc == BO_AddAssign || 
Opc == BO_SubAssign2.59k
) {
88
      // No loss of sign.
89
11
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
90
2.59k
    } else if (Opc == BO_MulAssign) {
91
25
      LossOfSign = isLossOfSign(Cast, C);
92
25
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
93
2.56k
    } else if (Opc == BO_DivAssign || 
Opc == BO_RemAssign2.55k
) {
94
14
      LossOfSign = isLossOfSign(Cast, C);
95
      // No loss of precision.
96
2.55k
    } else if (Opc == BO_AndAssign) {
97
5
      LossOfSign = isLossOfSign(Cast, C);
98
      // No loss of precision.
99
2.54k
    } else if (Opc == BO_OrAssign || 
Opc == BO_XorAssign2.54k
) {
100
4
      LossOfSign = isLossOfSign(Cast, C);
101
4
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
102
2.54k
    } else if (B->isRelationalOp() || 
B->isMultiplicativeOp()1.89k
) {
103
799
      LossOfSign = isLossOfSign(Cast, C);
104
799
    }
105
6.19k
  } else if (isa<DeclStmt, ReturnStmt>(Parent)) {
106
731
    if (!Cast->IgnoreParenImpCasts()->isEvaluatable(C.getASTContext())) {
107
469
      LossOfSign = isLossOfSign(Cast, C);
108
469
      LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
109
469
    }
110
5.46k
  } else {
111
5.46k
    LossOfSign = isLossOfSign(Cast, C);
112
5.46k
    LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
113
5.46k
  }
114
115
9.42k
  if (LossOfSign || 
LossOfPrecision9.40k
) {
116
    // Generate an error node.
117
26
    ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
118
26
    if (!N)
119
0
      return;
120
26
    if (LossOfSign)
121
15
      reportBug(N, Cast, C, "Loss of sign in implicit conversion");
122
26
    if (LossOfPrecision)
123
11
      reportBug(N, Cast, C, "Loss of precision in implicit conversion");
124
26
  }
125
9.42k
}
126
127
void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E,
128
26
                                  CheckerContext &C, const char Msg[]) const {
129
26
  if (!BT)
130
2
    BT.reset(
131
2
        new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
132
133
  // Generate a report for this bug.
134
26
  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
135
26
  bugreporter::trackExpressionValue(N, E, *R);
136
26
  C.emitReport(std::move(R));
137
26
}
138
139
bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
140
                                          QualType DestType,
141
6.48k
                                          CheckerContext &C) const {
142
  // Don't warn about explicit loss of precision.
143
6.48k
  if (Cast->isEvaluatable(C.getASTContext()))
144
1.93k
    return false;
145
146
4.55k
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
147
148
4.55k
  if (!DestType->isRealType() || 
!SubType->isIntegerType()1.99k
)
149
2.61k
    return false;
150
151
1.94k
  const bool isFloat = DestType->isFloatingType();
152
153
1.94k
  const auto &AC = C.getASTContext();
154
155
  // We will find the largest RepresentsUntilExp value such that the DestType
156
  // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
157
1.94k
  unsigned RepresentsUntilExp;
158
159
1.94k
  if (isFloat) {
160
7
    const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
161
7
    RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
162
1.93k
  } else {
163
1.93k
    RepresentsUntilExp = AC.getIntWidth(DestType);
164
1.93k
    if (RepresentsUntilExp == 1) {
165
      // This is just casting a number to bool, probably not a bug.
166
0
      return false;
167
0
    }
168
1.93k
    if (DestType->isSignedIntegerType())
169
1.57k
      RepresentsUntilExp--;
170
1.93k
  }
171
172
1.94k
  if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
173
    // Avoid overflow in our later calculations.
174
79
    return false;
175
79
  }
176
177
1.86k
  unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
178
1.86k
  if (SubType->isSignedIntegerType())
179
1.42k
    CorrectedSrcWidth--;
180
181
1.86k
  if (RepresentsUntilExp >= CorrectedSrcWidth) {
182
    // Simple case: the destination can store all values of the source type.
183
1.58k
    return false;
184
1.58k
  }
185
186
273
  unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
187
273
  if (isFloat) {
188
    // If this is a floating point type, it can also represent MaxVal exactly.
189
5
    MaxVal++;
190
5
  }
191
273
  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
192
  // TODO: maybe also check negative values with too large magnitude.
193
1.86k
}
194
195
bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
196
7.29k
                                     CheckerContext &C) const {
197
7.29k
  QualType CastType = Cast->getType();
198
7.29k
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
199
200
7.29k
  if (!CastType->isUnsignedIntegerType() || 
!SubType->isSignedIntegerType()697
)
201
7.07k
    return false;
202
203
218
  return C.isNegative(Cast->getSubExpr());
204
7.29k
}
205
206
71
void ento::registerConversionChecker(CheckerManager &mgr) {
207
71
  mgr.registerChecker<ConversionChecker>();
208
71
}
209
210
142
bool ento::shouldRegisterConversionChecker(const CheckerManager &mgr) {
211
142
  return true;
212
142
}