Rust: Panic within a panic causes illegal instruction SIGILL

Created on 30 Aug 2018  路  2Comments  路  Source: rust-lang/rust

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. :laughing:

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 on cargo 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());
}

Most helpful comment

The real MVP @mgattozzi realized what the problem was in a second. The display impl panics within the panic in the test and that's what causes the problem. Here's an even more minimal reproduction:

use std::fmt;

pub struct Foo;

impl fmt::Display for Foo {
    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
        panic!()
    }
}

#[test]
fn something() {
    panic!("{}", Foo);
}
thread panicked while panicking. aborting.
error: process didn't exit successfully: `/playground/target/debug/deps/playground-b71130afded4f9e4` (signal: 4, SIGILL: illegal instruction)

I guess you could say I did a good job writing this issue given that someone was able to take a cursory look at it and figure out so much. Sorry I didn't catch it myself! :laughing:

All 2 comments

The real MVP @mgattozzi realized what the problem was in a second. The display impl panics within the panic in the test and that's what causes the problem. Here's an even more minimal reproduction:

use std::fmt;

pub struct Foo;

impl fmt::Display for Foo {
    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
        panic!()
    }
}

#[test]
fn something() {
    panic!("{}", Foo);
}
thread panicked while panicking. aborting.
error: process didn't exit successfully: `/playground/target/debug/deps/playground-b71130afded4f9e4` (signal: 4, SIGILL: illegal instruction)

I guess you could say I did a good job writing this issue given that someone was able to take a cursory look at it and figure out so much. Sorry I didn't catch it myself! :laughing:

I'm going to close this issue because I think this is expected behaviour.

I totally misunderstood the bug and thought it was happening during compilation. Sorry about that folks! :fearful:

Looks like it's time for me to go to bed. :sleeping:

Was this page helpful?
0 / 5 - 0 ratings