Skip to content

Commit

Permalink
Make calling throw no longer UB by using "C-unwind"
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jan 3, 2022
1 parent 9144d59 commit 9bfb693
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 7 deletions.
3 changes: 3 additions & 0 deletions objc2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ malloc = ["malloc_buf"]
# Uses nightly features to make AutoreleasePool zero-cost even in debug mode
unstable_autoreleasesafe = []

# Uses the c_unwind feature to make throwing safe. Nightly only
unstable_c_unwind = []

[dependencies]
malloc_buf = { version = "1.0", optional = true }
objc-sys = { path = "../objc-sys", version = "=0.2.0-alpha.0" }
Expand Down
46 changes: 39 additions & 7 deletions objc2/src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ use crate::rc::{Id, Shared};
use crate::runtime::Object;

extern "C" {
#[cfg(not(feature = "unstable_c_unwind"))]
fn rust_objc_try_catch_exception(
f: extern "C" fn(*mut c_void),
context: *mut c_void,
error: *mut *mut ffi::objc_object,
) -> c_uchar;

#[cfg(feature = "unstable_c_unwind")]
fn rust_objc_try_catch_exception(
f: extern "C-unwind" fn(*mut c_void),
context: *mut c_void,
error: *mut *mut objc_object,
) -> c_uchar;
}

/// Throws an Objective-C exception.
Expand Down Expand Up @@ -57,14 +65,38 @@ pub unsafe fn throw(exception: Option<&Id<Object, Shared>>) -> ! {
}

unsafe fn try_no_ret<F: FnOnce()>(closure: F) -> Result<(), Option<Id<Object, Shared>>> {
extern "C" fn try_objc_execute_closure<F: FnOnce()>(closure: &mut Option<F>) {
// This is always passed Some, so it's safe to unwrap
let closure = closure.take().unwrap();
closure();
}
#[cfg(not(feature = "unstable_c_unwind"))]
let f = {
extern "C" fn try_objc_execute_closure<F>(closure: &mut Option<F>)
where
F: FnOnce(),
{
// This is always passed Some, so it's safe to unwrap
let closure = closure.take().unwrap();
closure();
}

let f: extern "C" fn(&mut Option<F>) = try_objc_execute_closure;
let f: extern "C" fn(*mut c_void) = unsafe { mem::transmute(f) };
f
};

#[cfg(feature = "unstable_c_unwind")]
let f = {
extern "C-unwind" fn try_objc_execute_closure<F>(closure: &mut Option<F>)
where
F: FnOnce(),
{
// This is always passed Some, so it's safe to unwrap
let closure = closure.take().unwrap();
closure();
}

let f: extern "C-unwind" fn(&mut Option<F>) = try_objc_execute_closure;
let f: extern "C-unwind" fn(*mut c_void) = unsafe { mem::transmute(f) };
f
};

let f: extern "C" fn(&mut Option<F>) = try_objc_execute_closure;
let f: extern "C" fn(*mut c_void) = unsafe { mem::transmute(f) };
// Wrap the closure in an Option so it can be taken
let mut closure = Some(closure);
let context = &mut closure as *mut _ as *mut c_void;
Expand Down
1 change: 1 addition & 0 deletions objc2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
feature = "unstable_autoreleasesafe",
feature(negative_impls, auto_traits)
)]
#![cfg_attr(feature = "unstable_c_unwind", feature(c_unwind))]
#![warn(elided_lifetimes_in_paths)]
#![warn(missing_docs)]
#![deny(non_ascii_idents)]
Expand Down

0 comments on commit 9bfb693

Please sign in to comment.