BoolAssignmentChecker.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- C++ -*--==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This defines BoolAssignmentChecker, a builtin check in ExprEngine that
  11. // performs checks for assignment of non-Boolean values to Boolean variables.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.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. using namespace clang;
  20. using namespace ento;
  21. namespace {
  22. class BoolAssignmentChecker : public Checker< check::Bind > {
  23. mutable std::unique_ptr<BuiltinBug> BT;
  24. void emitReport(ProgramStateRef state, CheckerContext &C) const;
  25. public:
  26. void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
  27. };
  28. } // end anonymous namespace
  29. void BoolAssignmentChecker::emitReport(ProgramStateRef state,
  30. CheckerContext &C) const {
  31. if (ExplodedNode *N = C.addTransition(state)) {
  32. if (!BT)
  33. BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
  34. C.emitReport(llvm::make_unique<BugReport>(*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<DefinedSVal> DV = val.getAs<DefinedSVal>();
  60. if (!DV)
  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. ConstraintManager &CM = C.getConstraintManager();
  68. // First, ensure that the value is >= 0.
  69. DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
  70. SVal greaterThanOrEqualToZeroVal =
  71. svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
  72. svalBuilder.getConditionType());
  73. Optional<DefinedSVal> greaterThanEqualToZero =
  74. greaterThanOrEqualToZeroVal.getAs<DefinedSVal>();
  75. if (!greaterThanEqualToZero) {
  76. // The SValBuilder cannot construct a valid SVal for this condition.
  77. // This means we cannot properly reason about it.
  78. return;
  79. }
  80. ProgramStateRef stateLT, stateGE;
  81. std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
  82. // Is it possible for the value to be less than zero?
  83. if (stateLT) {
  84. // It is possible for the value to be less than zero. We only
  85. // want to emit a warning, however, if that value is fully constrained.
  86. // If it it possible for the value to be >= 0, then essentially the
  87. // value is underconstrained and there is nothing left to be done.
  88. if (!stateGE)
  89. emitReport(stateLT, C);
  90. // In either case, we are done.
  91. return;
  92. }
  93. // If we reach here, it must be the case that the value is constrained
  94. // to only be >= 0.
  95. assert(stateGE == state);
  96. // At this point we know that the value is >= 0.
  97. // Now check to ensure that the value is <= 1.
  98. DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy);
  99. SVal lessThanEqToOneVal =
  100. svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal,
  101. svalBuilder.getConditionType());
  102. Optional<DefinedSVal> lessThanEqToOne =
  103. lessThanEqToOneVal.getAs<DefinedSVal>();
  104. if (!lessThanEqToOne) {
  105. // The SValBuilder cannot construct a valid SVal for this condition.
  106. // This means we cannot properly reason about it.
  107. return;
  108. }
  109. ProgramStateRef stateGT, stateLE;
  110. std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
  111. // Is it possible for the value to be greater than one?
  112. if (stateGT) {
  113. // It is possible for the value to be greater than one. We only
  114. // want to emit a warning, however, if that value is fully constrained.
  115. // If it is possible for the value to be <= 1, then essentially the
  116. // value is underconstrained and there is nothing left to be done.
  117. if (!stateLE)
  118. emitReport(stateGT, C);
  119. // In either case, we are done.
  120. return;
  121. }
  122. // If we reach here, it must be the case that the value is constrained
  123. // to only be <= 1.
  124. assert(stateLE == state);
  125. }
  126. void ento::registerBoolAssignmentChecker(CheckerManager &mgr) {
  127. mgr.registerChecker<BoolAssignmentChecker>();
  128. }