@@ -51,6 +51,64 @@ struct BinOpInfo {
51
51
BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
52
52
FPOptions FPFeatures;
53
53
const Expr *E; // Entire expr, for error unsupported. May not be binop.
54
+
55
+ // / Check if the binop can result in integer overflow.
56
+ bool mayHaveIntegerOverflow () const {
57
+ // Without constant input, we can't rule out overflow.
58
+ const auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS);
59
+ const auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS);
60
+ if (!LHSCI || !RHSCI)
61
+ return true ;
62
+
63
+ // Assume overflow is possible, unless we can prove otherwise.
64
+ bool Overflow = true ;
65
+ const auto &LHSAP = LHSCI->getValue ();
66
+ const auto &RHSAP = RHSCI->getValue ();
67
+ if (Opcode == BO_Add) {
68
+ if (Ty->hasSignedIntegerRepresentation ())
69
+ (void )LHSAP.sadd_ov (RHSAP, Overflow);
70
+ else
71
+ (void )LHSAP.uadd_ov (RHSAP, Overflow);
72
+ } else if (Opcode == BO_Sub) {
73
+ if (Ty->hasSignedIntegerRepresentation ())
74
+ (void )LHSAP.ssub_ov (RHSAP, Overflow);
75
+ else
76
+ (void )LHSAP.usub_ov (RHSAP, Overflow);
77
+ } else if (Opcode == BO_Mul) {
78
+ if (Ty->hasSignedIntegerRepresentation ())
79
+ (void )LHSAP.smul_ov (RHSAP, Overflow);
80
+ else
81
+ (void )LHSAP.umul_ov (RHSAP, Overflow);
82
+ } else if (Opcode == BO_Div || Opcode == BO_Rem) {
83
+ if (Ty->hasSignedIntegerRepresentation () && !RHSCI->isZero ())
84
+ (void )LHSAP.sdiv_ov (RHSAP, Overflow);
85
+ else
86
+ return false ;
87
+ }
88
+ return Overflow;
89
+ }
90
+
91
+ // / Check if the binop computes a division or a remainder.
92
+ bool isDivisionLikeOperation () const {
93
+ return Opcode == BO_Div || Opcode == BO_Rem || Opcode == BO_DivAssign ||
94
+ Opcode == BO_RemAssign;
95
+ }
96
+
97
+ // / Check if the binop can result in an integer division by zero.
98
+ bool mayHaveIntegerDivisionByZero () const {
99
+ if (isDivisionLikeOperation ())
100
+ if (auto *CI = dyn_cast<llvm::ConstantInt>(RHS))
101
+ return CI->isZero ();
102
+ return true ;
103
+ }
104
+
105
+ // / Check if the binop can result in a float division by zero.
106
+ bool mayHaveFloatDivisionByZero () const {
107
+ if (isDivisionLikeOperation ())
108
+ if (auto *CFP = dyn_cast<llvm::ConstantFP>(RHS))
109
+ return CFP->isZero ();
110
+ return true ;
111
+ }
54
112
};
55
113
56
114
static bool MustVisitNullValue (const Expr *E) {
@@ -85,9 +143,17 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
85
143
assert ((isa<UnaryOperator>(Op.E ) || isa<BinaryOperator>(Op.E )) &&
86
144
" Expected a unary or binary operator" );
87
145
146
+ // If the binop has constant inputs and we can prove there is no overflow,
147
+ // we can elide the overflow check.
148
+ if (!Op.mayHaveIntegerOverflow ())
149
+ return true ;
150
+
151
+ // If a unary op has a widened operand, the op cannot overflow.
88
152
if (const auto *UO = dyn_cast<UnaryOperator>(Op.E ))
89
153
return IsWidenedIntegerOp (Ctx, UO->getSubExpr ());
90
154
155
+ // We usually don't need overflow checks for binops with widened operands.
156
+ // Multiplication with promoted unsigned operands is a special case.
91
157
const auto *BO = cast<BinaryOperator>(Op.E );
92
158
auto OptionalLHSTy = getUnwidenedIntegerType (Ctx, BO->getLHS ());
93
159
if (!OptionalLHSTy)
@@ -100,14 +166,14 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
100
166
QualType LHSTy = *OptionalLHSTy;
101
167
QualType RHSTy = *OptionalRHSTy;
102
168
103
- // We usually don't need overflow checks for binary operations with widened
104
- // operands. Multiplication with promoted unsigned operands is a special case .
169
+ // This is the simple case: binops without unsigned multiplication, and with
170
+ // widened operands. No overflow check is needed here .
105
171
if ((Op.Opcode != BO_Mul && Op.Opcode != BO_MulAssign) ||
106
172
!LHSTy->isUnsignedIntegerType () || !RHSTy->isUnsignedIntegerType ())
107
173
return true ;
108
174
109
- // The overflow check can be skipped if either one of the unpromoted types
110
- // are less than half the size of the promoted type.
175
+ // For unsigned multiplication the overflow check can be elided if either one
176
+ // of the unpromoted types are less than half the size of the promoted type.
111
177
unsigned PromotedSize = Ctx.getTypeSize (Op.E ->getType ());
112
178
return (2 * Ctx.getTypeSize (LHSTy)) < PromotedSize ||
113
179
(2 * Ctx.getTypeSize (RHSTy)) < PromotedSize;
@@ -2377,7 +2443,8 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
2377
2443
const auto *BO = cast<BinaryOperator>(Ops.E );
2378
2444
if (CGF.SanOpts .has (SanitizerKind::SignedIntegerOverflow) &&
2379
2445
Ops.Ty ->hasSignedIntegerRepresentation () &&
2380
- !IsWidenedIntegerOp (CGF.getContext (), BO->getLHS ())) {
2446
+ !IsWidenedIntegerOp (CGF.getContext (), BO->getLHS ()) &&
2447
+ Ops.mayHaveIntegerOverflow ()) {
2381
2448
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType ());
2382
2449
2383
2450
llvm::Value *IntMin =
@@ -2400,11 +2467,13 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
2400
2467
CodeGenFunction::SanitizerScope SanScope (&CGF);
2401
2468
if ((CGF.SanOpts .has (SanitizerKind::IntegerDivideByZero) ||
2402
2469
CGF.SanOpts .has (SanitizerKind::SignedIntegerOverflow)) &&
2403
- Ops.Ty ->isIntegerType ()) {
2470
+ Ops.Ty ->isIntegerType () &&
2471
+ (Ops.mayHaveIntegerDivisionByZero () || Ops.mayHaveIntegerOverflow ())) {
2404
2472
llvm::Value *Zero = llvm::Constant::getNullValue (ConvertType (Ops.Ty ));
2405
2473
EmitUndefinedBehaviorIntegerDivAndRemCheck (Ops, Zero, true );
2406
2474
} else if (CGF.SanOpts .has (SanitizerKind::FloatDivideByZero) &&
2407
- Ops.Ty ->isRealFloatingType ()) {
2475
+ Ops.Ty ->isRealFloatingType () &&
2476
+ Ops.mayHaveFloatDivisionByZero ()) {
2408
2477
llvm::Value *Zero = llvm::Constant::getNullValue (ConvertType (Ops.Ty ));
2409
2478
llvm::Value *NonZero = Builder.CreateFCmpUNE (Ops.RHS , Zero);
2410
2479
EmitBinOpCheck (std::make_pair (NonZero, SanitizerKind::FloatDivideByZero),
@@ -2439,7 +2508,8 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
2439
2508
// Rem in C can't be a floating point type: C99 6.5.5p2.
2440
2509
if ((CGF.SanOpts .has (SanitizerKind::IntegerDivideByZero) ||
2441
2510
CGF.SanOpts .has (SanitizerKind::SignedIntegerOverflow)) &&
2442
- Ops.Ty ->isIntegerType ()) {
2511
+ Ops.Ty ->isIntegerType () &&
2512
+ (Ops.mayHaveIntegerDivisionByZero () || Ops.mayHaveIntegerOverflow ())) {
2443
2513
CodeGenFunction::SanitizerScope SanScope (&CGF);
2444
2514
llvm::Value *Zero = llvm::Constant::getNullValue (ConvertType (Ops.Ty ));
2445
2515
EmitUndefinedBehaviorIntegerDivAndRemCheck (Ops, Zero, false );
0 commit comments