1 //== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- C++ -*--==//
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
7 //===----------------------------------------------------------------------===//
9 // This defines BoolAssignmentChecker, a builtin check in ExprEngine that
10 // performs checks for assignment of non-Boolean values to Boolean variables.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/StaticAnalyzer/Checkers/Taint.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 using namespace clang
;
26 class BoolAssignmentChecker
: public Checker
< check::Bind
> {
27 mutable std::unique_ptr
<BugType
> BT
;
28 void emitReport(ProgramStateRef state
, CheckerContext
&C
,
29 bool IsTainted
= false) const;
32 void checkBind(SVal loc
, SVal val
, const Stmt
*S
, CheckerContext
&C
) const;
34 } // end anonymous namespace
36 void BoolAssignmentChecker::emitReport(ProgramStateRef state
, CheckerContext
&C
,
37 bool IsTainted
) const {
38 if (ExplodedNode
*N
= C
.generateNonFatalErrorNode(state
)) {
40 BT
.reset(new BugType(this, "Assignment of a non-Boolean value"));
42 StringRef Msg
= IsTainted
? "Might assign a tainted non-Boolean value"
43 : "Assignment of a non-Boolean value";
44 C
.emitReport(std::make_unique
<PathSensitiveBugReport
>(*BT
, Msg
, N
));
48 static bool isBooleanType(QualType Ty
) {
49 if (Ty
->isBooleanType()) // C++ or C99
52 if (const TypedefType
*TT
= Ty
->getAs
<TypedefType
>())
53 return TT
->getDecl()->getName() == "BOOL" || // Objective-C
54 TT
->getDecl()->getName() == "_Bool" || // stdbool.h < C99
55 TT
->getDecl()->getName() == "Boolean"; // MacTypes.h
60 void BoolAssignmentChecker::checkBind(SVal loc
, SVal val
, const Stmt
*S
,
61 CheckerContext
&C
) const {
63 // We are only interested in stores into Booleans.
64 const TypedValueRegion
*TR
=
65 dyn_cast_or_null
<TypedValueRegion
>(loc
.getAsRegion());
70 QualType valTy
= TR
->getValueType();
72 if (!isBooleanType(valTy
))
75 // Get the value of the right-hand side. We only care about values
76 // that are defined (UnknownVals and UndefinedVals are handled by other
78 std::optional
<NonLoc
> NV
= val
.getAs
<NonLoc
>();
82 // Check if the assigned value meets our criteria for correctness. It must
83 // be a value that is either 0 or 1. One way to check this is to see if
84 // the value is possibly < 0 (for a negative value) or greater than 1.
85 ProgramStateRef state
= C
.getState();
86 SValBuilder
&svalBuilder
= C
.getSValBuilder();
87 BasicValueFactory
&BVF
= svalBuilder
.getBasicValueFactory();
88 ConstraintManager
&CM
= C
.getConstraintManager();
90 llvm::APSInt Zero
= BVF
.getValue(0, valTy
);
91 llvm::APSInt One
= BVF
.getValue(1, valTy
);
93 ProgramStateRef StIn
, StOut
;
94 std::tie(StIn
, StOut
) = CM
.assumeInclusiveRangeDual(state
, *NV
, Zero
, One
);
98 if (StIn
&& StOut
&& taint::isTainted(state
, *NV
))
99 emitReport(StOut
, C
, /*IsTainted=*/true);
102 void ento::registerBoolAssignmentChecker(CheckerManager
&mgr
) {
103 mgr
.registerChecker
<BoolAssignmentChecker
>();
106 bool ento::shouldRegisterBoolAssignmentChecker(const CheckerManager
&mgr
) {