5.7 Overflow for Arithmetic Operations

Handling integer overflow is a critical consideration in systems programming, where incorrect handling can lead to security vulnerabilities or logic errors. Rust takes a different approach compared to languages like C when it comes to handling overflow in arithmetic operations.

5.7.1 Overflow Behavior in Debug Mode

In debug mode, Rust detects integer overflows and triggers a panic when overflow occurs. This allows developers to catch overflow issues early in the development process.

Example:

#![allow(unused)]
fn main() {
let x: u8 = 255;
let y = x + 1; // This will panic in debug mode due to overflow
println!("y = {}", y);
}

Running this code in debug mode results in a panic with a message indicating an attempt to add with overflow.

5.7.2 Overflow Behavior in Release Mode

In release mode, however, Rust performs two's complement wrapping arithmetic by default, where numbers wrap around (e.g., 255 + 1 becomes 0 for an u8).

5.7.3 Explicit Overflow Handling

Rust provides several methods to handle overflow explicitly:

  • Wrapping Arithmetic:

    • wrapping_add, wrapping_sub, wrapping_mul, etc.: Performs wrapping arithmetic explicitly.

      Example:

      fn main() {
          let x: u8 = 255;
          let y = x.wrapping_add(1); // y will be 0
          println!("Wrapping add result: {}", y);
      }
  • Checked Arithmetic:

    • checked_add, checked_sub, checked_mul, etc.: Returns Option types (Some(result) or None if overflow occurs), allowing for safe handling of overflows.

      Example:

      fn main() {
          let x: u8 = 255;
          match x.checked_add(1) {
              Some(y) => println!("Checked add result: {}", y),
              None => println!("Overflow occurred!"),
          }
      }
  • Saturating Arithmetic:

    • saturating_add, saturating_sub, saturating_mul, etc.: Saturates at the numeric boundaries (e.g., u8::MAX or u8::MIN).

      Example:

      fn main() {
          let x: u8 = 250;
          let y = x.saturating_add(10); // y will be 255 (u8::MAX)
          println!("Saturating add result: {}", y);
      }
  • Overflowing Arithmetic:

    • overflowing_add, overflowing_sub, overflowing_mul, etc.: Returns a tuple containing the result and a boolean indicating whether overflow occurred.

      Example:

      fn main() {
          let x: u8 = 255;
          let (y, overflowed) = x.overflowing_add(1);
          println!("Overflowing add result: {}, overflowed: {}", y, overflowed);
      }

By explicitly handling overflow, Rust ensures that you are aware of potential issues and can design safer programs, eliminating some of the vulnerabilities commonly found in systems written in C.