Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
Line
Count
Source (jump to first uncovered line)
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
10.5k
                                     CheckerContext &C) const {
56
10.5k
  // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
57
10.5k
  // calculations also.
58
10.5k
  if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
59
2.75k
    return;
60
7.78k
61
7.78k
  // Don't warn for loss of sign/precision in macros.
62
7.78k
  
if (7.78k
Cast->getExprLoc().isMacroID()7.78k
)
63
70
    return;
64
7.71k
65
7.71k
  // Get Parent.
66
7.71k
  const ParentMap &PM = C.getLocationContext()->getParentMap();
67
7.71k
  const Stmt *Parent = PM.getParent(Cast);
68
7.71k
  if (!Parent)
69
4
    return;
70
7.70k
71
7.70k
  bool LossOfSign = false;
72
7.70k
  bool LossOfPrecision = false;
73
7.70k
74
7.70k
  // Loss of sign/precision in binary operation.
75
7.70k
  if (const auto *
B7.70k
= dyn_cast<BinaryOperator>(Parent)) {
76
2.87k
    BinaryOperator::Opcode Opc = B->getOpcode();
77
2.87k
    if (
Opc == BO_Assign2.87k
) {
78
588
      LossOfSign = isLossOfSign(Cast, C);
79
588
      LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
80
2.87k
    } else 
if (2.28k
Opc == BO_AddAssign || 2.28k
Opc == BO_SubAssign2.28k
) {
81
6
      // No loss of sign.
82
6
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
83
2.28k
    } else 
if (2.28k
Opc == BO_MulAssign2.28k
) {
84
23
      LossOfSign = isLossOfSign(Cast, C);
85
23
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
86
2.28k
    } else 
if (2.25k
Opc == BO_DivAssign || 2.25k
Opc == BO_RemAssign2.25k
) {
87
6
      LossOfSign = isLossOfSign(Cast, C);
88
6
      // No loss of precision.
89
2.25k
    } else 
if (2.25k
Opc == BO_AndAssign2.25k
) {
90
5
      LossOfSign = isLossOfSign(Cast, C);
91
5
      // No loss of precision.
92
2.25k
    } else 
if (2.24k
Opc == BO_OrAssign || 2.24k
Opc == BO_XorAssign2.24k
) {
93
4
      LossOfSign = isLossOfSign(Cast, C);
94
4
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
95
2.24k
    } else 
if (2.24k
B->isRelationalOp() || 2.24k
B->isMultiplicativeOp()1.47k
) {
96
909
      LossOfSign = isLossOfSign(Cast, C);
97
909
    }
98
7.70k
  } else 
if (4.83k
isa<DeclStmt>(Parent)4.83k
) {
99
46
    LossOfSign = isLossOfSign(Cast, C);
100
46
    LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
101
46
  }
102
7.70k
103
7.70k
  if (
LossOfSign || 7.70k
LossOfPrecision7.69k
) {
104
48
    // Generate an error node.
105
48
    ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
106
48
    if (!N)
107
0
      return;
108
48
    
if (48
LossOfSign48
)
109
12
      reportBug(N, C, "Loss of sign in implicit conversion");
110
48
    if (LossOfPrecision)
111
36
      reportBug(N, C, "Loss of precision in implicit conversion");
112
48
  }
113
10.5k
}
114
115
void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
116
48
                                  const char Msg[]) const {
117
48
  if (!BT)
118
1
    BT.reset(
119
1
        new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
120
48
121
48
  // Generate a report for this bug.
122
48
  auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
123
48
  C.emitReport(std::move(R));
124
48
}
125
126
// Is E value greater or equal than Val?
127
static bool isGreaterEqual(CheckerContext &C, const Expr *E,
128
331
                           unsigned long long Val) {
129
331
  ProgramStateRef State = C.getState();
130
331
  SVal EVal = C.getSVal(E);
131
331
  if (EVal.isUnknownOrUndef())
132
0
    return false;
133
331
  
if (331
!EVal.getAs<NonLoc>() && 331
EVal.getAs<Loc>()5
) {
134
5
    ProgramStateManager &Mgr = C.getStateManager();
135
5
    EVal =
136
5
        Mgr.getStoreManager().getBinding(State->getStore(), EVal.castAs<Loc>());
137
5
  }
138
331
  if (
EVal.isUnknownOrUndef() || 331
!EVal.getAs<NonLoc>()331
)
139
0
    return false;
140
331
141
331
  SValBuilder &Bldr = C.getSValBuilder();
142
331
  DefinedSVal V = Bldr.makeIntVal(Val, C.getASTContext().LongLongTy);
143
331
144
331
  // Is DefinedEVal greater or equal with V?
145
331
  SVal GE = Bldr.evalBinOp(State, BO_GE, EVal, V, Bldr.getConditionType());
146
331
  if (GE.isUnknownOrUndef())
147
0
    return false;
148
331
  ConstraintManager &CM = C.getConstraintManager();
149
331
  ProgramStateRef StGE, StLT;
150
331
  std::tie(StGE, StLT) = CM.assumeDual(State, GE.castAs<DefinedSVal>());
151
327
  return StGE && !StLT;
152
331
}
153
154
// Is E value negative?
155
19
static bool isNegative(CheckerContext &C, const Expr *E) {
156
19
  ProgramStateRef State = C.getState();
157
19
  SVal EVal = State->getSVal(E, C.getLocationContext());
158
19
  if (
EVal.isUnknownOrUndef() || 19
!EVal.getAs<NonLoc>()19
)
159
0
    return false;
160
19
  DefinedSVal DefinedEVal = EVal.castAs<DefinedSVal>();
161
19
162
19
  SValBuilder &Bldr = C.getSValBuilder();
163
19
  DefinedSVal V = Bldr.makeIntVal(0, false);
164
19
165
19
  SVal LT =
166
19
      Bldr.evalBinOp(State, BO_LT, DefinedEVal, V, Bldr.getConditionType());
167
19
168
19
  // Is E value greater than MaxVal?
169
19
  ConstraintManager &CM = C.getConstraintManager();
170
19
  ProgramStateRef StNegative, StPositive;
171
19
  std::tie(StNegative, StPositive) =
172
19
      CM.assumeDual(State, LT.castAs<DefinedSVal>());
173
19
174
13
  return StNegative && !StPositive;
175
19
}
176
177
bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
178
                                          QualType DestType,
179
667
                                          CheckerContext &C) const {
180
667
  // Don't warn about explicit loss of precision.
181
667
  if (Cast->isEvaluatable(C.getASTContext()))
182
64
    return false;
183
603
184
603
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
185
603
186
603
  if (
!DestType->isIntegerType() || 603
!SubType->isIntegerType()512
)
187
93
    return false;
188
510
189
510
  
if (510
C.getASTContext().getIntWidth(DestType) >=
190
510
      C.getASTContext().getIntWidth(SubType))
191
179
    return false;
192
331
193
331
  unsigned W = C.getASTContext().getIntWidth(DestType);
194
331
  if (
W == 1 || 331
W >= 64U331
)
195
0
    return false;
196
331
197
331
  unsigned long long MaxVal = 1ULL << W;
198
331
  return isGreaterEqual(C, Cast->getSubExpr(), MaxVal);
199
331
}
200
201
bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
202
1.58k
                                   CheckerContext &C) const {
203
1.58k
  QualType CastType = Cast->getType();
204
1.58k
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();
205
1.58k
206
1.58k
  if (
!CastType->isUnsignedIntegerType() || 1.58k
!SubType->isSignedIntegerType()254
)
207
1.56k
    return false;
208
19
209
19
  return isNegative(C, Cast->getSubExpr());
210
19
}
211
212
65
void ento::registerConversionChecker(CheckerManager &mgr) {
213
65
  mgr.registerChecker<ConversionChecker>();
214
65
}