Search code examples
rustpanic

What are all the ways rust might panic without explicitly calling unwrap/panic?


Recently I was writing a driver for a pressure sensor and was avoiding using floating-point instructions as the microcontroller I am using doesn't have a hardware FPU and emulated instructions are rather expensive. I made an error in the type I used to store the result of the multiplication. As a result with some inputs, this code would overflow the integer and panic.

This is great, as it meant that I found the bug before it got out into production. But on further research, it seems that this integer-overflow check is only enabled on debug builds and is later disabled on release builds.

So in an attempt to find all the cases where panic would occur in my code I created a fuzzing framework specifically for hardware drivers which can be found here. This framework could find and backtrace the bug and I later found a few others in other driver code. So that's great, but I can't be 100% sure that the fuzzing engine has found all the ways that my driver could panic.

Based on the research that I've done here are all the ways that rust will panic;

  1. An explicit call to panic! (I can mitigate this with a code-review of my deps).
  2. An explicit call to unwrap (I can mitigate this with a code-review of my deps).
  3. Indexing an array out of bounds.
  4. Overflowing an integer (In debug mode only)
  5. Dividing by 0

Before finding the bug described above I was only aware of cases 1,2,4 as potential areas where rust would panic, as they were the cases that seem to be the most touted/documented features of rust.

Are there any other cases where core rust (i.e. nostd), will panic?

As a follow-up question; is there any way to be 100% sure that there is no possible code pathway that my code could ever panic e.g. via static analysis or another method?


Solution

  • There are many functions in core that panic when used improperly (random example: AtomicI64::load). All of these panics are documented in the core documentation. There are also ways that panics can occur even without an explicit function call or macro invocation in core. All of these are syntax sugar for a core trait (such as Add or Index) but are typically invoked using their syntax sugar, and are implemented with compiler magic (code generation is handled differently than normal by the compiler):

    • +/-/*/>>/<< panic on overflow in debug mode
    • dividing by zero or modulusing zero (x / 0 or x % 0)
    • for signed integer types, i*::MIN / -1 and i*::MIN % -1 always panics, even in release mode
    • for signed integer types, -i*::MIN
    • performing an out of bounds array index into a slice/array/str

    The no_panic crate can be used to statically verify that a function will never panic. There are a few catches to be aware of when using this crate — be sure to read the documentation first.