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