diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp | 201 |
1 files changed, 0 insertions, 201 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp deleted file mode 100644 index 5058d101b8e5..000000000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp +++ /dev/null @@ -1,201 +0,0 @@ -//=== ConversionChecker.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Check that there is no loss of sign/precision in assignments, comparisons -// and multiplications. -// -// ConversionChecker uses path sensitive analysis to determine possible values -// of expressions. A warning is reported when: -// * a negative value is implicitly converted to an unsigned value in an -// assignment, comparison or multiplication. -// * assignment / initialization when the source value is greater than the max -// value of the target integer type -// * assignment / initialization when the source integer is above the range -// where the target floating point type can represent all integers -// -// Many compilers and tools have similar checks that are based on semantic -// analysis. Those checks are sound but have poor precision. ConversionChecker -// is an alternative to those checks. -// -//===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" -#include "clang/AST/ParentMap.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "llvm/ADT/APFloat.h" - -#include <climits> - -using namespace clang; -using namespace ento; - -namespace { -class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> { -public: - void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const; - -private: - mutable std::unique_ptr<BuiltinBug> BT; - - bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType, - CheckerContext &C) const; - - bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const; - - void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const; -}; -} - -void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast, - CheckerContext &C) const { - // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for - // calculations also. - if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts())) - return; - - // Don't warn for loss of sign/precision in macros. - if (Cast->getExprLoc().isMacroID()) - return; - - // Get Parent. - const ParentMap &PM = C.getLocationContext()->getParentMap(); - const Stmt *Parent = PM.getParent(Cast); - if (!Parent) - return; - - bool LossOfSign = false; - bool LossOfPrecision = false; - - // Loss of sign/precision in binary operation. - if (const auto *B = dyn_cast<BinaryOperator>(Parent)) { - BinaryOperator::Opcode Opc = B->getOpcode(); - if (Opc == BO_Assign) { - LossOfSign = isLossOfSign(Cast, C); - LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C); - } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) { - // No loss of sign. - LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C); - } else if (Opc == BO_MulAssign) { - LossOfSign = isLossOfSign(Cast, C); - LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C); - } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) { - LossOfSign = isLossOfSign(Cast, C); - // No loss of precision. - } else if (Opc == BO_AndAssign) { - LossOfSign = isLossOfSign(Cast, C); - // No loss of precision. - } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) { - LossOfSign = isLossOfSign(Cast, C); - LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C); - } else if (B->isRelationalOp() || B->isMultiplicativeOp()) { - LossOfSign = isLossOfSign(Cast, C); - } - } else if (isa<DeclStmt>(Parent)) { - LossOfSign = isLossOfSign(Cast, C); - LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C); - } - - if (LossOfSign || LossOfPrecision) { - // Generate an error node. - ExplodedNode *N = C.generateNonFatalErrorNode(C.getState()); - if (!N) - return; - if (LossOfSign) - reportBug(N, C, "Loss of sign in implicit conversion"); - if (LossOfPrecision) - reportBug(N, C, "Loss of precision in implicit conversion"); - } -} - -void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C, - const char Msg[]) const { - if (!BT) - BT.reset( - new BuiltinBug(this, "Conversion", "Possible loss of sign/precision.")); - - // Generate a report for this bug. - auto R = llvm::make_unique<BugReport>(*BT, Msg, N); - C.emitReport(std::move(R)); -} - -bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast, - QualType DestType, - CheckerContext &C) const { - // Don't warn about explicit loss of precision. - if (Cast->isEvaluatable(C.getASTContext())) - return false; - - QualType SubType = Cast->IgnoreParenImpCasts()->getType(); - - if (!DestType->isRealType() || !SubType->isIntegerType()) - return false; - - const bool isFloat = DestType->isFloatingType(); - - const auto &AC = C.getASTContext(); - - // We will find the largest RepresentsUntilExp value such that the DestType - // can exactly represent all nonnegative integers below 2^RepresentsUntilExp. - unsigned RepresentsUntilExp; - - if (isFloat) { - const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType); - RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema); - } else { - RepresentsUntilExp = AC.getIntWidth(DestType); - if (RepresentsUntilExp == 1) { - // This is just casting a number to bool, probably not a bug. - return false; - } - if (DestType->isSignedIntegerType()) - RepresentsUntilExp--; - } - - if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) { - // Avoid overflow in our later calculations. - return false; - } - - unsigned CorrectedSrcWidth = AC.getIntWidth(SubType); - if (SubType->isSignedIntegerType()) - CorrectedSrcWidth--; - - if (RepresentsUntilExp >= CorrectedSrcWidth) { - // Simple case: the destination can store all values of the source type. - return false; - } - - unsigned long long MaxVal = 1ULL << RepresentsUntilExp; - if (isFloat) { - // If this is a floating point type, it can also represent MaxVal exactly. - MaxVal++; - } - return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal); - // TODO: maybe also check negative values with too large magnitude. -} - -bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast, - CheckerContext &C) const { - QualType CastType = Cast->getType(); - QualType SubType = Cast->IgnoreParenImpCasts()->getType(); - - if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType()) - return false; - - return C.isNegative(Cast->getSubExpr()); -} - -void ento::registerConversionChecker(CheckerManager &mgr) { - mgr.registerChecker<ConversionChecker>(); -} - -bool ento::shouldRegisterConversionChecker(const LangOptions &LO) { - return true; -} |
