32#include "llvm/ADT/APFloat.h"
40class ConversionChecker :
public Checker<check::PreStmt<ImplicitCastExpr>> {
42 void checkPreStmt(
const ImplicitCastExpr *Cast, CheckerContext &
C)
const;
45 const BugType BT{
this,
"Conversion"};
47 bool isLossOfPrecision(
const ImplicitCastExpr *Cast, QualType DestType,
48 CheckerContext &
C)
const;
50 bool isLossOfSign(
const ImplicitCastExpr *Cast, CheckerContext &
C)
const;
52 void reportBug(ExplodedNode *N,
const Expr *E, CheckerContext &
C,
53 const char Msg[])
const;
60 if (
Cast->getType()->isBooleanType())
64 if (
Cast->getExprLoc().isMacroID())
68 const ParentMap &PM =
C.getLocationContext()->getParentMap();
76 bool LossOfSign =
false;
77 bool LossOfPrecision =
false;
80 if (
const auto *B = dyn_cast<BinaryOperator>(Parent)) {
82 if (Opc == BO_Assign) {
83 if (!
Cast->IgnoreParenImpCasts()->isEvaluatable(
C.getASTContext())) {
84 LossOfSign = isLossOfSign(Cast,
C);
85 LossOfPrecision = isLossOfPrecision(Cast,
Cast->getType(),
C);
87 }
else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
89 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(),
C);
90 }
else if (Opc == BO_MulAssign) {
91 LossOfSign = isLossOfSign(Cast,
C);
92 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(),
C);
93 }
else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
94 LossOfSign = isLossOfSign(Cast,
C);
96 }
else if (Opc == BO_AndAssign) {
97 LossOfSign = isLossOfSign(Cast,
C);
99 }
else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
100 LossOfSign = isLossOfSign(Cast,
C);
101 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(),
C);
102 }
else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
103 LossOfSign = isLossOfSign(Cast,
C);
106 if (!
Cast->IgnoreParenImpCasts()->isEvaluatable(
C.getASTContext())) {
107 LossOfSign = isLossOfSign(Cast,
C);
108 LossOfPrecision = isLossOfPrecision(Cast,
Cast->getType(),
C);
111 LossOfSign = isLossOfSign(Cast,
C);
112 LossOfPrecision = isLossOfPrecision(Cast,
Cast->getType(),
C);
115 if (LossOfSign || LossOfPrecision) {
117 ExplodedNode *N =
C.generateNonFatalErrorNode(
C.getState());
121 reportBug(N, Cast,
C,
"Loss of sign in implicit conversion");
123 reportBug(N, Cast,
C,
"Loss of precision in implicit conversion");
127void ConversionChecker::reportBug(ExplodedNode *N,
const Expr *E,
128 CheckerContext &
C,
const char Msg[])
const {
130 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
132 C.emitReport(std::move(R));
135bool ConversionChecker::isLossOfPrecision(
const ImplicitCastExpr *Cast,
137 CheckerContext &
C)
const {
139 if (
Cast->isEvaluatable(
C.getASTContext()))
142 QualType SubType =
Cast->IgnoreParenImpCasts()->getType();
149 const auto &AC =
C.getASTContext();
153 unsigned RepresentsUntilExp;
156 const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
157 RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
159 RepresentsUntilExp = AC.getIntWidth(DestType);
160 if (RepresentsUntilExp == 1) {
165 RepresentsUntilExp--;
168 if (RepresentsUntilExp >=
sizeof(
unsigned long long) *
CHAR_BIT) {
173 unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
177 if (RepresentsUntilExp >= CorrectedSrcWidth) {
182 unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
187 return C.isGreaterOrEqual(
Cast->getSubExpr(), MaxVal);
191bool ConversionChecker::isLossOfSign(
const ImplicitCastExpr *Cast,
192 CheckerContext &
C)
const {
194 QualType SubType =
Cast->IgnoreParenImpCasts()->getType();
199 return C.isNegative(
Cast->getSubExpr());
202void ento::registerConversionChecker(CheckerManager &mgr) {
206bool ento::shouldRegisterConversionChecker(
const CheckerManager &mgr) {
BinaryOperatorKind Opcode
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Stmt * getParent(Stmt *) const
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isFloatingType() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
bool Cast(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)