1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::io::Write;
use std::panic::PanicInfo;
use std::{env, thread};

use log::{error, warn};
use servo::config::opts;

use crate::crash_handler::raise_signal_or_exit_with_error;

pub(crate) fn panic_hook(info: &PanicInfo) {
    warn!("Panic hook called.");
    let msg = match info.payload().downcast_ref::<&'static str>() {
        Some(s) => *s,
        None => match info.payload().downcast_ref::<String>() {
            Some(s) => &**s,
            None => "Box<Any>",
        },
    };
    let current_thread = thread::current();
    let name = current_thread.name().unwrap_or("<unnamed>");
    let stderr = std::io::stderr();
    let mut stderr = stderr.lock();
    if let Some(location) = info.location() {
        let _ = writeln!(
            &mut stderr,
            "{} (thread {}, at {}:{})",
            msg,
            name,
            location.file(),
            location.line()
        );
    } else {
        let _ = writeln!(&mut stderr, "{} (thread {})", msg, name);
    }
    if env::var("RUST_BACKTRACE").is_ok() {
        let _ = crate::backtrace::print(&mut stderr);
    }
    drop(stderr);

    if opts::get().hard_fail && !opts::get().multiprocess {
        // When we are exiting due to a hard-failure mode, we trigger a segfault so that crash
        // tests detect that we crashed. If we exit normally it just looks like a non-crash exit.
        raise_signal_or_exit_with_error(libc::SIGSEGV);
    }

    error!("{}", msg);
}