8323688: C2: Fix UB of jlong overflow in PhaseIdealLoop::is_counted_loop()

Reviewed-by: thartmann, kvn
This commit is contained in:
Christian Hagedorn 2024-09-24 06:47:20 +00:00
parent 4098acc200
commit 1dd60b62e3

View File

@ -1918,12 +1918,28 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_
// Since stride > 0 and limit_correction <= stride + 1, we can restate this with no over- or underflow into:
// max_int - canonicalized_correction - limit_correction >= limit
// Since canonicalized_correction and limit_correction are both constants, we can replace them with a new constant:
// final_correction = canonicalized_correction + limit_correction
// (v) final_correction = canonicalized_correction + limit_correction
//
// which gives us:
//
// Final predicate condition:
// max_int - final_correction >= limit
//
// However, we need to be careful that (v) does not over- or underflow.
// We know that:
// canonicalized_correction = stride - 1
// and
// limit_correction <= stride + 1
// and thus
// canonicalized_correction + limit_correction <= 2 * stride
// To prevent an over- or underflow of (v), we must ensure that
// 2 * stride <= max_int
// which can safely be checked without over- or underflow with
// (vi) stride != min_int AND abs(stride) <= max_int / 2
//
// We could try to further optimize the cases where (vi) does not hold but given that such large strides are
// very uncommon and the loop would only run for a very few iterations anyway, we simply bail out if (vi) fails.
//
// (2) Loop Limit Check Predicate for (ii):
// Using (ii): init < limit
//
@ -1954,6 +1970,10 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_
// there is no overflow of the iv phi after the first iteration. In this case, we don't need to check (ii)
// again and can skip the predicate.
// Check (vi) and bail out if the stride is too big.
if (stride_con == min_signed_integer(iv_bt) || (ABS(stride_con) > max_signed_integer(iv_bt) / 2)) {
return false;
}
// Accounting for (LE3) and (LE4) where we use pre-incremented phis in the loop exit check.
const jlong limit_correction_for_pre_iv_exit_check = (phi_incr != nullptr) ? stride_con : 0;