]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
Merge ACPICA 20180105.
[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 source value is greater than the max
18 //   value of target
19 //
20 // Many compilers and tools have similar checks that are based on semantic
21 // analysis. Those checks are sound but have poor precision. ConversionChecker
22 // is an alternative to those checks.
23 //
24 //===----------------------------------------------------------------------===//
25 #include "ClangSACheckers.h"
26 #include "clang/AST/ParentMap.h"
27 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
28 #include "clang/StaticAnalyzer/Core/Checker.h"
29 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
31
32 using namespace clang;
33 using namespace ento;
34
35 namespace {
36 class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
37 public:
38   void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;
39
40 private:
41   mutable std::unique_ptr<BuiltinBug> BT;
42
43   // Is there loss of precision
44   bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
45                          CheckerContext &C) const;
46
47   // Is there loss of sign
48   bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
49
50   void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
51 };
52 }
53
54 void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
55                                      CheckerContext &C) const {
56   // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
57   // calculations also.
58   if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
59     return;
60
61   // Don't warn for loss of sign/precision in macros.
62   if (Cast->getExprLoc().isMacroID())
63     return;
64
65   // Get Parent.
66   const ParentMap &PM = C.getLocationContext()->getParentMap();
67   const Stmt *Parent = PM.getParent(Cast);
68   if (!Parent)
69     return;
70
71   bool LossOfSign = false;
72   bool LossOfPrecision = false;
73
74   // Loss of sign/precision in binary operation.
75   if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
76     BinaryOperator::Opcode Opc = B->getOpcode();
77     if (Opc == BO_Assign) {
78       LossOfSign = isLossOfSign(Cast, C);
79       LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
80     } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
81       // No loss of sign.
82       LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
83     } else if (Opc == BO_MulAssign) {
84       LossOfSign = isLossOfSign(Cast, C);
85       LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
86     } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
87       LossOfSign = isLossOfSign(Cast, C);
88       // No loss of precision.
89     } else if (Opc == BO_AndAssign) {
90       LossOfSign = isLossOfSign(Cast, C);
91       // No loss of precision.
92     } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
93       LossOfSign = isLossOfSign(Cast, C);
94       LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
95     } else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
96       LossOfSign = isLossOfSign(Cast, C);
97     }
98   } else if (isa<DeclStmt>(Parent)) {
99     LossOfSign = isLossOfSign(Cast, C);
100     LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
101   }
102
103   if (LossOfSign || LossOfPrecision) {
104     // Generate an error node.
105     ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
106     if (!N)
107       return;
108     if (LossOfSign)
109       reportBug(N, C, "Loss of sign in implicit conversion");
110     if (LossOfPrecision)
111       reportBug(N, C, "Loss of precision in implicit conversion");
112   }
113 }
114
115 void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
116                                   const char Msg[]) const {
117   if (!BT)
118     BT.reset(
119         new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
120
121   // Generate a report for this bug.
122   auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
123   C.emitReport(std::move(R));
124 }
125
126 // Is E value greater or equal than Val?
127 static bool isGreaterEqual(CheckerContext &C, const Expr *E,
128                            unsigned long long Val) {
129   ProgramStateRef State = C.getState();
130   SVal EVal = C.getSVal(E);
131   if (EVal.isUnknownOrUndef())
132     return false;
133   if (!EVal.getAs<NonLoc>() && EVal.getAs<Loc>()) {
134     ProgramStateManager &Mgr = C.getStateManager();
135     EVal =
136         Mgr.getStoreManager().getBinding(State->getStore(), EVal.castAs<Loc>());
137   }
138   if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
139     return false;
140
141   SValBuilder &Bldr = C.getSValBuilder();
142   DefinedSVal V = Bldr.makeIntVal(Val, C.getASTContext().LongLongTy);
143
144   // Is DefinedEVal greater or equal with V?
145   SVal GE = Bldr.evalBinOp(State, BO_GE, EVal, V, Bldr.getConditionType());
146   if (GE.isUnknownOrUndef())
147     return false;
148   ConstraintManager &CM = C.getConstraintManager();
149   ProgramStateRef StGE, StLT;
150   std::tie(StGE, StLT) = CM.assumeDual(State, GE.castAs<DefinedSVal>());
151   return StGE && !StLT;
152 }
153
154 // Is E value negative?
155 static bool isNegative(CheckerContext &C, const Expr *E) {
156   ProgramStateRef State = C.getState();
157   SVal EVal = State->getSVal(E, C.getLocationContext());
158   if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
159     return false;
160   DefinedSVal DefinedEVal = EVal.castAs<DefinedSVal>();
161
162   SValBuilder &Bldr = C.getSValBuilder();
163   DefinedSVal V = Bldr.makeIntVal(0, false);
164
165   SVal LT =
166       Bldr.evalBinOp(State, BO_LT, DefinedEVal, V, Bldr.getConditionType());
167
168   // Is E value greater than MaxVal?
169   ConstraintManager &CM = C.getConstraintManager();
170   ProgramStateRef StNegative, StPositive;
171   std::tie(StNegative, StPositive) =
172       CM.assumeDual(State, LT.castAs<DefinedSVal>());
173
174   return StNegative && !StPositive;
175 }
176
177 bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
178                                           QualType DestType,
179                                           CheckerContext &C) const {
180   // Don't warn about explicit loss of precision.
181   if (Cast->isEvaluatable(C.getASTContext()))
182     return false;
183
184   QualType SubType = Cast->IgnoreParenImpCasts()->getType();
185
186   if (!DestType->isIntegerType() || !SubType->isIntegerType())
187     return false;
188
189   if (C.getASTContext().getIntWidth(DestType) >=
190       C.getASTContext().getIntWidth(SubType))
191     return false;
192
193   unsigned W = C.getASTContext().getIntWidth(DestType);
194   if (W == 1 || W >= 64U)
195     return false;
196
197   unsigned long long MaxVal = 1ULL << W;
198   return isGreaterEqual(C, Cast->getSubExpr(), MaxVal);
199 }
200
201 bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
202                                    CheckerContext &C) const {
203   QualType CastType = Cast->getType();
204   QualType SubType = Cast->IgnoreParenImpCasts()->getType();
205
206   if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
207     return false;
208
209   return isNegative(C, Cast->getSubExpr());
210 }
211
212 void ento::registerConversionChecker(CheckerManager &mgr) {
213   mgr.registerChecker<ConversionChecker>();
214 }