clang  10.0.0git
ConversionChecker.cpp
Go to the documentation of this file.
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 //===----------------------------------------------------------------------===//
27 #include "clang/AST/ParentMap.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  CheckerContext &C) const {
58  // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
59  // calculations also.
60  if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
61  return;
62 
63  // Don't warn for loss of sign/precision in macros.
64  if (Cast->getExprLoc().isMacroID())
65  return;
66 
67  // Get Parent.
68  const ParentMap &PM = C.getLocationContext()->getParentMap();
69  const Stmt *Parent = PM.getParent(Cast);
70  if (!Parent)
71  return;
72 
73  bool LossOfSign = false;
74  bool LossOfPrecision = false;
75 
76  // Loss of sign/precision in binary operation.
77  if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
78  BinaryOperator::Opcode Opc = B->getOpcode();
79  if (Opc == BO_Assign) {
80  LossOfSign = isLossOfSign(Cast, C);
81  LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
82  } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
83  // No loss of sign.
84  LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
85  } else if (Opc == BO_MulAssign) {
86  LossOfSign = isLossOfSign(Cast, C);
87  LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
88  } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
89  LossOfSign = isLossOfSign(Cast, C);
90  // No loss of precision.
91  } else if (Opc == BO_AndAssign) {
92  LossOfSign = isLossOfSign(Cast, C);
93  // No loss of precision.
94  } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
95  LossOfSign = isLossOfSign(Cast, C);
96  LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
97  } else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
98  LossOfSign = isLossOfSign(Cast, C);
99  }
100  } else if (isa<DeclStmt>(Parent)) {
101  LossOfSign = isLossOfSign(Cast, C);
102  LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
103  }
104 
105  if (LossOfSign || LossOfPrecision) {
106  // Generate an error node.
107  ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
108  if (!N)
109  return;
110  if (LossOfSign)
111  reportBug(N, C, "Loss of sign in implicit conversion");
112  if (LossOfPrecision)
113  reportBug(N, C, "Loss of precision in implicit conversion");
114  }
115 }
116 
117 void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
118  const char Msg[]) const {
119  if (!BT)
120  BT.reset(
121  new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
122 
123  // Generate a report for this bug.
124  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
125  C.emitReport(std::move(R));
126 }
127 
128 bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
129  QualType DestType,
130  CheckerContext &C) const {
131  // Don't warn about explicit loss of precision.
132  if (Cast->isEvaluatable(C.getASTContext()))
133  return false;
134 
135  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
136 
137  if (!DestType->isRealType() || !SubType->isIntegerType())
138  return false;
139 
140  const bool isFloat = DestType->isFloatingType();
141 
142  const auto &AC = C.getASTContext();
143 
144  // We will find the largest RepresentsUntilExp value such that the DestType
145  // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
146  unsigned RepresentsUntilExp;
147 
148  if (isFloat) {
149  const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
150  RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
151  } else {
152  RepresentsUntilExp = AC.getIntWidth(DestType);
153  if (RepresentsUntilExp == 1) {
154  // This is just casting a number to bool, probably not a bug.
155  return false;
156  }
157  if (DestType->isSignedIntegerType())
158  RepresentsUntilExp--;
159  }
160 
161  if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
162  // Avoid overflow in our later calculations.
163  return false;
164  }
165 
166  unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
167  if (SubType->isSignedIntegerType())
168  CorrectedSrcWidth--;
169 
170  if (RepresentsUntilExp >= CorrectedSrcWidth) {
171  // Simple case: the destination can store all values of the source type.
172  return false;
173  }
174 
175  unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
176  if (isFloat) {
177  // If this is a floating point type, it can also represent MaxVal exactly.
178  MaxVal++;
179  }
180  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
181  // TODO: maybe also check negative values with too large magnitude.
182 }
183 
184 bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
185  CheckerContext &C) const {
186  QualType CastType = Cast->getType();
187  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
188 
189  if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
190  return false;
191 
192  return C.isNegative(Cast->getSubExpr());
193 }
194 
195 void ento::registerConversionChecker(CheckerManager &mgr) {
196  mgr.registerChecker<ConversionChecker>();
197 }
198 
199 bool ento::shouldRegisterConversionChecker(const LangOptions &LO) {
200  return true;
201 }
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:800
A (possibly-)qualified type.
Definition: Type.h:654
Stmt - This represents one statement.
Definition: Stmt.h:66
Stmt * getParent(Stmt *) const
Definition: ParentMap.cpp:134
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition: Type.cpp:1968
Expr * getSubExpr()
Definition: Expr.h:3202
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:53
BinaryOperatorKind
#define CHAR_BIT
Definition: limits.h:63
NodeId Parent
Definition: ASTDiff.cpp:191
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:336
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], or an enum decl which has a signed representation.
Definition: Type.cpp:1928
QualType getType() const
Definition: Expr.h:137
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:3274
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:224
bool isRealType() const
Definition: Type.cpp:2027
Dataflow Directional Tag Classes.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:2995
bool isMacroID() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:6811
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
bool isFloatingType() const
Definition: Type.cpp:2005
CastType
Definition: SemaCast.cpp:45