Skip to content

Commit

Permalink
Make set_panic_hook into a safe fn
Browse files Browse the repository at this point in the history
  • Loading branch information
FenrirWolf committed Feb 25, 2024
1 parent 17dc4c4 commit 94c5691
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
49 changes: 34 additions & 15 deletions ctru-rs/src/applets/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,31 +91,50 @@ impl PopUp {
/// Sets a custom panic hook that uses the error applet to display panic messages. You can also choose to have
/// messages printed over stderr along with the pop-up display.
///
/// # Safety
///
/// The error applet requires that both the [`Apt`] and [`Gfx`] services are active whenever it launches.
/// By calling this function, you promise that you will keep those services alive until either the program ends or
/// you unregister this hook with [`std::panic::take_hook`](https://doc.rust-lang.org/std/panic/fn.take_hook.html).
pub unsafe fn set_panic_hook(use_stderr: bool) {
/// If the `Gfx` service is not initialized during a panic, the error applet will not be displayed and the panic
/// message will be printed over stderr.
pub fn set_panic_hook(use_stderr: bool) {
use crate::services::gfx::GFX_ACTIVE;

use std::io::Write;
use std::sync::TryLockError;

std::panic::set_hook(Box::new(move |panic_info| {
let mut popup = PopUp::new(Kind::Top);
let _apt = Apt::new();

let thread = std::thread::current();

let name = thread.name().unwrap_or("<unnamed>");

let payload = format!("thread '{name}' {panic_info}");
// If we get a `WouldBlock` error, we know that the `Gfx` service has been initialized.
// Otherwise fallback to printing over stderr.
match GFX_ACTIVE.try_lock() {
Err(TryLockError::WouldBlock) => {
if use_stderr {
print_to_stderr(&name, &panic_info);

Check warning on line 114 in ctru-rs/src/applets/error.rs

View workflow job for this annotation

GitHub Actions / lint (nightly-2024-02-18)

this expression creates a reference which is immediately dereferenced by the compiler

Check warning on line 114 in ctru-rs/src/applets/error.rs

View workflow job for this annotation

GitHub Actions / lint (nightly-2024-02-18)

this expression creates a reference which is immediately dereferenced by the compiler
}

popup.set_text(&payload);
let payload = format!("thread '{name}' {panic_info}");

if use_stderr {
eprintln!("{payload}");
}
let mut popup = PopUp::new(Kind::Top);

unsafe {
popup.launch_unchecked();
popup.set_text(&payload);

unsafe {
popup.launch_unchecked();
}
}
_ => {
print_to_stderr(&name, &panic_info);

Check warning on line 128 in ctru-rs/src/applets/error.rs

View workflow job for this annotation

GitHub Actions / lint (nightly-2024-02-18)

this expression creates a reference which is immediately dereferenced by the compiler

Check warning on line 128 in ctru-rs/src/applets/error.rs

View workflow job for this annotation

GitHub Actions / lint (nightly-2024-02-18)

this expression creates a reference which is immediately dereferenced by the compiler
}
}
}))
}));

fn print_to_stderr(name: &str, panic_info: &std::panic::PanicInfo) {
let mut stderr = std::io::stderr().lock();

let _ = writeln!(stderr, "thread '{name}' {panic_info}");
}
}

impl std::fmt::Display for Error {
Expand Down
2 changes: 1 addition & 1 deletion ctru-rs/src/services/gfx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ pub struct Gfx {
_service_handler: ServiceReference,
}

static GFX_ACTIVE: Mutex<()> = Mutex::new(());
pub(crate) static GFX_ACTIVE: Mutex<()> = Mutex::new(());

impl Gfx {
/// Initialize a new default service handle.
Expand Down

0 comments on commit 94c5691

Please sign in to comment.