Turns out &mut T: FromFfi was unsound from the beginning after all
This commit is contained in:
parent
36300b07d3
commit
a2cbb24a75
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -941,75 +941,43 @@ 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
|
where
|
||||||
// called via FFI can be running at the same time on the same OS thread (no Lua reentrancy).
|
T: Type,
|
||||||
//
|
{
|
||||||
// i.e. The call stack will always look something like this:
|
type From = Option<&'s T>;
|
||||||
//
|
|
||||||
// * 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
|
|
||||||
T: Type,
|
|
||||||
{
|
|
||||||
type From = Option<$ty>;
|
|
||||||
|
|
||||||
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"); "#)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert(from: Self::From) -> Self {
|
fn convert(from: Self::From) -> Self {
|
||||||
// SAFETY: we already checked that the reference is nonnull from the lua side
|
// SAFETY: we already checked that the reference is nonnull from the lua side
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
from.is_some(),
|
from.is_some(),
|
||||||
"<{}>::convert() called on a null reference when it was checked to be nonnull",
|
"<{}>::convert() called on a null reference when it was checked to be nonnull",
|
||||||
stringify!($ty),
|
stringify!($ty),
|
||||||
);
|
);
|
||||||
|
|
||||||
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) => {
|
where
|
||||||
unsafe impl<T> IntoFfi for $ty
|
T: Type,
|
||||||
where
|
{
|
||||||
T: Type,
|
type Into = Self;
|
||||||
{
|
|
||||||
type Into = Self;
|
|
||||||
|
|
||||||
fn convert(self) -> Self::Into {
|
fn convert(self) -> Self::Into {
|
||||||
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
|
||||||
// thing in C (they are just pointers).
|
// thing in C (they are just pointers).
|
||||||
@ -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"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user