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 {
|
||||
// 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
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -941,75 +941,43 @@ impl_ptr_intoabi!(Option<&'static T>);
|
||||
#[cfg(feature = "option_ref_abi")]
|
||||
impl_ptr_intoabi!(Option<&'static mut 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
|
||||
T: Type,
|
||||
{
|
||||
type From = Option<$ty>;
|
||||
unsafe impl<'s, T> FromFfi for &'s T
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type From = Option<&'s T>;
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
display!(r#"assert(not rawequal({arg}, nil), "argument '{arg}' cannot be nil"); "#)
|
||||
}
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
display!(r#"assert(not rawequal({arg}, nil), "argument '{arg}' cannot be nil"); "#)
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
// SAFETY: we already checked that the reference is nonnull from the lua side
|
||||
debug_assert!(
|
||||
from.is_some(),
|
||||
"<{}>::convert() called on a null reference when it was checked to be nonnull",
|
||||
stringify!($ty),
|
||||
);
|
||||
fn convert(from: Self::From) -> Self {
|
||||
// SAFETY: we already checked that the reference is nonnull from the lua side
|
||||
debug_assert!(
|
||||
from.is_some(),
|
||||
"<{}>::convert() called on a null reference when it was checked to be nonnull",
|
||||
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
|
||||
// not outlive the pointee otherwise.
|
||||
//
|
||||
macro_rules! impl_ref_intoabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T> IntoFfi for $ty
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type Into = Self;
|
||||
unsafe impl<T> IntoFfi for &'static T
|
||||
where
|
||||
T: Type,
|
||||
{
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
fn convert(self) -> Self::Into {
|
||||
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
|
||||
// thing in C (they are just pointers).
|
||||
@ -1084,13 +1052,6 @@ macro_rules! impl_externcfn {
|
||||
};
|
||||
|
||||
($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>
|
||||
where
|
||||
$($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) -> J);
|
||||
|
||||
impl<'s> Annotation for &'s [u8] {
|
||||
fn annotation() -> impl Display {
|
||||
"string"
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> Annotation for &'s str {
|
||||
fn annotation() -> impl Display {
|
||||
"string"
|
||||
}
|
||||
}
|
||||
|
||||
impl Annotation for Vec<u8> {
|
||||
fn annotation() -> impl Display {
|
||||
"string"
|
||||
}
|
||||
}
|
||||
|
||||
impl Annotation for String {
|
||||
fn annotation() -> impl Display {
|
||||
"string"
|
||||
|
Loading…
x
Reference in New Issue
Block a user