desktop: Implement crash report dialog when a panic happens

This commit is contained in:
Nathan Adams 2023-01-18 20:04:54 +01:00
parent 0fd618e80a
commit ea37d0a3ad
4 changed files with 118 additions and 2 deletions

50
.github/ISSUE_TEMPLATE/crash_report.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: "\U0001f4A5 Crash report"
description: File a crash report.
labels: ["bug", "panic", "desktop"]
body:
- type: markdown
attributes:
value: |
- If you have a question about Ruffle, you can ask for help on our [Discord chat][chat].
- Also consult the [Frequently Asked Questions][faq] for common issues and questions.
- Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean.
- Also make sure that you are using the [latest available version of Ruffle][version].
- Otherwise, fill out the information below to the best of your ability. Thank you!
[chat]: https://discord.gg/ruffle
[faq]: https://github.com/ruffle-rs/ruffle/wiki/Frequently-Asked-Questions-For-Users
[version]: https://github.com/ruffle-rs/ruffle/tags
- type: textarea
attributes:
label: Describe what you were doing
description: |
Provide a clear and concise description of what you were doing when you encountered the crash.
- If there are steps to reproduce, list them here.
- If this is an issue with a specific SWF file, please provide a link to the SWF file, or you can attach the SWF by zipping it and dragging it onto the issue box.
validations:
required: true
- type: textarea
id: panic_text
attributes:
label: What does the crash message say?
validations:
required: true
- type: markdown
attributes:
value: |
# Device information
- type: input
id: operating_system
attributes:
label: Operating system
description: Please list the OS you are using.
placeholder: Windows 10, macOS Catalina, Android 11, iOS 14, etc.
validations:
required: true
- type: textarea
id: extra_info
attributes:
label: Additional information
description: If you have any additional information for us, such as device logs or renderer info, use the field below.
validations:
required: false

12
Cargo.lock generated
View File

@ -2999,6 +2999,16 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "os_info"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4750134fb6a5d49afc80777394ad5d95b04bc12068c6abb92fae8f43817270f"
dependencies = [
"log",
"winapi",
]
[[package]]
name = "os_str_bytes"
version = "6.4.1"
@ -3534,8 +3544,10 @@ dependencies = [
"embed-resource",
"generational-arena",
"isahc",
"os_info",
"rfd",
"ruffle_core",
"ruffle_render",
"ruffle_render_wgpu",
"ruffle_video_software",
"tracing",

View File

@ -11,6 +11,7 @@ version.workspace = true
clap = { version = "4.0.32", features = ["derive"] }
cpal = "0.14.2"
ruffle_core = { path = "../core", features = ["audio", "mp3", "nellymoser"] }
ruffle_render = { path = "../render" }
ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] }
ruffle_video_software = { path = "../video/software", optional = true }
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
@ -25,6 +26,7 @@ isahc = "1.7.2"
rfd = "0.10.0"
anyhow = "1.0"
bytemuck = "1.12.3"
os_info = { version = "3", default-features = false }
# Deliberately held back to match tracy client used by profiling crate
tracing-tracy = { version = "=0.10.0", optional = true }

View File

@ -24,10 +24,12 @@ use ruffle_core::{
config::Letterbox, events::KeyCode, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder,
PlayerEvent, StageDisplayState, StaticCallstack, ViewportDimensions,
};
use ruffle_render::backend::RenderBackend;
use ruffle_render_wgpu::backend::WgpuRenderBackend;
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
use std::cell::RefCell;
use std::io::Read;
use std::panic::PanicInfo;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
@ -43,6 +45,8 @@ use winit::window::{Fullscreen, Icon, Window, WindowBuilder};
thread_local! {
static CALLSTACK: RefCell<Option<StaticCallstack>> = RefCell::default();
static RENDER_INFO: RefCell<Option<String>> = RefCell::default();
static SWF_INFO: RefCell<Option<String>> = RefCell::default();
}
#[cfg(feature = "tracy")]
@ -232,6 +236,7 @@ impl App {
.and_then(|segments| segments.last())
.unwrap_or_else(|| movie_url.as_str());
let title = format!("Ruffle - {filename}");
SWF_INFO.with(|i| *i.borrow_mut() = Some(filename.to_string()));
let window = WindowBuilder::new()
.with_visible(false)
@ -268,6 +273,7 @@ impl App {
)
.map_err(|e| anyhow!(e.to_string()))
.context("Couldn't create wgpu rendering backend")?;
RENDER_INFO.with(|i| *i.borrow_mut() = Some(renderer.debug_info().to_string()));
let window = Rc::new(window);
@ -853,7 +859,7 @@ fn init() {
let prev_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
prev_hook(info);
panic_hook();
panic_hook(info);
}));
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
@ -868,12 +874,58 @@ fn init() {
tracing::subscriber::set_global_default(subscriber).expect("Couldn't set up global subscriber");
}
fn panic_hook() {
fn panic_hook(info: &PanicInfo) {
CALLSTACK.with(|callstack| {
if let Some(callstack) = &*callstack.borrow() {
callstack.avm2(|callstack| println!("AVM2 stack trace: {callstack}"))
}
});
// [NA] Let me just point out that PanicInfo::message() exists but isn't stable and that sucks.
let panic_text = info.to_string();
let message = if let Some(text) = panic_text.strip_prefix("panicked at '") {
let location = info.location().map(|l| l.to_string()).unwrap_or_default();
if let Some(text) = text.strip_suffix(&format!("', {location}")) {
text.trim()
} else {
text.trim()
}
} else {
panic_text.trim()
};
if rfd::MessageDialog::new()
.set_level(rfd::MessageLevel::Error)
.set_title("Ruffle")
.set_description(&format!(
"Ruffle has encountered a fatal error, this is a bug.\n\n\
{message}\n\n\
Please report this to us so that we can fix it. Thank you!\n\
Pressing Yes will open a browser window."
))
.set_buttons(rfd::MessageButtons::YesNo)
.show()
{
let mut params = vec![];
params.push(("panic_text", info.to_string()));
params.push(("operating_system", os_info::get().to_string()));
let mut extra_info = vec![];
RENDER_INFO.with(|i| {
if let Some(render_info) = i.take() {
extra_info.push(render_info);
}
});
SWF_INFO.with(|i| {
if let Some(swf_name) = i.take() {
extra_info.push(format!("SWF: {swf_name}"));
}
});
if !extra_info.is_empty() {
params.push(("extra_info", extra_info.join("\n")));
}
if let Ok(url) = Url::parse_with_params("https://github.com/ruffle-rs/ruffle/issues/new?assignees=&labels=bug&template=crash_report.yml", &params) {
let _ = webbrowser::open(url.as_str());
}
}
}
fn shutdown() {