blob: f26f73129e7816f30ffd66eba0ba7a08ee8de548 [file] [log] [blame]
Ryan Govostes55011c02012-02-11 16:32:09 +00001//== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- 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// This defines BoolAssignmentChecker, a builtin check in ExprEngine that
11// performs checks for assignment of non-Boolean values to Boolean variables.
12//
13//===----------------------------------------------------------------------===//
14
15#include "ClangSACheckers.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000016#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Ryan Govostes55011c02012-02-11 16:32:09 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
18#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ryan Govostes55011c02012-02-11 16:32:09 +000020
21using namespace clang;
22using namespace ento;
23
24namespace {
25 class BoolAssignmentChecker : public Checker< check::Bind > {
Ahmed Charlesb8984322014-03-07 20:03:18 +000026 mutable std::unique_ptr<BuiltinBug> BT;
Ryan Govostes55011c02012-02-11 16:32:09 +000027 void emitReport(ProgramStateRef state, CheckerContext &C) const;
28 public:
29 void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
30 };
31} // end anonymous namespace
32
33void BoolAssignmentChecker::emitReport(ProgramStateRef state,
34 CheckerContext &C) const {
Devin Coughline39bd402015-09-16 22:03:05 +000035 if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
Ryan Govostes55011c02012-02-11 16:32:09 +000036 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000037 BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
Aaron Ballman8d3a7a52015-06-23 13:15:32 +000038 C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N));
Ryan Govostes55011c02012-02-11 16:32:09 +000039 }
40}
41
42static bool isBooleanType(QualType Ty) {
43 if (Ty->isBooleanType()) // C++ or C99
44 return true;
Ted Kremenek3a0678e2015-09-08 03:50:52 +000045
Ryan Govostes55011c02012-02-11 16:32:09 +000046 if (const TypedefType *TT = Ty->getAs<TypedefType>())
47 return TT->getDecl()->getName() == "BOOL" || // Objective-C
48 TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99
49 TT->getDecl()->getName() == "Boolean"; // MacTypes.h
Ted Kremenek3a0678e2015-09-08 03:50:52 +000050
Ryan Govostes55011c02012-02-11 16:32:09 +000051 return false;
52}
53
54void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
55 CheckerContext &C) const {
Ted Kremenek3a0678e2015-09-08 03:50:52 +000056
Ryan Govostes55011c02012-02-11 16:32:09 +000057 // We are only interested in stores into Booleans.
58 const TypedValueRegion *TR =
59 dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
Ted Kremenek3a0678e2015-09-08 03:50:52 +000060
Ryan Govostes55011c02012-02-11 16:32:09 +000061 if (!TR)
62 return;
Ted Kremenek3a0678e2015-09-08 03:50:52 +000063
Ryan Govostes55011c02012-02-11 16:32:09 +000064 QualType valTy = TR->getValueType();
Ted Kremenek3a0678e2015-09-08 03:50:52 +000065
Ryan Govostes55011c02012-02-11 16:32:09 +000066 if (!isBooleanType(valTy))
67 return;
Ted Kremenek3a0678e2015-09-08 03:50:52 +000068
Ryan Govostes55011c02012-02-11 16:32:09 +000069 // Get the value of the right-hand side. We only care about values
70 // that are defined (UnknownVals and UndefinedVals are handled by other
71 // checkers).
David Blaikie05785d12013-02-20 22:23:23 +000072 Optional<DefinedSVal> DV = val.getAs<DefinedSVal>();
Ryan Govostes55011c02012-02-11 16:32:09 +000073 if (!DV)
74 return;
Ted Kremenek3a0678e2015-09-08 03:50:52 +000075
Ryan Govostes55011c02012-02-11 16:32:09 +000076 // Check if the assigned value meets our criteria for correctness. It must
77 // be a value that is either 0 or 1. One way to check this is to see if
78 // the value is possibly < 0 (for a negative value) or greater than 1.
Ted Kremenek3a0678e2015-09-08 03:50:52 +000079 ProgramStateRef state = C.getState();
Ryan Govostes55011c02012-02-11 16:32:09 +000080 SValBuilder &svalBuilder = C.getSValBuilder();
81 ConstraintManager &CM = C.getConstraintManager();
Ted Kremenek3a0678e2015-09-08 03:50:52 +000082
83 // First, ensure that the value is >= 0.
Ryan Govostes55011c02012-02-11 16:32:09 +000084 DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
85 SVal greaterThanOrEqualToZeroVal =
86 svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
87 svalBuilder.getConditionType());
David Blaikie2fdacbc2013-02-20 05:52:05 +000088
David Blaikie05785d12013-02-20 22:23:23 +000089 Optional<DefinedSVal> greaterThanEqualToZero =
David Blaikie2fdacbc2013-02-20 05:52:05 +000090 greaterThanOrEqualToZeroVal.getAs<DefinedSVal>();
91
Ryan Govostes55011c02012-02-11 16:32:09 +000092 if (!greaterThanEqualToZero) {
93 // The SValBuilder cannot construct a valid SVal for this condition.
Ted Kremenek3a0678e2015-09-08 03:50:52 +000094 // This means we cannot properly reason about it.
Ryan Govostes55011c02012-02-11 16:32:09 +000095 return;
96 }
Ted Kremenek3a0678e2015-09-08 03:50:52 +000097
Ryan Govostes55011c02012-02-11 16:32:09 +000098 ProgramStateRef stateLT, stateGE;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +000099 std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000100
Ryan Govostes55011c02012-02-11 16:32:09 +0000101 // Is it possible for the value to be less than zero?
102 if (stateLT) {
103 // It is possible for the value to be less than zero. We only
104 // want to emit a warning, however, if that value is fully constrained.
105 // If it it possible for the value to be >= 0, then essentially the
106 // value is underconstrained and there is nothing left to be done.
107 if (!stateGE)
108 emitReport(stateLT, C);
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000109
Ryan Govostes55011c02012-02-11 16:32:09 +0000110 // In either case, we are done.
111 return;
112 }
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000113
Ryan Govostes55011c02012-02-11 16:32:09 +0000114 // If we reach here, it must be the case that the value is constrained
115 // to only be >= 0.
116 assert(stateGE == state);
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000117
Ryan Govostes55011c02012-02-11 16:32:09 +0000118 // At this point we know that the value is >= 0.
119 // Now check to ensure that the value is <= 1.
120 DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy);
121 SVal lessThanEqToOneVal =
122 svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal,
123 svalBuilder.getConditionType());
David Blaikie2fdacbc2013-02-20 05:52:05 +0000124
David Blaikie05785d12013-02-20 22:23:23 +0000125 Optional<DefinedSVal> lessThanEqToOne =
David Blaikie2fdacbc2013-02-20 05:52:05 +0000126 lessThanEqToOneVal.getAs<DefinedSVal>();
127
Ryan Govostes55011c02012-02-11 16:32:09 +0000128 if (!lessThanEqToOne) {
129 // The SValBuilder cannot construct a valid SVal for this condition.
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000130 // This means we cannot properly reason about it.
Ryan Govostes55011c02012-02-11 16:32:09 +0000131 return;
132 }
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000133
Ryan Govostes55011c02012-02-11 16:32:09 +0000134 ProgramStateRef stateGT, stateLE;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000135 std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000136
Ryan Govostes55011c02012-02-11 16:32:09 +0000137 // Is it possible for the value to be greater than one?
138 if (stateGT) {
139 // It is possible for the value to be greater than one. We only
140 // want to emit a warning, however, if that value is fully constrained.
141 // If it is possible for the value to be <= 1, then essentially the
142 // value is underconstrained and there is nothing left to be done.
143 if (!stateLE)
144 emitReport(stateGT, C);
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000145
Ryan Govostes55011c02012-02-11 16:32:09 +0000146 // In either case, we are done.
147 return;
148 }
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000149
Ryan Govostes55011c02012-02-11 16:32:09 +0000150 // If we reach here, it must be the case that the value is constrained
151 // to only be <= 1.
152 assert(stateLE == state);
153}
154
155void ento::registerBoolAssignmentChecker(CheckerManager &mgr) {
156 mgr.registerChecker<BoolAssignmentChecker>();
157}