Skip to content

Should have a story for debugging panics #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fitzgen opened this issue Feb 14, 2018 · 2 comments
Closed

Should have a story for debugging panics #54

fitzgen opened this issue Feb 14, 2018 · 2 comments

Comments

@fitzgen
Copy link
Member

fitzgen commented Feb 14, 2018

Right now, it translates to a RuntimeError being raised in the JS host, that stringifies to "RuntimeError: unreachable executed". This is not helpful. Even if you are using a browser's debugger, at best you'll get the name of the function that panicked and the line in the WAT. The WAT isn't very readable, at least to me.

When we have something like https://github.com/rust-lang-nursery/rust-wasm/issues/16#issuecomment-363956170, the default panic handler could use this functionality to essentially do a console.error log.

@alexcrichton
Copy link
Contributor

One thing which I've found helpful is to define a local macro:

macro_rules! panic {
    () => (panic!("explicit panic"));
    ($msg:expr) => (
        _panic1(&($msg, file!(), line!()))
    );
    ($fmt:expr, $($arg:tt)*) => (
        _panic2(&format_args!($fmt, $($arg)*), &(file!(), line!()))
    );
}

#[cold]
#[inline(never)]
pub fn _panic1(&(msg, file, line): &(&'static str, &'static str, u32)) -> ! {
    debug_println!("rust panicked at: {}: {}:{}", msg, file, line);
    abort()
}

#[cold]
#[inline(never)]
pub fn _panic2(args: &fmt::Arguments, &(file, line): &(&str, u32)) -> ! {
    debug_println!("rust panicked at: {}: {}:{}", args, file, line);
    abort()
}

macro_rules! debug_println {
    ($($t:tt)*) => (_println(&format_args!($($t)*)))
}

#[wasm_bindgen]
extern {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

pub fn _println(a: &fmt::Arguments) {
    if !cfg!(debug_assertions) {
        return
    }

    let s = a.to_string();
    log(&s);
}

pub fn abort() -> ! {
    wasm_bindgen::throw("rust had to abort")
}

This will shadow the panic! macro in the standard library and allow you to use panic! freely throughout your crate. In release mode everything will optimize away and no strings will be emitted, but in debug mode you'll see why something is panicking (including filename/line number) on the console. By shadowing panic! you're able to also reuse standard macros like assert! and they'll use this implementation of panic.

The downside of this approach is that it doesn't handle panics originating in foreign libraries, for example unwrap() which panics inside the standard library. That'll definitely require a more intrusive and heavyweight solution.

@fitzgen
Copy link
Member Author

fitzgen commented Jun 6, 2018

We have https://github.com/rustwasm/console_error_panic_hook now, which works A+++ (as long as you install the hook) so I think we can close this now.

@fitzgen fitzgen closed this as completed Jun 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants