Bug: signed int multiply translated as checked *, panics instead of wrapping like C
Related to the already-fixed #27 (refcount.h overflow-detection idiom) — same root cause class (C's implementation-defined-wrapping signed arithmetic translated as Rust's panic-on-overflow */+/-), different call site.
Repro
C source (lib/tests/test_sort.c, a bounded LCG-style pseudo-random sequence):
static void test_sort(struct kunit *test)
{
int *a, i, r = 1;
...
for (i = 0; i < TEST_LEN; i++) {
r = (r * 725861) % 6599;
a[i] = r;
}
...
}
r is always reduced mod 6599 after each iteration, so on the surface this looks bounded — but the intermediate product r * 725861 (with r up to 6598) is up to ~4.79 billion, which overflows i32 (max ~2.1 billion) before the % 6599 brings it back down. C's signed overflow here wraps in practice (GCC/clang default codegen); c2rust's transpile emits a plain Rust * operator:
r = r * 725861 as ::core::ffi::c_int % 6599 as ::core::ffi::c_int;
With overflow-checks on (as in a debug/kernel Rust build), this panics at runtime:
panicked at lib/tests/test_sort_rs.rs:4088:17:
attempt to multiply with overflow
Fix applied locally (narrow, not upstreamed yet)
r = r.wrapping_mul(725861 as ::core::ffi::c_int) % 6599 as ::core::ffi::c_int;
Suggested general fix
Same shape as #27's resolution: any C signed-integer */+/- operation should translate to wrapping_mul/wrapping_add/wrapping_sub rather than the bare Rust operator, since C's actual (if technically UB) runtime behavior for these ops is 2's-complement wraparound on every mainstream target — matching what #27 already established for +/-, this closes the same gap for *.
Bug: signed
intmultiply translated as checked*, panics instead of wrapping like CRelated to the already-fixed #27 (
refcount.hoverflow-detection idiom) — same root cause class (C's implementation-defined-wrapping signed arithmetic translated as Rust's panic-on-overflow*/+/-), different call site.Repro
C source (
lib/tests/test_sort.c, a bounded LCG-style pseudo-random sequence):ris always reduced mod 6599 after each iteration, so on the surface this looks bounded — but the intermediate productr * 725861(withrup to 6598) is up to ~4.79 billion, which overflowsi32(max ~2.1 billion) before the% 6599brings it back down. C's signed overflow here wraps in practice (GCC/clang default codegen); c2rust's transpile emits a plain Rust*operator:With
overflow-checkson (as in a debug/kernel Rust build), this panics at runtime:Fix applied locally (narrow, not upstreamed yet)
Suggested general fix
Same shape as #27's resolution: any C signed-integer
*/+/-operation should translate towrapping_mul/wrapping_add/wrapping_subrather than the bare Rust operator, since C's actual (if technically UB) runtime behavior for these ops is 2's-complement wraparound on every mainstream target — matching what #27 already established for+/-, this closes the same gap for*.