ConversionChecker.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. //=== ConversionChecker.cpp -------------------------------------*- 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. // Check that there is no loss of sign/precision in assignments, comparisons
  10. // and multiplications.
  11. //
  12. // ConversionChecker uses path sensitive analysis to determine possible values
  13. // of expressions. A warning is reported when:
  14. // * a negative value is implicitly converted to an unsigned value in an
  15. // assignment, comparison or multiplication.
  16. // * assignment / initialization when the source value is greater than the max
  17. // value of the target integer type
  18. // * assignment / initialization when the source integer is above the range
  19. // where the target floating point type can represent all integers
  20. //
  21. // Many compilers and tools have similar checks that are based on semantic
  22. // analysis. Those checks are sound but have poor precision. ConversionChecker
  23. // is an alternative to those checks.
  24. //
  25. //===----------------------------------------------------------------------===//
  26. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  27. #include "clang/AST/ParentMap.h"
  28. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  29. #include "clang/StaticAnalyzer/Core/Checker.h"
  30. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  31. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  32. #include "llvm/ADT/APFloat.h"
  33. #include <climits>
  34. using namespace clang;
  35. using namespace ento;
  36. namespace {
  37. class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
  38. public:
  39. void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;
  40. private:
  41. mutable std::unique_ptr<BuiltinBug> BT;
  42. bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
  43. CheckerContext &C) const;
  44. bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
  45. void reportBug(ExplodedNode *N, const Expr *E, CheckerContext &C,
  46. const char Msg[]) const;
  47. };
  48. }
  49. void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
  50. CheckerContext &C) const {
  51. // Don't warn for implicit conversions to bool
  52. if (Cast->getType()->isBooleanType())
  53. return;
  54. // Don't warn for loss of sign/precision in macros.
  55. if (Cast->getExprLoc().isMacroID())
  56. return;
  57. // Get Parent.
  58. const ParentMap &PM = C.getLocationContext()->getParentMap();
  59. const Stmt *Parent = PM.getParent(Cast);
  60. if (!Parent)
  61. return;
  62. // Dont warn if this is part of an explicit cast
  63. if (isa<ExplicitCastExpr>(Parent))
  64. return;
  65. bool LossOfSign = false;
  66. bool LossOfPrecision = false;
  67. // Loss of sign/precision in binary operation.
  68. if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
  69. BinaryOperator::Opcode Opc = B->getOpcode();
  70. if (Opc == BO_Assign) {
  71. if (!Cast->IgnoreParenImpCasts()->isEvaluatable(C.getASTContext())) {
  72. LossOfSign = isLossOfSign(Cast, C);
  73. LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
  74. }
  75. } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
  76. // No loss of sign.
  77. LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
  78. } else if (Opc == BO_MulAssign) {
  79. LossOfSign = isLossOfSign(Cast, C);
  80. LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
  81. } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
  82. LossOfSign = isLossOfSign(Cast, C);
  83. // No loss of precision.
  84. } else if (Opc == BO_AndAssign) {
  85. LossOfSign = isLossOfSign(Cast, C);
  86. // No loss of precision.
  87. } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
  88. LossOfSign = isLossOfSign(Cast, C);
  89. LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
  90. } else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
  91. LossOfSign = isLossOfSign(Cast, C);
  92. }
  93. } else if (isa<DeclStmt, ReturnStmt>(Parent)) {
  94. if (!Cast->IgnoreParenImpCasts()->isEvaluatable(C.getASTContext())) {
  95. LossOfSign = isLossOfSign(Cast, C);
  96. LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
  97. }
  98. } else {
  99. LossOfSign = isLossOfSign(Cast, C);
  100. LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
  101. }
  102. if (LossOfSign || LossOfPrecision) {
  103. // Generate an error node.
  104. ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
  105. if (!N)
  106. return;
  107. if (LossOfSign)
  108. reportBug(N, Cast, C, "Loss of sign in implicit conversion");
  109. if (LossOfPrecision)
  110. reportBug(N, Cast, C, "Loss of precision in implicit conversion");
  111. }
  112. }
  113. void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E,
  114. CheckerContext &C, const char Msg[]) const {
  115. if (!BT)
  116. BT.reset(
  117. new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
  118. // Generate a report for this bug.
  119. auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
  120. bugreporter::trackExpressionValue(N, E, *R);
  121. C.emitReport(std::move(R));
  122. }
  123. bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
  124. QualType DestType,
  125. CheckerContext &C) const {
  126. // Don't warn about explicit loss of precision.
  127. if (Cast->isEvaluatable(C.getASTContext()))
  128. return false;
  129. QualType SubType = Cast->IgnoreParenImpCasts()->getType();
  130. if (!DestType->isRealType() || !SubType->isIntegerType())
  131. return false;
  132. const bool isFloat = DestType->isFloatingType();
  133. const auto &AC = C.getASTContext();
  134. // We will find the largest RepresentsUntilExp value such that the DestType
  135. // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
  136. unsigned RepresentsUntilExp;
  137. if (isFloat) {
  138. const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
  139. RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
  140. } else {
  141. RepresentsUntilExp = AC.getIntWidth(DestType);
  142. if (RepresentsUntilExp == 1) {
  143. // This is just casting a number to bool, probably not a bug.
  144. return false;
  145. }
  146. if (DestType->isSignedIntegerType())
  147. RepresentsUntilExp--;
  148. }
  149. if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
  150. // Avoid overflow in our later calculations.
  151. return false;
  152. }
  153. unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
  154. if (SubType->isSignedIntegerType())
  155. CorrectedSrcWidth--;
  156. if (RepresentsUntilExp >= CorrectedSrcWidth) {
  157. // Simple case: the destination can store all values of the source type.
  158. return false;
  159. }
  160. unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
  161. if (isFloat) {
  162. // If this is a floating point type, it can also represent MaxVal exactly.
  163. MaxVal++;
  164. }
  165. return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
  166. // TODO: maybe also check negative values with too large magnitude.
  167. }
  168. bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
  169. CheckerContext &C) const {
  170. QualType CastType = Cast->getType();
  171. QualType SubType = Cast->IgnoreParenImpCasts()->getType();
  172. if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
  173. return false;
  174. return C.isNegative(Cast->getSubExpr());
  175. }
  176. void ento::registerConversionChecker(CheckerManager &mgr) {
  177. mgr.registerChecker<ConversionChecker>();
  178. }
  179. bool ento::shouldRegisterConversionChecker(const CheckerManager &mgr) {
  180. return true;
  181. }