diff --git a/Cargo.toml b/Cargo.toml index 439ed720b7835de6cef38536bf1bb861a0b244fd..04743c56ead5d28bca0202bc7d5a539f700967b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ sctk-adwaita = { path = "vendor/sctk-adwaita" } [profile.release] lto = "fat" codegen-units = 1 +panic = "abort" # Code that runs at a person's pace, not a frame's: system services, the network, file and # image formats, shader translation. diff --git a/crates/snowbound/src/windows.rs b/crates/snowbound/src/windows.rs index f7621be1cec1c12a1b265a99b00d0a1be52a5441..a9e8f24c192d798a9cd66b948835e08d4c9df12a 100644 --- a/crates/snowbound/src/windows.rs +++ b/crates/snowbound/src/windows.rs @@ -935,42 +935,44 @@ pub fn cover_border_line(_: &mut Ui, _: f32) {} pub fn with_pool( run: impl FnOnce() -> Result<(), Box>, ) -> Result<(), Box> { - use std::panic; - let log = log_stderr(); + let details = log_stderr().map(|log| format!("The log is at {}.", log.display())); let (major, minor, build) = version(); eprintln!( "Snowbound {} on Windows {major}.{minor}.{build}", option_env!("SNOWBOUND_BUILD").unwrap_or("development") ); - panic::set_hook(Box::new(|info| { + let shown = details.clone(); + std::panic::set_hook(Box::new(move |info| { let thread = std::thread::current(); let backtrace = std::backtrace::Backtrace::force_capture(); eprintln!( "Thread {:?} {info}\n{backtrace}", thread.name().unwrap_or("") ); + // The panic aborts the process once this returns, taking an alert's thread with it. + if cfg!(panic = "abort") + && let Some(details) = &shown + { + let text = wide(format!( + "Snowbound stopped because of a problem.\n\n{details}" + )); + let caption = wide("Snowbound"); + let style = wm::MB_OK | wm::MB_ICONWARNING; + unsafe { + wm::MessageBoxW(std::ptr::null_mut(), text.as_ptr(), caption.as_ptr(), style) + }; + } })); unsafe { windows_sys::Win32::System::Diagnostics::Debug::AddVectoredExceptionHandler(0, Some(fault)) }; - let result = panic::catch_unwind(panic::AssertUnwindSafe(run)); - let Some(log) = log else { - return result.unwrap_or_else(|payload| panic::resume_unwind(payload)); - }; - let details = format!("The log is at {}.", log.display()); - // The window is gone, and a message box it owned wouldn't show. - WINDOW.store(0, Ordering::Relaxed); - match result { - Ok(Err(error)) => { - alert(&error.to_string(), &details); - Err(error) - } - Ok(done) => done, - Err(payload) => { - alert("Snowbound stopped because of a problem.", &details); - panic::resume_unwind(payload) - } + let result = run(); + if let (Err(error), Some(details)) = (&result, details) { + // The window is gone, and a message box it owned wouldn't show. + WINDOW.store(0, Ordering::Relaxed); + alert(&error.to_string(), &details); } + result } /// Points stderr at `snowbound.log` in the cache folder where it goes nowhere, keeping the diff --git a/platform/windows/cargo.sh b/platform/windows/cargo.sh index 2fdba63a8771864033b8ec4bb4dd88718a07281b..19d16f48a67d82fbe157eeaa9a0d8ad2dbe5663e 100755 --- a/platform/windows/cargo.sh +++ b/platform/windows/cargo.sh @@ -22,7 +22,7 @@ x86_64) # raw-dylib imports (the windows crates) are made by llvm-mingw's dlltool. Cargo # can't see link.sh's inputs; folding their hash into the flags relinks on change. runtime=$(cat "$here/link.sh" "$here"/rt/* | shasum | cut -c1-12) - set -- -Zbuild-std=std,panic_unwind \ + set -- -Zbuild-std=std,panic_abort,panic_unwind \ --config "target.$target.linker='$here/link.sh'" \ --config "target.$target.rustflags=['-C','linker-flavor=gcc','-C','metadata=rt-$runtime','-C','dlltool=$LLVM_MINGW/bin/x86_64-w64-mingw32-dlltool']" "$@" ;;