Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
35266 views
//== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- C++ -*--==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This defines BoolAssignmentChecker, a builtin check in ExprEngine that9// performs checks for assignment of non-Boolean values to Boolean variables.10//11//===----------------------------------------------------------------------===//1213#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"14#include "clang/StaticAnalyzer/Checkers/Taint.h"15#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"16#include "clang/StaticAnalyzer/Core/Checker.h"17#include "clang/StaticAnalyzer/Core/CheckerManager.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"19#include <optional>2021using namespace clang;22using namespace ento;2324namespace {25class BoolAssignmentChecker : public Checker<check::Bind> {26const BugType BT{this, "Assignment of a non-Boolean value"};27void emitReport(ProgramStateRef State, CheckerContext &C,28bool IsTainted = false) const;2930public:31void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;32};33} // end anonymous namespace3435void BoolAssignmentChecker::emitReport(ProgramStateRef State, CheckerContext &C,36bool IsTainted) const {37if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {38StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value"39: "Assignment of a non-Boolean value";40C.emitReport(std::make_unique<PathSensitiveBugReport>(BT, Msg, N));41}42}4344static bool isBooleanType(QualType Ty) {45if (Ty->isBooleanType()) // C++ or C9946return true;4748if (const TypedefType *TT = Ty->getAs<TypedefType>())49return TT->getDecl()->getName() == "BOOL" || // Objective-C50TT->getDecl()->getName() == "_Bool" || // stdbool.h < C9951TT->getDecl()->getName() == "Boolean"; // MacTypes.h5253return false;54}5556void BoolAssignmentChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,57CheckerContext &C) const {5859// We are only interested in stores into Booleans.60const TypedValueRegion *TR =61dyn_cast_or_null<TypedValueRegion>(Loc.getAsRegion());6263if (!TR)64return;6566QualType RegTy = TR->getValueType();6768if (!isBooleanType(RegTy))69return;7071// Get the value of the right-hand side. We only care about values72// that are defined (UnknownVals and UndefinedVals are handled by other73// checkers).74std::optional<NonLoc> NV = Val.getAs<NonLoc>();75if (!NV)76return;7778// Check if the assigned value meets our criteria for correctness. It must79// be a value that is either 0 or 1. One way to check this is to see if80// the value is possibly < 0 (for a negative value) or greater than 1.81ProgramStateRef State = C.getState();82BasicValueFactory &BVF = C.getSValBuilder().getBasicValueFactory();83ConstraintManager &CM = C.getConstraintManager();8485llvm::APSInt Zero = BVF.getValue(0, RegTy);86llvm::APSInt One = BVF.getValue(1, RegTy);8788ProgramStateRef StIn, StOut;89std::tie(StIn, StOut) = CM.assumeInclusiveRangeDual(State, *NV, Zero, One);9091if (!StIn)92emitReport(StOut, C);93if (StIn && StOut && taint::isTainted(State, *NV))94emitReport(StOut, C, /*IsTainted=*/true);95}9697void ento::registerBoolAssignmentChecker(CheckerManager &Mgr) {98Mgr.registerChecker<BoolAssignmentChecker>();99}100101bool ento::shouldRegisterBoolAssignmentChecker(const CheckerManager &Mgr) {102return true;103}104105106