Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- C++ -*--==//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This defines BoolAssignmentChecker, a builtin check in ExprEngine that
10
// performs checks for assignment of non-Boolean values to Boolean variables.
11
//
12
//===----------------------------------------------------------------------===//
13
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"
20
#include <optional>
21
22
using namespace clang;
23
using namespace ento;
24
25
namespace {
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;
30
31
  public:
32
    void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
33
  };
34
} // end anonymous namespace
35
36
void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext &C,
37
24
                                       bool IsTainted) const {
38
24
  if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
39
24
    if (!BT)
40
2
      BT.reset(new BugType(this, "Assignment of a non-Boolean value"));
41
42
24
    StringRef Msg = IsTainted ? 
"Might assign a tainted non-Boolean value"2
43
24
                              : 
"Assignment of a non-Boolean value"22
;
44
24
    C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, Msg, N));
45
24
  }
46
24
}
47
48
1.97k
static bool isBooleanType(QualType Ty) {
49
1.97k
  if (Ty->isBooleanType()) // C++ or C99
50
17
    return true;
51
52
1.96k
  if (const TypedefType *TT = Ty->getAs<TypedefType>())
53
122
    return TT->getDecl()->getName() == "BOOL"   || // Objective-C
54
122
           
TT->getDecl()->getName() == "_Bool"91
|| // stdbool.h < C99
55
122
           
TT->getDecl()->getName() == "Boolean"91
; // MacTypes.h
56
57
1.83k
  return false;
58
1.96k
}
59
60
void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
61
2.08k
                                      CheckerContext &C) const {
62
63
  // We are only interested in stores into Booleans.
64
2.08k
  const TypedValueRegion *TR =
65
2.08k
    dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
66
67
2.08k
  if (!TR)
68
108
    return;
69
70
1.97k
  QualType valTy = TR->getValueType();
71
72
1.97k
  if (!isBooleanType(valTy))
73
1.91k
    return;
74
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
77
  // checkers).
78
66
  std::optional<NonLoc> NV = val.getAs<NonLoc>();
79
66
  if (!NV)
80
0
    return;
81
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
66
  ProgramStateRef state = C.getState();
86
66
  SValBuilder &svalBuilder = C.getSValBuilder();
87
66
  BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
88
66
  ConstraintManager &CM = C.getConstraintManager();
89
90
66
  llvm::APSInt Zero = BVF.getValue(0, valTy);
91
66
  llvm::APSInt One = BVF.getValue(1, valTy);
92
93
66
  ProgramStateRef StIn, StOut;
94
66
  std::tie(StIn, StOut) = CM.assumeInclusiveRangeDual(state, *NV, Zero, One);
95
96
66
  if (!StIn)
97
22
    emitReport(StOut, C);
98
66
  if (StIn && 
StOut44
&&
taint::isTainted(state, *NV)10
)
99
2
    emitReport(StOut, C, /*IsTainted=*/true);
100
66
}
101
102
76
void ento::registerBoolAssignmentChecker(CheckerManager &mgr) {
103
76
    mgr.registerChecker<BoolAssignmentChecker>();
104
76
}
105
106
152
bool ento::shouldRegisterBoolAssignmentChecker(const CheckerManager &mgr) {
107
152
  return true;
108
152
}