Turns out &mut T: FromFfi was unsound from the beginning after all

This commit is contained in:
lumi 2025-06-28 15:06:32 +10:00
parent 36300b07d3
commit a2cbb24a75
Signed by: luaneko
GPG Key ID: 406809B8763FF07A
2 changed files with 43 additions and 65 deletions

View File

@ -156,7 +156,12 @@ impl lua_pollable {
pub fn is_valid(&self) -> bool { pub fn is_valid(&self) -> bool {
// TODO: signature check can currently read out-of-bounds if lua code for some reason yields // TODO: signature check can currently read out-of-bounds if lua code for some reason yields
// a cdata of size less than 8 bytes that is not a lua_future. there is no easy way to fix // a cdata of size less than 8 bytes that is not a lua_future. there is no easy way to fix
// afaik this because there is no way to find the size of a cdata payload using the C API. // AFAIK this because there is no way to find the size of a cdata payload using the C API.
// unfortunately we have to trust that the user won't do that right now.
//
// the only "saving grace" is that the user should never be running untrusted code anyway,
// because this whole project is based on the ffi library which should never be exposed to
// untrusted code in the first place.
self.sig == SIGNATURE self.sig == SIGNATURE
} }
} }

View File

@ -941,31 +941,11 @@ impl_ptr_intoabi!(Option<&'static T>);
#[cfg(feature = "option_ref_abi")] #[cfg(feature = "option_ref_abi")]
impl_ptr_intoabi!(Option<&'static mut T>); impl_ptr_intoabi!(Option<&'static mut T>);
// unsafe impl<'s, T> FromFfi for &'s T
// SAFETY: `FromFfi` for *mutable* references is safe because it is guaranteed that no two Rust code
// called via FFI can be running at the same time on the same OS thread (no Lua reentrancy).
//
// i.e. The call stack will always look something like this:
//
// * Runtime (LuaJIT/Rust) -> Lua (via C) -> Rust (via FFI): This is SAFE and the only use case we
// support. All references (mutable or not) to Rust user objects will be dropped before
// returning to Lua.
//
// * Runtime (LuaJIT/Rust) -> Lua (via C) -> Rust (via FFI) -> Lua (via callback): This is UNSAFE
// because we cannot prevent the Lua callback from calling back into Rust code via FFI which
// could violate exclusive borrow semantics. This is prevented by not implementing `FromFfi` for
// function pointers (see below).
//
// The runtime does not keep any references to Rust user objects boxed in cdata (futures are the
// only exception; their ownership is transferred to the runtime via yield).
//
macro_rules! impl_ref_fromabi {
($ty:ty) => {
unsafe impl<'s, T> FromFfi for $ty
where where
T: Type, T: Type,
{ {
type From = Option<$ty>; type From = Option<&'s T>;
fn prelude(arg: &str) -> impl Display { fn prelude(arg: &str) -> impl Display {
display!(r#"assert(not rawequal({arg}, nil), "argument '{arg}' cannot be nil"); "#) display!(r#"assert(not rawequal({arg}, nil), "argument '{arg}' cannot be nil"); "#)
@ -982,19 +962,12 @@ macro_rules! impl_ref_fromabi {
unsafe { from.unwrap_unchecked() } unsafe { from.unwrap_unchecked() }
} }
} }
};
}
impl_ref_fromabi!(&'s T);
impl_ref_fromabi!(&'s mut T);
// //
// SAFETY: `IntoFfi` only for 'static references because we cannot guarantee that the pointer will // SAFETY: `IntoFfi` only for 'static references because we cannot guarantee that the pointer will
// not outlive the pointee otherwise. // not outlive the pointee otherwise.
// //
macro_rules! impl_ref_intoabi { unsafe impl<T> IntoFfi for &'static T
($ty:ty) => {
unsafe impl<T> IntoFfi for $ty
where where
T: Type, T: Type,
{ {
@ -1004,11 +977,6 @@ macro_rules! impl_ref_intoabi {
self self
} }
} }
};
}
impl_ref_intoabi!(&'static T);
impl_ref_intoabi!(&'static mut T);
// //
// SAFETY: No `FromFfi` and `IntoFfi` for arrays because passing or returning them by value is not a // SAFETY: No `FromFfi` and `IntoFfi` for arrays because passing or returning them by value is not a
@ -1084,13 +1052,6 @@ macro_rules! impl_externcfn {
}; };
($ty:ident, fn($($arg:ident),*) -> $ret:ident) => { ($ty:ident, fn($($arg:ident),*) -> $ret:ident) => {
//
// SAFETY: No `FromFfi` for function pointers because of borrow safety invariants (see above
// in `&mut T`).
//
// We also can't implement `IntoFfi` because we can't call `FromFfi` and `IntoFfi` for the
// function's respective argument and return values.
//
unsafe impl<$($arg,)* $ret> Type for $ty<($($arg,)*), $ret> unsafe impl<$($arg,)* $ret> Type for $ty<($($arg,)*), $ret>
where where
$($arg: Type,)* $($arg: Type,)*
@ -1145,12 +1106,24 @@ impl_externcfn!(fn(A, B, C, D, E, F, G) -> H);
impl_externcfn!(fn(A, B, C, D, E, F, G, H) -> I); impl_externcfn!(fn(A, B, C, D, E, F, G, H) -> I);
impl_externcfn!(fn(A, B, C, D, E, F, G, H, I) -> J); impl_externcfn!(fn(A, B, C, D, E, F, G, H, I) -> J);
impl<'s> Annotation for &'s [u8] {
fn annotation() -> impl Display {
"string"
}
}
impl<'s> Annotation for &'s str { impl<'s> Annotation for &'s str {
fn annotation() -> impl Display { fn annotation() -> impl Display {
"string" "string"
} }
} }
impl Annotation for Vec<u8> {
fn annotation() -> impl Display {
"string"
}
}
impl Annotation for String { impl Annotation for String {
fn annotation() -> impl Display { fn annotation() -> impl Display {
"string" "string"