Description
See first comment for an even smaller example of the issue. Thanks @mgattozzi for the insight that led to that!
I was integrating NonZeroU8
into some code when I ran into an illegal instruction error that looks like this:
thread panicked while panicking. aborting.
error: process didn't exit successfully: `/path/to/my/project/target/debug/deps/xxxx-b71130afded4f9e4` (signal: 4, SIGILL: illegal instruction)
I spent a really long time trying to narrow this down and I got down to the following contrived example: (Rust Playground)
use std::{
fmt,
num::NonZeroU8,
};
pub struct Foo;
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", NonZeroU8::new(0).unwrap())
}
}
#[test]
fn something() {
panic!("{}", Foo);
}
This probably looks like super weird code that no one would ever write, but this started from some real code I promise. 😆
The key part of this code is:
NonZeroU8::new(0).unwrap()
The illegal instruction error occurs whenever that 0
is any value less than or equal to zero. You may be asking yourself "How do you make a u8 literal less than zero?" Well you don't. Rust protects you from that. The thing that Rust doesn't protect you from is this: (Rust Playground)
let y = 3;
let x = 2 - y;
write!(f, "{}", NonZeroU8::new(x).unwrap())
The variable x
will be -1
and the code will produce the same illegal instruction error.
Some weird things to note about this:
- It seems to work when run with
cargo run
. The failure is oncargo test
. - I haven't figured out how to recreate this without the impl of
Display
. Inlining does NOT produce the error:
// No illegal instructions for this code!
use std::num::NonZeroU8;
#[test]
fn something() {
panic!("{}", NonZeroU8::new(0).unwrap());
}