Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- 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
// This defines BoolAssignmentChecker, a builtin check in ExprEngine that
10
// performs checks for assignment of non-Boolean values to Boolean variables.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16
#include "clang/StaticAnalyzer/Core/Checker.h"
17
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19
20
using namespace clang;
21
using namespace ento;
22
23
namespace {
24
  class BoolAssignmentChecker : public Checker< check::Bind > {
25
    mutable std::unique_ptr<BuiltinBug> BT;
26
    void emitReport(ProgramStateRef state, CheckerContext &C) const;
27
  public:
28
    void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
29
  };
30
} // end anonymous namespace
31
32
void BoolAssignmentChecker::emitReport(ProgramStateRef state,
33
22
                                       CheckerContext &C) const {
34
22
  if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
35
22
    if (!BT)
36
2
      BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
37
22
    C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N));
38
22
  }
39
22
}
40
41
1.84k
static bool isBooleanType(QualType Ty) {
42
1.84k
  if (Ty->isBooleanType()) // C++ or C99
43
17
    return true;
44
1.82k
45
1.82k
  if (const TypedefType *TT = Ty->getAs<TypedefType>())
46
116
    return TT->getDecl()->getName() == "BOOL"   || // Objective-C
47
116
           
TT->getDecl()->getName() == "_Bool"85
|| // stdbool.h < C99
48
116
           
TT->getDecl()->getName() == "Boolean"85
; // MacTypes.h
49
1.71k
50
1.71k
  return false;
51
1.71k
}
52
53
void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
54
1.95k
                                      CheckerContext &C) const {
55
1.95k
56
1.95k
  // We are only interested in stores into Booleans.
57
1.95k
  const TypedValueRegion *TR =
58
1.95k
    dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
59
1.95k
60
1.95k
  if (!TR)
61
111
    return;
62
1.84k
63
1.84k
  QualType valTy = TR->getValueType();
64
1.84k
65
1.84k
  if (!isBooleanType(valTy))
66
1.78k
    return;
67
64
68
64
  // Get the value of the right-hand side.  We only care about values
69
64
  // that are defined (UnknownVals and UndefinedVals are handled by other
70
64
  // checkers).
71
64
  Optional<DefinedSVal> DV = val.getAs<DefinedSVal>();
72
64
  if (!DV)
73
0
    return;
74
64
75
64
  // Check if the assigned value meets our criteria for correctness.  It must
76
64
  // be a value that is either 0 or 1.  One way to check this is to see if
77
64
  // the value is possibly < 0 (for a negative value) or greater than 1.
78
64
  ProgramStateRef state = C.getState();
79
64
  SValBuilder &svalBuilder = C.getSValBuilder();
80
64
  ConstraintManager &CM = C.getConstraintManager();
81
64
82
64
  // First, ensure that the value is >= 0.
83
64
  DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
84
64
  SVal greaterThanOrEqualToZeroVal =
85
64
    svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
86
64
                          svalBuilder.getConditionType());
87
64
88
64
  Optional<DefinedSVal> greaterThanEqualToZero =
89
64
      greaterThanOrEqualToZeroVal.getAs<DefinedSVal>();
90
64
91
64
  if (!greaterThanEqualToZero) {
92
0
    // The SValBuilder cannot construct a valid SVal for this condition.
93
0
    // This means we cannot properly reason about it.
94
0
    return;
95
0
  }
96
64
97
64
  ProgramStateRef stateLT, stateGE;
98
64
  std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
99
64
100
64
  // Is it possible for the value to be less than zero?
101
64
  if (stateLT) {
102
16
    // It is possible for the value to be less than zero.  We only
103
16
    // want to emit a warning, however, if that value is fully constrained.
104
16
    // If it it possible for the value to be >= 0, then essentially the
105
16
    // value is underconstrained and there is nothing left to be done.
106
16
    if (!stateGE)
107
8
      emitReport(stateLT, C);
108
16
109
16
    // In either case, we are done.
110
16
    return;
111
16
  }
112
48
113
48
  // If we reach here, it must be the case that the value is constrained
114
48
  // to only be >= 0.
115
48
  assert(stateGE == state);
116
48
117
48
  // At this point we know that the value is >= 0.
118
48
  // Now check to ensure that the value is <= 1.
119
48
  DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy);
120
48
  SVal lessThanEqToOneVal =
121
48
    svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal,
122
48
                          svalBuilder.getConditionType());
123
48
124
48
  Optional<DefinedSVal> lessThanEqToOne =
125
48
      lessThanEqToOneVal.getAs<DefinedSVal>();
126
48
127
48
  if (!lessThanEqToOne) {
128
0
    // The SValBuilder cannot construct a valid SVal for this condition.
129
0
    // This means we cannot properly reason about it.
130
0
    return;
131
0
  }
132
48
133
48
  ProgramStateRef stateGT, stateLE;
134
48
  std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
135
48
136
48
  // Is it possible for the value to be greater than one?
137
48
  if (stateGT) {
138
14
    // It is possible for the value to be greater than one.  We only
139
14
    // want to emit a warning, however, if that value is fully constrained.
140
14
    // If it is possible for the value to be <= 1, then essentially the
141
14
    // value is underconstrained and there is nothing left to be done.
142
14
    if (!stateLE)
143
14
      emitReport(stateGT, C);
144
14
145
14
    // In either case, we are done.
146
14
    return;
147
14
  }
148
34
149
34
  // If we reach here, it must be the case that the value is constrained
150
34
  // to only be <= 1.
151
34
  assert(stateLE == state);
152
34
}
153
154
71
void ento::registerBoolAssignmentChecker(CheckerManager &mgr) {
155
71
    mgr.registerChecker<BoolAssignmentChecker>();
156
71
}
157
158
71
bool ento::shouldRegisterBoolAssignmentChecker(const LangOptions &LO) {
159
71
  return true;
160
71
}