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 const BugType BT
{this, "Assignment of a non-Boolean value"};
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
)) {
39 StringRef Msg
= IsTainted
? "Might assign a tainted non-Boolean value"
40 : "Assignment of a non-Boolean value";
41 C
.emitReport(std::make_unique
<PathSensitiveBugReport
>(BT
, Msg
, N
));
45 static bool isBooleanType(QualType Ty
) {
46 if (Ty
->isBooleanType()) // C++ or C99
49 if (const TypedefType
*TT
= Ty
->getAs
<TypedefType
>())
50 return TT
->getDecl()->getName() == "BOOL" || // Objective-C
51 TT
->getDecl()->getName() == "_Bool" || // stdbool.h < C99
52 TT
->getDecl()->getName() == "Boolean"; // MacTypes.h
57 void BoolAssignmentChecker::checkBind(SVal Loc
, SVal Val
, const Stmt
*S
,
58 CheckerContext
&C
) const {
60 // We are only interested in stores into Booleans.
61 const TypedValueRegion
*TR
=
62 dyn_cast_or_null
<TypedValueRegion
>(Loc
.getAsRegion());
67 QualType RegTy
= TR
->getValueType();
69 if (!isBooleanType(RegTy
))
72 // Get the value of the right-hand side. We only care about values
73 // that are defined (UnknownVals and UndefinedVals are handled by other
75 std::optional
<NonLoc
> NV
= Val
.getAs
<NonLoc
>();
79 // Check if the assigned value meets our criteria for correctness. It must
80 // be a value that is either 0 or 1. One way to check this is to see if
81 // the value is possibly < 0 (for a negative value) or greater than 1.
82 ProgramStateRef State
= C
.getState();
83 BasicValueFactory
&BVF
= C
.getSValBuilder().getBasicValueFactory();
84 ConstraintManager
&CM
= C
.getConstraintManager();
86 llvm::APSInt Zero
= BVF
.getValue(0, RegTy
);
87 llvm::APSInt One
= BVF
.getValue(1, RegTy
);
89 ProgramStateRef StIn
, StOut
;
90 std::tie(StIn
, StOut
) = CM
.assumeInclusiveRangeDual(State
, *NV
, Zero
, One
);
94 if (StIn
&& StOut
&& taint::isTainted(State
, *NV
))
95 emitReport(StOut
, C
, /*IsTainted=*/true);
98 void ento::registerBoolAssignmentChecker(CheckerManager
&Mgr
) {
99 Mgr
.registerChecker
<BoolAssignmentChecker
>();
102 bool ento::shouldRegisterBoolAssignmentChecker(const CheckerManager
&Mgr
) {