Skip to content

Commit 940de82

Browse files
DadaIsCrazyV8 LUCI CQ
authored andcommitted
[turboshaft] Prevent signed division overflow in loop unrolling
Signed division can overflow in a single case: min_int/-1. This is undefined behavior, and could lead in particular to floating point exceptions. Bug: chromium:42202729 Change-Id: Ieb702a24d204bc81fc912f1085beb28d22e7b1b5 Fixed: chromium:356183775 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5756762 Auto-Submit: Darius Mercadier <[email protected]> Reviewed-by: Matthias Liedtke <[email protected]> Commit-Queue: Darius Mercadier <[email protected]> Cr-Commit-Position: refs/heads/main@{#95470}
1 parent 651c429 commit 940de82

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

src/compiler/turboshaft/loop-unrolling-reducer.cc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,20 @@ bool SubWillOverflow(Int lhs, Int rhs) {
362362
}
363363
}
364364

365+
template <class Int>
366+
bool DivWillOverflow(Int dividend, Int divisor) {
367+
if constexpr (std::is_unsigned_v<Int>) {
368+
return false;
369+
} else {
370+
return dividend == std::numeric_limits<Int>::min() && divisor == -1;
371+
}
372+
}
373+
365374
} // namespace
366375

367-
// Returns true if the loop `for (i = init, i cmp_op max; i = i binop_cst
368-
// binop_op)` has fewer than `max_iter_` iterations.
376+
// Returns true if the loop
377+
// `for (i = init, i cmp_op max; i = i binop_op binop_cst)` has fewer than
378+
// `max_iter_` iterations.
369379
template <class Int>
370380
IterationCount StaticCanonicalForLoopMatcher::CountIterationsImpl(
371381
Int init, Int max, CmpOp cmp_op, Int binop_cst, BinOp binop_op,
@@ -419,6 +429,7 @@ IterationCount StaticCanonicalForLoopMatcher::CountIterationsImpl(
419429
// eventually stop.
420430
return {};
421431
}
432+
DCHECK(!DivWillOverflow(max - init, binop_cst));
422433
Int quotient = (max - init) / binop_cst;
423434
DCHECK_GE(quotient, 0);
424435
return IterationCount::Approx(quotient);
@@ -434,6 +445,7 @@ IterationCount StaticCanonicalForLoopMatcher::CountIterationsImpl(
434445
// eventually stop.
435446
return {};
436447
}
448+
if (DivWillOverflow(max - init, binop_cst)) return {};
437449
Int quotient = (max - init) / binop_cst;
438450
DCHECK_GE(quotient, 0);
439451
return IterationCount::Approx(quotient);
@@ -469,8 +481,9 @@ IterationCount StaticCanonicalForLoopMatcher::CountIterationsImpl(
469481
return {};
470482
}
471483

472-
// Returns true if the loop `for (i = init, i cmp_op max; i = i binop_cst
473-
// binop_op)` has fewer than `max_iter_` iterations.
484+
// Returns true if the loop
485+
// `for (i = initial_input, i cmp_op cmp_cst; i = i binop_op binop_cst)` has
486+
// fewer than `max_iter_` iterations.
474487
IterationCount StaticCanonicalForLoopMatcher::CountIterations(
475488
uint64_t cmp_cst, CmpOp cmp_op, uint64_t initial_input, uint64_t binop_cst,
476489
BinOp binop_op, WordRepresentation binop_rep, bool loop_if_cond_is) const {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2024 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
for (let i = 0; i < 50; i++) {
6+
for (let j = 2; -2147483647 < j; j--) {
7+
if (j == -30000) {
8+
break;
9+
}
10+
}
11+
}

0 commit comments

Comments
 (0)