]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / ConversionChecker.cpp
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 }