Skip to content

Fix pow overflow checks at min_value - #201

Open
abhiishek340 wants to merge 1 commit into
janestreet:masterfrom
abhiishek340:fix-pow-negative-overflow-bounds
Open

abhiishek340 wants to merge 1 commit into
janestreet:masterfrom
abhiishek340:fix-pow-negative-overflow-bounds

Conversation

@abhiishek340

Copy link
Copy Markdown

Fixes #197.

The negative overflow bounds were generated as the negated positive bounds, but min_value has one more unit of magnitude than max_value. Separately, int_pow and int63_pow_on_int64 used abs base, which is negative for min_value, so the bounds check was skipped.

before after
Int.pow Int.min_value 2 0 raises
Int.pow (-4) 31 (= Int.min_value) raises Int.min_value
Int64.pow (-2L) 63L raises Int64.min_value
Int64.pow (-8L) 21L raises Int64.min_value
Int64.pow Int64.min_value 0L raises 1L

One note on the issue: on 63-bit int, (-2) ** 62 = 2 ** 62, which does overflow, so raising there is correct. The int case that reaches min_value is (-4) ** 31.

Changes

  • generate_pow_overflow_bounds.ml: compute negative bounds against -(max_value + 1) for odd exponents (and for 0 and 1), and against max_value for even ones. Emit negative tables for every type, using the same per-architecture structure as the positive int table. Negative int entries are parenthesized inside Stdlib.Int64.to_int (...).
  • pow_overflow_bounds.ml / .mli: regenerated. Positive tables are unchanged. In int64_negative_overflow_bounds, only exponents 0, 1, 3, 7, 9, 21 and 63 change.
  • int_math.ml: int_pow and int63_pow_on_int64 compare signed bases against the positive and negative bounds, as int64_pow already does. This also removes the now-unused abs_local.

Testing

I don't have an OxCaml toolchain, so I haven't built Base itself. What I did check:

  • Ran the patched generator with OCaml 5.2.1 + zarith. The unpatched generator reproduces the committed pow_overflow_bounds.ml. Every new negative bound b at exponent e satisfies min_value <= b ** e, and b - 1 overflows.
  • Compiled the regenerated table file (with small stand-ins for Iarray / Portability_hacks) together with the new checks and an OCaml port of Base_int_math_int_pow_stub. Compared int, int64 and int63-on-int64 results against Zarith for about 210k (base, exponent) pairs: bases from -300 to 300, ±2^k ± 1, every table bound ± 1, and min_value / max_value; exponents 0 to 70. There were no mismatches.

The negative overflow bounds were the negated positive bounds, but
min_value has one more unit of magnitude than max_value. As a result:

- Int64.pow rejected exact results equal to Int64.min_value, such as
  (-2L) ** 63L and (-8L) ** 21L, and raised for Int64.min_value ** 0L.
- Int.pow and the Int63-on-int64 path used [abs base], which is
  negative for min_value, so Int.pow Int.min_value 2 returned 0 instead
  of raising. They also rejected (-4) ** 31 = Int.min_value.

Generate negative bounds from the minimum value for every integer type,
and make int_pow and int63_pow_on_int64 compare signed bases against the
positive and negative bounds, as int64_pow already does.

Fixes janestreet#197

Signed-off-by: Abhishek Yadav <abhiishek340@gmail.com>
@github-iron github-iron added the forwarded-to-js-devs This report has been forwarded to Jane Street's internal review system. label Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

forwarded-to-js-devs This report has been forwarded to Jane Street's internal review system.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

broken overflow check in pow

2 participants