32 #include "llvm/ADT/APFloat.h"
36 using namespace clang;
40 class ConversionChecker :
public Checker<check::PreStmt<ImplicitCastExpr>> {
45 mutable std::unique_ptr<BuiltinBug> BT;
48 CheckerContext &C)
const;
52 void reportBug(ExplodedNode *N,
const Expr *E, CheckerContext &C,
53 const char Msg[])
const;
58 CheckerContext &C)
const {
60 if (
Cast->getType()->isBooleanType())
64 if (
Cast->getExprLoc().isMacroID())
68 const ParentMap &PM =
C.getLocationContext()->getParentMap();
73 if (isa<ExplicitCastExpr>(
Parent))
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);
105 }
else if (isa<DeclStmt, ReturnStmt>(
Parent)) {
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");
127 void ConversionChecker::reportBug(ExplodedNode *N,
const Expr *E,
128 CheckerContext &C,
const char Msg[])
const {
131 new BuiltinBug(
this,
"Conversion",
"Possible loss of sign/precision."));
134 auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
136 C.emitReport(std::move(R));
141 CheckerContext &C)
const {
143 if (
Cast->isEvaluatable(
C.getASTContext()))
146 QualType SubType =
Cast->IgnoreParenImpCasts()->getType();
153 const auto &AC =
C.getASTContext();
157 unsigned RepresentsUntilExp;
160 const llvm::fltSemantics &
Sema = AC.getFloatTypeSemantics(DestType);
161 RepresentsUntilExp = llvm::APFloat::semanticsPrecision(
Sema);
163 RepresentsUntilExp = AC.getIntWidth(DestType);
164 if (RepresentsUntilExp == 1) {
169 RepresentsUntilExp--;
172 if (RepresentsUntilExp >=
sizeof(
unsigned long long) *
CHAR_BIT) {
177 unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
181 if (RepresentsUntilExp >= CorrectedSrcWidth) {
186 unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
191 return C.isGreaterOrEqual(
Cast->getSubExpr(), MaxVal);
196 CheckerContext &C)
const {
198 QualType SubType =
Cast->IgnoreParenImpCasts()->getType();
203 return C.isNegative(
Cast->getSubExpr());
206 void ento::registerConversionChecker(CheckerManager &mgr) {
207 mgr.registerChecker<ConversionChecker>();
210 bool ento::shouldRegisterConversionChecker(
const CheckerManager &mgr) {