From 84ef934223531c673721c1003d0656d395f32012 Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Mon, 10 Jan 2022 16:43:11 -0800 Subject: [PATCH 1/4] Add back slightly simpler Console::drop This is needed for soundness. Otherwise libctru will have a dangling pointer, and will write to it when printing. --- ctru-rs/src/console.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index e640109..21d2c66 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -50,3 +50,22 @@ impl Default for Console { Console::init(Screen::Top) } } + +impl Drop for Console { + fn drop(&mut self) { + unsafe { + // Get the current console by replacing it with the default. + let default_console = ctru_sys::consoleGetDefault(); + let current_console = ctru_sys::consoleSelect(default_console); + + if std::ptr::eq(current_console, &*self.context) { + // Console dropped while selected. We just replaced it with the + // default so there's nothing more to do. + } else { + // Console dropped while a different console was selected. Put back + // the console that was selected. + ctru_sys::consoleSelect(current_console); + } + } + } +} From 12ae54c6059b7ce0d8d89510af45794f62760dfd Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Mon, 10 Jan 2022 16:46:52 -0800 Subject: [PATCH 2/4] Add some more explanation to Console::drop --- ctru-rs/src/console.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index 21d2c66..1a226b7 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -54,6 +54,11 @@ impl Default for Console { impl Drop for Console { fn drop(&mut self) { unsafe { + // Safety: We are about to deallocate the PrintConsole data pointed + // to by libctru. Without this drop code libctru would have a + // dangling pointer that it writes to on every print. To prevent + // this we replace the console with the default if it was selected. + // Get the current console by replacing it with the default. let default_console = ctru_sys::consoleGetDefault(); let current_console = ctru_sys::consoleSelect(default_console); From 9a45f575c892b2fe56d4cbd0b2d25ab0dd303d6e Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Tue, 11 Jan 2022 17:19:11 -0800 Subject: [PATCH 3/4] Add back initialization of default console in Console::drop If the default console isn't initialized then it will segfault. --- ctru-rs/src/console.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index 1a226b7..5c0b92a 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -65,7 +65,10 @@ impl Drop for Console { if std::ptr::eq(current_console, &*self.context) { // Console dropped while selected. We just replaced it with the - // default so there's nothing more to do. + // default so make sure it's initialized. + if !(*default_console).consoleInitialised { + ctru_sys::consoleInit(Screen::Top.into(), default_console); + } } else { // Console dropped while a different console was selected. Put back // the console that was selected. From c3ae3a1abc14b2d54eb800a8337e20e90dbb92c5 Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Tue, 11 Jan 2022 17:57:48 -0800 Subject: [PATCH 4/4] Select an empty console when dropping the selected console --- ctru-rs/Cargo.toml | 1 + ctru-rs/src/console.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index e841bf6..f33e177 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -12,6 +12,7 @@ name = "ctru" [dependencies] ctru-sys = { path = "../ctru-sys", version = "0.4" } +const-zero = "0.1.0" linker-fix-3ds = { git = "https://github.com/Meziu/rust-linker-fix-3ds.git" } pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" } libc = { git = "https://github.com/Meziu/libc.git" } diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index 5c0b92a..d7ab478 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -53,22 +53,23 @@ impl Default for Console { impl Drop for Console { fn drop(&mut self) { + static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; + unsafe { // Safety: We are about to deallocate the PrintConsole data pointed // to by libctru. Without this drop code libctru would have a // dangling pointer that it writes to on every print. To prevent - // this we replace the console with the default if it was selected. + // this we replace the console with an empty one if it was selected. + // This is the same state that libctru starts up in, before + // initializing a console. Writes to the console will not show up on + // the screen, but it won't crash either. - // Get the current console by replacing it with the default. - let default_console = ctru_sys::consoleGetDefault(); - let current_console = ctru_sys::consoleSelect(default_console); + // Get the current console by replacing it with an empty one. + let current_console = ctru_sys::consoleSelect(&mut EMPTY_CONSOLE); if std::ptr::eq(current_console, &*self.context) { // Console dropped while selected. We just replaced it with the - // default so make sure it's initialized. - if !(*default_console).consoleInitialised { - ctru_sys::consoleInit(Screen::Top.into(), default_console); - } + // empty console so nothing more to do. } else { // Console dropped while a different console was selected. Put back // the console that was selected.