BoolAssignmentChecker.cpp 3.5 KB

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