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