clang 8.0.0

ConversionChecker.cpp
Go to the documentation of this file.
1 //=== ConversionChecker.cpp -------------------------------------*- 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 // Check that there is no loss of sign/precision in assignments, comparisons
11 // and multiplications.
12 //
13 // ConversionChecker uses path sensitive analysis to determine possible values
14 // of expressions. A warning is reported when:
15 // * a negative value is implicitly converted to an unsigned value in an
16 // assignment, comparison or multiplication.
17 // * assignment / initialization when the source value is greater than the max
18 // value of the target integer type
19 // * assignment / initialization when the source integer is above the range
20 // where the target floating point type can represent all integers
21 //
22 // Many compilers and tools have similar checks that are based on semantic
23 // analysis. Those checks are sound but have poor precision. ConversionChecker
24 // is an alternative to those checks.
25 //
26 //===----------------------------------------------------------------------===//
27 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
28 #include "clang/AST/ParentMap.h"
29 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
30 #include "clang/StaticAnalyzer/Core/Checker.h"
31 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
32 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
33 #include "llvm/ADT/APFloat.h"
34
35 #include <climits>
36
37 using namespace clang;
38 using namespace ento;
39
40 namespace {
41 class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
42 public:
43 void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;
44
45 private:
46 mutable std::unique_ptr<BuiltinBug> BT;
47
48 bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
49 CheckerContext &C) const;
50
51 bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
52
53 void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
54 };
55 }
56
57 void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
58 CheckerContext &C) const {
59 // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
60 // calculations also.
61 if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
62 return;
63
64 // Don't warn for loss of sign/precision in macros.
65 if (Cast->getExprLoc().isMacroID())
66 return;
67
68 // Get Parent.
69 const ParentMap &PM = C.getLocationContext()->getParentMap();
70 const Stmt *Parent = PM.getParent(Cast);
71 if (!Parent)
72 return;
73
74 bool LossOfSign = false;
75 bool LossOfPrecision = false;
76
77 // Loss of sign/precision in binary operation.
78 if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
79 BinaryOperator::Opcode Opc = B->getOpcode();
80 if (Opc == BO_Assign) {
81 LossOfSign = isLossOfSign(Cast, C);
82 LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
83 } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
84 // No loss of sign.
85 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
86 } else if (Opc == BO_MulAssign) {
87 LossOfSign = isLossOfSign(Cast, C);
88 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
89 } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
90 LossOfSign = isLossOfSign(Cast, C);
91 // No loss of precision.
92 } else if (Opc == BO_AndAssign) {
93 LossOfSign = isLossOfSign(Cast, C);
94 // No loss of precision.
95 } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
96 LossOfSign = isLossOfSign(Cast, C);
97 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
98 } else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
99 LossOfSign = isLossOfSign(Cast, C);
100 }
101 } else if (isa<DeclStmt>(Parent)) {
102 LossOfSign = isLossOfSign(Cast, C);
103 LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
104 }
105
106 if (LossOfSign || LossOfPrecision) {
107 // Generate an error node.
108 ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
109 if (!N)
110 return;
111 if (LossOfSign)
112 reportBug(N, C, "Loss of sign in implicit conversion");
113 if (LossOfPrecision)
114 reportBug(N, C, "Loss of precision in implicit conversion");
115 }
116 }
117
118 void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
119 const char Msg[]) const {
120 if (!BT)
121 BT.reset(
122 new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
123
124 // Generate a report for this bug.
125 auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
126 C.emitReport(std::move(R));
127 }
128
129 bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
130 QualType DestType,
131 CheckerContext &C) const {
132 // Don't warn about explicit loss of precision.
133 if (Cast->isEvaluatable(C.getASTContext()))
134 return false;
135
136 QualType SubType = Cast->IgnoreParenImpCasts()->getType();
137
138 if (!DestType->isRealType() || !SubType->isIntegerType())
139 return false;
140
141 const bool isFloat = DestType->isFloatingType();
142
143 const auto &AC = C.getASTContext();
144
145 // We will find the largest RepresentsUntilExp value such that the DestType
146 // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
147 unsigned RepresentsUntilExp;
148
149 if (isFloat) {
150 const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
151 RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
152 } else {
153 RepresentsUntilExp = AC.getIntWidth(DestType);
154 if (RepresentsUntilExp == 1) {
155 // This is just casting a number to bool, probably not a bug.
156 return false;
157 }
158 if (DestType->isSignedIntegerType())
159 RepresentsUntilExp--;
160 }
161
162 if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
163 // Avoid overflow in our later calculations.
164 return false;
165 }
166
167 unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
168 if (SubType->isSignedIntegerType())
169 CorrectedSrcWidth--;
170
171 if (RepresentsUntilExp >= CorrectedSrcWidth) {
172 // Simple case: the destination can store all values of the source type.
173 return false;
174 }
175
176 unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
177 if (isFloat) {
178 // If this is a floating point type, it can also represent MaxVal exactly.
179 MaxVal++;
180 }
181 return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
182 // TODO: maybe also check negative values with too large magnitude.
183 }
184
185 bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
186 CheckerContext &C) const {
187 QualType CastType = Cast->getType();
188 QualType SubType = Cast->IgnoreParenImpCasts()->getType();
189
190 if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
191 return false;
192
193 return C.isNegative(Cast->getSubExpr());
194 }
195
196 void ento::registerConversionChecker(CheckerManager &mgr) {
197 mgr.registerChecker<ConversionChecker>();
198 }
ento
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:638
clang::ParentMap
Definition: ParentMap.h:21
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:66
clang::ParentMap::getParent
Stmt * getParent(Stmt *) const
Definition: ParentMap.cpp:123
BugType.h
clang::Type::isUnsignedIntegerType
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:1884
Checker.h
CheckerManager.h
clang::CastExpr::getSubExpr
Expr * getSubExpr()
Definition: Expr.h:3050
clang::BinaryOperatorKind
BinaryOperatorKind
Definition: OperationKinds.h:26
CHAR_BIT
#define CHAR_BIT
Definition: limits.h:79
Parent
NodeId Parent
Definition: ASTDiff.cpp:192
clang::Sema
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:278
ParentMap.h
clang::Type::isSignedIntegerType
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:1844
clang::Expr::getType
QualType getType() const
Definition: Expr.h:128
BuiltinCheckerRegistration.h
clang::ImplicitCastExpr
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:3115
clang::Expr::getExprLoc
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:215
clang::Type::isRealType
bool isRealType() const
Definition: Type.cpp:1943
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:22
clang::Expr::IgnoreParenImpCasts
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
Definition: Expr.cpp:2693
clang::SourceLocation::isMacroID
bool isMacroID() const
Definition: SourceLocation.h:101
clang::Type::isIntegerType
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:6578
clang::Expr::isEvaluatable
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...
Definition: ExprConstant.cpp:11040
clang::Type::isFloatingType
bool isFloatingType() const
Definition: Type.cpp:1921
CheckerContext.h
CastType
CastType
Definition: SemaCast.cpp:46