From 13c72ed4b7cc1a516f60b571084d4151b0f605f6 Mon Sep 17 00:00:00 2001 From: sonodima Date: Thu, 3 Oct 2024 20:10:09 +0200 Subject: [PATCH 1/3] updated try_seh to return values returned by the handled closure --- src/lib.rs | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8ef0a81..b6d5f00 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -use core::ffi::c_void; +use core::{ffi::c_void, mem::MaybeUninit}; mod code; mod exception; @@ -40,6 +40,22 @@ where } } +fn do_execute_proc(mut closure: F) -> Result<(), Exception> +where + F: FnMut(), +{ + let mut exception = Exception::empty(); + let closure = &mut closure as *mut _ as *mut c_void; + + unsafe { + match handler_stub(handled_proc::, closure, &mut exception) { + MS_CATCHED => Err(exception), + MS_DISABLED => panic!("exception handling is not supported in this build of microseh"), + /* MS_SUCCEEDED */ _ => Ok(()), + } + } +} + /// Executes the provided closure in a context where exceptions are handled, catching any\ /// hardware exceptions that occur. /// @@ -77,22 +93,16 @@ where /// /// If exception handling is disabled in the build, which occurs when the library is\ /// not built on Windows with Microsoft Visual C++. -pub fn try_seh(mut closure: F) -> Result<(), Exception> +pub fn try_seh(mut closure: F) -> Result where - F: FnMut(), + F: FnMut() -> R, { - let mut exception = Exception::empty(); - let closure = &mut closure as *mut _ as *mut c_void; - - unsafe { - match handler_stub(handled_proc::, closure, &mut exception) { - MS_CATCHED => Err(exception), - MS_DISABLED => panic!("exception handling is not supported in this build of microseh"), - /* MS_SUCCEEDED */ _ => Ok(()), - } - } + let mut ret_val = MaybeUninit::::uninit(); + do_execute_proc(|| { ret_val.write(closure()); }) + .map(|_| unsafe { ret_val.assume_init() }) } + #[cfg(test)] mod tests { use super::*; @@ -230,4 +240,16 @@ mod tests { assert_eq!(ex.unwrap_err().registers().x0(), 0xbadc0debabefffff); } + + #[test] + fn ret_vals() { + let a = try_seh(|| { 1337 }); + assert_eq!(a.unwrap(), 1337); + + let b = try_seh(|| { "hello" }); + assert_eq!(b.unwrap(), "hello"); + + let c = try_seh(|| { }); + assert_eq!(core::mem::size_of_val(&c.unwrap()), 0x0); + } } From 8ebb1a05d277a7b8ad2ddd4d8343250cdcbce8a8 Mon Sep 17 00:00:00 2001 From: sonodima Date: Thu, 3 Oct 2024 20:13:23 +0200 Subject: [PATCH 2/3] updated try_seh documentation --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b6d5f00..7fb1034 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,8 @@ where /// Executes the provided closure in a context where exceptions are handled, catching any\ /// hardware exceptions that occur. +/// +/// Any value returned by the closure is returned by this function, if no exceptions occur. /// /// # Arguments /// @@ -65,7 +67,7 @@ where /// /// # Returns /// -/// * `Ok(())` - If the closure executed without throwing any exceptions. +/// * `Ok(R)` - If the closure executed without throwing any exceptions. /// * `Err(Exception)` - If an exception occurred during the execution of the closure. /// /// # Examples @@ -83,7 +85,7 @@ where /// # Caveats /// /// If an exception occours within the closure, resources that require cleanup via\ -/// the `Drop` trait, may not be properly released. +/// the `Drop` trait, will not be released. /// /// As a rule of thumb, it's recommended not to define resources that implement\ /// the `Drop` trait inside the closure. Instead, allocate and manage these resources\ From f467cbda87e7a95acfaf264de10a0a99110f7e91 Mon Sep 17 00:00:00 2001 From: sonodima Date: Thu, 3 Oct 2024 20:17:12 +0200 Subject: [PATCH 3/3] added ret_val safety info --- src/lib.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7fb1034..dc73fac 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,7 @@ where /// Executes the provided closure in a context where exceptions are handled, catching any\ /// hardware exceptions that occur. -/// +/// /// Any value returned by the closure is returned by this function, if no exceptions occur. /// /// # Arguments @@ -100,11 +100,14 @@ where F: FnMut() -> R, { let mut ret_val = MaybeUninit::::uninit(); - do_execute_proc(|| { ret_val.write(closure()); }) - .map(|_| unsafe { ret_val.assume_init() }) + do_execute_proc(|| { + ret_val.write(closure()); + }) + // SAFETY: We should only reach this point if the inner closure has returned + // without throwing an exception, so `ret_val` should be initialized. + .map(|_| unsafe { ret_val.assume_init() }) } - #[cfg(test)] mod tests { use super::*; @@ -245,13 +248,13 @@ mod tests { #[test] fn ret_vals() { - let a = try_seh(|| { 1337 }); + let a = try_seh(|| 1337); assert_eq!(a.unwrap(), 1337); - let b = try_seh(|| { "hello" }); + let b = try_seh(|| "hello"); assert_eq!(b.unwrap(), "hello"); - let c = try_seh(|| { }); + let c = try_seh(|| {}); assert_eq!(core::mem::size_of_val(&c.unwrap()), 0x0); } }