capi: better clarify story around panic safety

- catches panics for all functions now except frame for performance reasons
This commit is contained in:
chyyran 2023-04-23 02:01:31 -04:00
parent 70aa4091e0
commit 3a5c477442
5 changed files with 126 additions and 32 deletions

View file

@ -1,6 +1,31 @@
macro_rules! ffi_body { macro_rules! ffi_body {
(nopanic $body:block) => {
{
let result: Result<(), $crate::error::LibrashaderError> = try {
$body
};
let Err(e) = result else {
return $crate::error::LibrashaderError::ok()
};
e.export()
}
};
($body:block) => { ($body:block) => {
{ {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
$crate::ffi::ffi_body!(nopanic $body)
}));
result.unwrap_or_else(|e| $crate::error::LibrashaderError::UnknownError(e).export())
}
};
(nopanic |$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => {
{
$($crate::error::assert_non_null!($ref_capture);)*
$(let $ref_capture = unsafe { &*$ref_capture };)*
$($crate::error::assert_non_null!($mut_capture);)*
$(let $mut_capture = unsafe { &mut *$mut_capture };)*
let result: Result<(), $crate::error::LibrashaderError> = try { let result: Result<(), $crate::error::LibrashaderError> = try {
$body $body
}; };
@ -13,8 +38,15 @@ macro_rules! ffi_body {
}; };
(|$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => { (|$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => {
{ {
$($crate::error::assert_non_null!($ref_capture);)* let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
$(let $ref_capture = unsafe { &*$ref_capture };)* $crate::ffi::ffi_body!(nopanic |$($ref_capture),*|; mut |$($mut_capture),*| $body)
}));
result.unwrap_or_else(|e| $crate::error::LibrashaderError::UnknownError(e).export())
}
};
(nopanic mut |$($mut_capture:ident),*| $body:block) => {
{
$($crate::error::assert_non_null!($mut_capture);)* $($crate::error::assert_non_null!($mut_capture);)*
$(let $mut_capture = unsafe { &mut *$mut_capture };)* $(let $mut_capture = unsafe { &mut *$mut_capture };)*
let result: Result<(), $crate::error::LibrashaderError> = try { let result: Result<(), $crate::error::LibrashaderError> = try {
@ -29,19 +61,14 @@ macro_rules! ffi_body {
}; };
(mut |$($mut_capture:ident),*| $body:block) => { (mut |$($mut_capture:ident),*| $body:block) => {
{ {
$($crate::error::assert_non_null!($mut_capture);)* let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
$(let $mut_capture = unsafe { &mut *$mut_capture };)* $crate::ffi::ffi_body!(nopanic mut |$($mut_capture),*| $body)
let result: Result<(), $crate::error::LibrashaderError> = try { }));
$body
};
let Err(e) = result else { result.unwrap_or_else(|e| $crate::error::LibrashaderError::UnknownError(e).export())
return $crate::error::LibrashaderError::ok()
};
e.export()
} }
}; };
(|$($ref_capture:ident),*| $body:block) => { (nopanic |$($ref_capture:ident),*| $body:block) => {
{ {
$($crate::error::assert_non_null!($ref_capture);)* $($crate::error::assert_non_null!($ref_capture);)*
$(let $ref_capture = unsafe { &*$ref_capture };)* $(let $ref_capture = unsafe { &*$ref_capture };)*
@ -54,24 +81,20 @@ macro_rules! ffi_body {
}; };
e.export() e.export()
} }
};
(|$($ref_capture:ident),*| $body:block) => {
{
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
$crate::ffi::ffi_body!(nopanic |$($ref_capture),*| $body)
}));
result.unwrap_or_else(|e| $crate::error::LibrashaderError::UnknownError(e).export())
} }
};
} }
macro_rules! extern_fn { macro_rules! extern_fn {
($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => { // raw doesn't wrap in ffi_body
::paste::paste! {
/// Function pointer definition for
#[doc = ::std::stringify!($func_name)]
pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t;
}
#[no_mangle]
$(#[$($attrss)*])*
pub unsafe extern "C" fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t {
$crate::ffi::ffi_body!($body)
}
};
($(#[$($attrss:tt)*])* raw fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => { ($(#[$($attrss:tt)*])* raw fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => {
::paste::paste! { ::paste::paste! {
/// Function pointer definition for /// Function pointer definition for
@ -86,6 +109,21 @@ macro_rules! extern_fn {
} }
}; };
// ffi_body but panic-safe
($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => {
::paste::paste! {
/// Function pointer definition for
#[doc = ::std::stringify!($func_name)]
pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t;
}
#[no_mangle]
$(#[$($attrss)*])*
pub unsafe extern "C" fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t {
$crate::ffi::ffi_body!($body)
}
};
($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) |$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => { ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) |$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => {
::paste::paste! { ::paste::paste! {
/// Function pointer definition for /// Function pointer definition for
@ -126,6 +164,62 @@ macro_rules! extern_fn {
$crate::ffi::ffi_body!(|$($ref_capture),*| $body) $crate::ffi::ffi_body!(|$($ref_capture),*| $body)
} }
}; };
// nopanic variants that are UB if panics
($(#[$($attrss:tt)*])* nopanic fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => {
::paste::paste! {
/// Function pointer definition for
#[doc = ::std::stringify!($func_name)]
pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t;
}
#[no_mangle]
$(#[$($attrss)*])*
pub unsafe extern "C" fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t {
$crate::ffi::ffi_body!(nopanic $body)
}
};
($(#[$($attrss:tt)*])* nopanic fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) |$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => {
::paste::paste! {
/// Function pointer definition for
#[doc = ::std::stringify!($func_name)]
pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t;
}
#[no_mangle]
$(#[$($attrss)*])*
pub unsafe extern "C" fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t {
$crate::ffi::ffi_body!(nopanic |$($ref_capture),*|; mut |$($mut_capture),*| $body)
}
};
($(#[$($attrss:tt)*])* nopanic fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) mut |$($mut_capture:ident),*| $body:block) => {
::paste::paste! {
/// Function pointer definition for
#[doc = ::std::stringify!($func_name)]
pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t;
}
#[no_mangle]
$(#[$($attrss)*])*
pub unsafe extern "C" fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t {
$crate::ffi::ffi_body!(nopanic mut |$($mut_capture),*| $body)
}
};
($(#[$($attrss:tt)*])* nopanic fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) |$($ref_capture:ident),*| $body:block) => {
::paste::paste! {
/// Function pointer definition for
#[doc = ::std::stringify!($func_name)]
pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t;
}
#[no_mangle]
$(#[$($attrss)*])*
pub unsafe extern "C" fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t {
$crate::ffi::ffi_body!(nopanic |$($ref_capture),*| $body)
}
};
} }
pub(crate) use extern_fn; pub(crate) use extern_fn;

View file

@ -216,7 +216,7 @@ extern_fn! {
/// the filter chain was created with. /// the filter chain was created with.
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// - You must ensure that only one thread has access to `chain` before you call this function. Only one
/// thread at a time may call this function. /// thread at a time may call this function.
fn libra_d3d11_filter_chain_frame( nopanic fn libra_d3d11_filter_chain_frame(
chain: *mut libra_d3d11_filter_chain_t, chain: *mut libra_d3d11_filter_chain_t,
// cbindgen can't discover that ID3D11DeviceContext has the niche optimization // cbindgen can't discover that ID3D11DeviceContext has the niche optimization
// so ManuallyDrop<Option<ID3D11DeviceContext>> doesn't generate correct bindings. // so ManuallyDrop<Option<ID3D11DeviceContext>> doesn't generate correct bindings.

View file

@ -226,7 +226,7 @@ extern_fn! {
/// and must be associated with the `ID3D12Device` this filter chain was created with. /// and must be associated with the `ID3D12Device` this filter chain was created with.
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// - You must ensure that only one thread has access to `chain` before you call this function. Only one
/// thread at a time may call this function. /// thread at a time may call this function.
fn libra_d3d12_filter_chain_frame( nopanic fn libra_d3d12_filter_chain_frame(
chain: *mut libra_d3d12_filter_chain_t, chain: *mut libra_d3d12_filter_chain_t,
command_list: ManuallyDrop<ID3D12GraphicsCommandList>, command_list: ManuallyDrop<ID3D12GraphicsCommandList>,
frame_count: usize, frame_count: usize,

View file

@ -172,7 +172,7 @@ extern_fn! {
/// thread at a time may call this function. The thread `libra_gl_filter_chain_frame` is called from /// thread at a time may call this function. The thread `libra_gl_filter_chain_frame` is called from
/// must have its thread-local OpenGL context initialized with the same context used to create /// must have its thread-local OpenGL context initialized with the same context used to create
/// the filter chain. /// the filter chain.
fn libra_gl_filter_chain_frame( nopanic fn libra_gl_filter_chain_frame(
chain: *mut libra_gl_filter_chain_t, chain: *mut libra_gl_filter_chain_t,
frame_count: usize, frame_count: usize,
image: libra_source_image_gl_t, image: libra_source_image_gl_t,

View file

@ -246,7 +246,7 @@ extern_fn! {
/// struct. /// struct.
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// - You must ensure that only one thread has access to `chain` before you call this function. Only one
/// thread at a time may call this function. /// thread at a time may call this function.
fn libra_vk_filter_chain_frame( nopanic fn libra_vk_filter_chain_frame(
chain: *mut libra_vk_filter_chain_t, chain: *mut libra_vk_filter_chain_t,
command_buffer: vk::CommandBuffer, command_buffer: vk::CommandBuffer,
frame_count: usize, frame_count: usize,