Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Rust perform integer overflow checks in --release?

I have this piece of simple code:

let val: u8 = 255 + 1;
println!("{}", val);

It is said here that such a code will compile normally if run with the --release flag.

I am running this code via cargo run --release, and I still see the checks:

error: this arithmetic operation will overflow
 --> src/main.rs:2:19
  |
2 |     let val: u8 = 255 + 1;
  |                   ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
  |
  = note: `#[deny(arithmetic_overflow)]` on by default

error: could not compile `rust-bin` due to previous error

Am I missing something?

like image 491
Oleksandr Novik Avatar asked Dec 12 '25 10:12

Oleksandr Novik


1 Answers

The book is slightly imprecise. Overflow is in principle disallowed in both debug and release modes, it's just that release mode omits runtime checks for performance reasons (emitting code that overflows instead, which is cheap as that's what CPUs typically to do anyway). Static checks are not removed because they don't compromise on performance of generated code. This prints 0 in release mode and panics in debug1:

let x: u8 = "255".parse().unwrap();
let val: u8 = x + 1;
println!("{}", val);

You can disable the compile-time checks using #[allow(arithmetic_overflow)]. This also prints 0 in release mode and panics in debug:

#[allow(arithmetic_overflow)]
let val: u8 = 255 + 1;
println!("{}", val);

The correct approach is to not depend on this behavior of release mode, but to tell the compiler what you want. This prints 0 in both debug and release mode:

let val: u8 = 255u8.wrapping_add(1); // or saturating_add(), etc
println!("{}", val);

1 The example uses "255".parse() because, to my surprise, let x = 255u8; let val = x + 1; doesn't compile - in other words, rustc doesn't just prevent overflow in constant arithmetic, but also wherever else it can prove it happens. The change was apparently made in Rust 1.45, because it compiled in Rust 1.44 and older. Since it broke code that previously compiled, the change was technically backward-incompatible, but presumably broke sufficiently few actual crates that it was deemed worth it. Surprising as it is, it's quite possible that "255".parse::<u8>() + 1 will become a compile-time error in a later release.

like image 110
user4815162342 Avatar answered Dec 15 '25 13:12

user4815162342



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!