diff --git a/components/util/lib.rs b/components/util/lib.rs index 9a06ee1b725..3f9755c4306 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(feature = "non-geckolib", feature(decode_utf16))] #![feature(optin_builtin_traits)] #![feature(plugin)] +#![feature(panic_handler)] #![feature(reflect_marker)] #![feature(step_by)] diff --git a/components/util/opts.rs b/components/util/opts.rs index a5799883e14..30fc68275ae 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -198,6 +198,9 @@ pub struct Opts { // Which rendering API to use. pub render_api: RenderApi, + + // don't skip any backtraces on panic + pub full_backtraces: bool, } fn print_usage(app: &str, opts: &Options) { @@ -285,6 +288,9 @@ pub struct DebugOptions { /// Use multisample antialiasing in WebRender. pub use_msaa: bool, + // don't skip any backtraces on panic + pub full_backtraces: bool, + } @@ -319,6 +325,7 @@ impl DebugOptions { "disable-vsync" => debug_options.disable_vsync = true, "wr-stats" => debug_options.webrender_stats = true, "msaa" => debug_options.use_msaa = true, + "full-backtraces" => debug_options.full_backtraces = true, "" => {}, _ => return Err(option) }; @@ -365,6 +372,7 @@ pub fn print_debug_usage(app: &str) -> ! { "Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate"); print_option("wr-stats", "Show WebRender profiler on screen."); print_option("msaa", "Use multisample antialiasing in WebRender."); + print_option("full-backtraces", "Print full backtraces for all errors"); println!(""); @@ -506,6 +514,7 @@ pub fn default_opts() -> Opts { use_msaa: false, render_api: DEFAULT_RENDER_API, profile_dir: None, + full_backtraces: false, } } @@ -791,6 +800,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { webrender_stats: debug_options.webrender_stats, use_msaa: debug_options.use_msaa, profile_dir: opt_match.opt_str("profile-dir"), + full_backtraces: debug_options.full_backtraces, }; set_defaults(opts); diff --git a/components/util/thread.rs b/components/util/thread.rs index f17d6985867..f32e6ccd4f7 100644 --- a/components/util/thread.rs +++ b/components/util/thread.rs @@ -3,8 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use ipc_channel::ipc::IpcSender; +use opts; use serde::Serialize; use std::borrow::ToOwned; +use std::io::{Write, stderr}; +use std::panic::{PanicInfo, take_handler, set_handler}; use std::sync::mpsc::Sender; use std::thread; use std::thread::Builder; @@ -14,7 +17,39 @@ pub fn spawn_named(name: String, f: F) where F: FnOnce() + Send + 'static { let builder = thread::Builder::new().name(name); - builder.spawn(f).unwrap(); + + if opts::get().full_backtraces { + builder.spawn(f).unwrap(); + return; + } + + let f_with_handler = move || { + let hook = take_handler(); + + let new_handler = move |info: &PanicInfo| { + let payload = info.payload(); + if let Some(s) = payload.downcast_ref::() { + if s.contains("SendError") { + let err = stderr(); + let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \ + `SendError` (backtrace skipped)\n", + thread::current().name().unwrap_or("")); + return; + } else if s.contains("RecvError") { + let err = stderr(); + let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \ + `RecvError` (backtrace skipped)\n", + thread::current().name().unwrap_or("")); + return; + } + } + hook(&info); + }; + set_handler(new_handler); + f(); + }; + + builder.spawn(f_with_handler).unwrap(); } /// An abstraction over `Sender` and `IpcSender`, for use in