BoolAssignmentChecker.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. #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>
  20. using namespace clang;
  21. using namespace ento;
  22. namespace {
  23. class BoolAssignmentChecker : public Checker< check::Bind > {
  24. mutable std::unique_ptr<BuiltinBug> BT;
  25. void emitReport(ProgramStateRef state, CheckerContext &C,
  26. bool IsTainted = false) const;
  27. public:
  28. void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
  29. };
  30. } // end anonymous namespace
  31. void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext &C,
  32. bool IsTainted) const {
  33. if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
  34. if (!BT)
  35. BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
  36. StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value"
  37. : "Assignment of a non-Boolean value";
  38. C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, Msg, N));
  39. }
  40. }
  41. static bool isBooleanType(QualType Ty) {
  42. if (Ty->isBooleanType()) // C++ or C99
  43. return true;
  44. if (const TypedefType *TT = Ty->getAs<TypedefType>())
  45. return TT->getDecl()->getName() == "BOOL" || // Objective-C
  46. TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99
  47. TT->getDecl()->getName() == "Boolean"; // MacTypes.h
  48. return false;
  49. }
  50. void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
  51. CheckerContext &C) const {
  52. // We are only interested in stores into Booleans.
  53. const TypedValueRegion *TR =
  54. dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
  55. if (!TR)
  56. return;
  57. QualType valTy = TR->getValueType();
  58. if (!isBooleanType(valTy))
  59. return;
  60. // Get the value of the right-hand side. We only care about values
  61. // that are defined (UnknownVals and UndefinedVals are handled by other
  62. // checkers).
  63. std::optional<NonLoc> NV = val.getAs<NonLoc>();
  64. if (!NV)
  65. return;
  66. // Check if the assigned value meets our criteria for correctness. It must
  67. // be a value that is either 0 or 1. One way to check this is to see if
  68. // the value is possibly < 0 (for a negative value) or greater than 1.
  69. ProgramStateRef state = C.getState();
  70. SValBuilder &svalBuilder = C.getSValBuilder();
  71. BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
  72. ConstraintManager &CM = C.getConstraintManager();
  73. llvm::APSInt Zero = BVF.getValue(0, valTy);
  74. llvm::APSInt One = BVF.getValue(1, valTy);
  75. ProgramStateRef StIn, StOut;
  76. std::tie(StIn, StOut) = CM.assumeInclusiveRangeDual(state, *NV, Zero, One);
  77. if (!StIn)
  78. emitReport(StOut, C);
  79. if (StIn && StOut && taint::isTainted(state, *NV))
  80. emitReport(StOut, C, /*IsTainted=*/true);
  81. }
  82. void ento::registerBoolAssignmentChecker(CheckerManager &mgr) {
  83. mgr.registerChecker<BoolAssignmentChecker>();
  84. }
  85. bool ento::shouldRegisterBoolAssignmentChecker(const CheckerManager &mgr) {
  86. return true;
  87. }