diff --git a/crates/lune-std-ffi/src/c/c_arr.rs b/crates/lune-std-ffi/src/c/c_arr.rs index 9302a3d..33625a8 100644 --- a/crates/lune-std-ffi/src/c/c_arr.rs +++ b/crates/lune-std-ffi/src/c/c_arr.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::ffi::{ ffi_association::{get_association, set_association}, - FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSignedness, NativeSize, + FfiBox, GetNativeDataHandle, NativeConvert, NativeDataHandle, NativeSize, }; // This is a series of some type. @@ -104,11 +104,6 @@ impl NativeSize for CArr { self.size } } -impl NativeSignedness for CArr { - fn get_signedness(&self) -> bool { - false - } -} impl NativeConvert for CArr { // FIXME: FfiBox, FfiRef support required unsafe fn luavalue_into<'lua>( @@ -192,7 +187,7 @@ impl LuaUserData for CArr { if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.check_readable(&userdata, offset, this.get_size()) { + if !data_handle.check_readable(offset, this.get_size()) { return Err(LuaError::external("Unreadable data handle")); } @@ -208,7 +203,7 @@ impl LuaUserData for CArr { if !data_handle.check_boundary(offset, this.size) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(&userdata, offset, this.size) { + if !data_handle.checek_writable(offset, this.size) { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index d83ecf7..c1877a6 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,7 +1,10 @@ use libffi::middle::{Cif, Type}; use mlua::prelude::*; -use super::c_helper::{libffi_type_from_userdata, libffi_type_list_from_table}; +use super::c_helper::{ + get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, +}; +use crate::ffi::NativeConvert; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -21,24 +24,35 @@ use super::c_helper::{libffi_type_from_userdata, libffi_type_list_from_table}; pub struct CFn { libffi_cif: Cif, - args: Vec, - ret: Type, + args_conv: Vec<*const dyn NativeConvert>, + ret_conv: *const dyn NativeConvert, } impl CFn { - pub fn new(args: Vec, ret: Type) -> Self { - let libffi_cif = Cif::new(args.clone(), ret.clone()); + pub fn new( + args: Vec, + ret: Type, + args_conv: Vec<*const dyn NativeConvert>, + ret_conv: *const dyn NativeConvert, + ) -> Self { + let libffi_cif: Cif = Cif::new(args.clone(), ret.clone()); Self { libffi_cif, - args, - ret, + args_conv, + ret_conv, } } pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - let args = libffi_type_list_from_table(lua, &args)?; - let ret = libffi_type_from_userdata(lua, &ret)?; - Ok(Self::new(args, ret)) + let args_type = libffi_type_list_from_table(lua, &args)?; + let ret_type = libffi_type_from_userdata(lua, &ret)?; + + Ok(Self::new( + args_type, + ret_type, + unsafe { get_conv_list_from_table(&args)? }, + unsafe { get_conv(&ret)? }, + )) } } diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs index 39df226..16a399b 100644 --- a/crates/lune-std-ffi/src/c/c_struct.rs +++ b/crates/lune-std-ffi/src/c/c_struct.rs @@ -50,6 +50,7 @@ impl CStruct { // Get tailing padded size of struct // See http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Size-and-Alignment.html + // In here, using get_ensured_size is waste let size = unsafe { (*struct_type.as_raw_ptr()).size }; Ok(Self { @@ -91,7 +92,8 @@ impl CStruct { } // size of - result.push_str(format!("size = {} ", userdata.borrow::()?.size).as_str()); + result + .push_str(format!("size = {} ", userdata.borrow::()?.get_size()).as_str()); Ok(result) } else { Err(LuaError::external("failed to get inner type table.")) @@ -206,7 +208,7 @@ impl LuaUserData for CStruct { if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.check_readable(&userdata, offset, this.get_size()) { + if !data_handle.check_readable(offset, this.get_size()) { return Err(LuaError::external("Unreadable data handle")); } @@ -219,10 +221,10 @@ impl LuaUserData for CStruct { let offset = offset.unwrap_or(0); let data_handle = &userdata.get_data_handle()?; - if !data_handle.check_boundary(offset, this.size) { + if !data_handle.check_boundary(offset, this.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(&userdata, offset, this.size) { + if !data_handle.checek_writable(offset, this.get_size()) { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs index 4ab4cd8..7ad121d 100644 --- a/crates/lune-std-ffi/src/c/c_type.rs +++ b/crates/lune-std-ffi/src/c/c_type.rs @@ -164,7 +164,7 @@ where if !data_handle.check_boundary(offset, ctype.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.check_readable(&userdata, offset, ctype.get_size()) { + if !data_handle.check_readable(offset, ctype.get_size()) { return Err(LuaError::external("Unreadable data handle")); } @@ -187,7 +187,7 @@ where if !data_handle.check_boundary(offset, ctype.get_size()) { return Err(LuaError::external("Out of bounds")); } - if !data_handle.checek_writable(&userdata, offset, ctype.get_size()) { + if !data_handle.checek_writable(offset, ctype.get_size()) { return Err(LuaError::external("Unwritable data handle")); } diff --git a/crates/lune-std-ffi/src/c/c_void.rs b/crates/lune-std-ffi/src/c/c_void.rs index e69de29..b1e6fcb 100644 --- a/crates/lune-std-ffi/src/c/c_void.rs +++ b/crates/lune-std-ffi/src/c/c_void.rs @@ -0,0 +1 @@ +use core::ffi::c_void; diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs index f769666..9229b8d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_box.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs @@ -1,27 +1,17 @@ use std::boxed::Box; -use std::sync::OnceLock; use mlua::prelude::*; use super::{ association_names::REF_INNER, ffi_association::set_association, - ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList}, + ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, NativeDataHandle, }; -static BOX_REF_FLAGS: OnceLock = OnceLock::new(); -fn get_box_ref_flags() -> FfiRefFlagList { - BOX_REF_FLAGS - .get_or_init(|| { - FfiRefFlagList::new(&[ - FfiRefFlag::Offsetable, - FfiRefFlag::Readable, - FfiRefFlag::Writable, - ]) - }) - .to_owned() -} +const BOX_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( + FfiRefFlag::Offsetable.value() | FfiRefFlag::Readable.value() | FfiRefFlag::Writable.value(), +); // It is an untyped, sized memory area that Lua can manage. // This area is safe within Lua. Operations have their boundaries checked. @@ -35,6 +25,7 @@ fn get_box_ref_flags() -> FfiRefFlagList { struct RefData { address: usize, offset: usize, + lua_inner_id: i32, } pub struct FfiBox { @@ -77,7 +68,7 @@ impl FfiBox { this: LuaAnyUserData<'lua>, offset: Option, ) -> LuaResult> { - let mut target = this.borrow_mut::()?; + let target = this.borrow::()?; let mut bounds = FfiRefBounds::new(0, target.size()); let mut ptr = target.get_ptr(); @@ -98,7 +89,7 @@ impl FfiBox { // To deref a box space is to allow lua to read any space, // which has security issues and is ultimately dangerous. // Therefore, box:ref():deref() is not allowed. - let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), get_box_ref_flags(), bounds))?; + let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), BOX_REF_FLAGS, bounds))?; // Makes box alive longer then ref set_association(lua, REF_INNER, &luaref, &this)?; @@ -106,6 +97,27 @@ impl FfiBox { Ok(luaref) } + // Make FfiRef from box, without any safe features + pub fn luaref_unsafe<'lua>( + lua: &'lua Lua, + this: LuaAnyUserData<'lua>, + offset: Option, + ) -> LuaResult> { + let target = this.borrow::()?; + let mut ptr = target.get_ptr(); + + // Calculate offset + if let Some(t) = offset { + ptr = unsafe { target.get_ptr().byte_offset(t) }; + } + + lua.create_userdata(FfiRef::new( + ptr.cast(), + FfiRefFlagList::all(), + UNSIZED_BOUNDS, + )) + } + // Fill every field with 0 pub fn zero(&mut self) { self.data.fill(0u8); @@ -130,13 +142,16 @@ impl NativeDataHandle for FfiBox { self.size() > ((offset as usize) + size) } // FIXME - fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + fn checek_writable(&self, offset: isize, size: usize) -> bool { true } // FIXME - fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { + fn check_readable(&self, offset: isize, size: usize) -> bool { true } + fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()> { + Ok(()) + } unsafe fn get_pointer(&self, offset: isize) -> *mut () { self.get_ptr().byte_offset(offset).cast::<()>() } @@ -155,8 +170,13 @@ impl LuaUserData for FfiBox { methods.add_function( "ref", |lua, (this, offset): (LuaAnyUserData, Option)| { - let luaref = FfiBox::luaref(lua, this, offset)?; - Ok(luaref) + FfiBox::luaref(lua, this, offset) + }, + ); + methods.add_function( + "unsafeRef", + |lua, (this, offset): (LuaAnyUserData, Option)| { + FfiBox::luaref_unsafe(lua, this, offset) }, ); methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(this.stringify())); diff --git a/crates/lune-std-ffi/src/ffi/ffi_func.rs b/crates/lune-std-ffi/src/ffi/ffi_func.rs deleted file mode 100644 index 2126bc5..0000000 --- a/crates/lune-std-ffi/src/ffi/ffi_func.rs +++ /dev/null @@ -1,3 +0,0 @@ -struct FfiFunc { - args: Vec, -} diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs index 6b5180a..4d92462 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs @@ -1,5 +1,4 @@ -use std::ffi::c_void; -use std::sync::LazyLock; +use core::ffi::c_void; use dlopen2::symbor::Library; use mlua::prelude::*; @@ -10,14 +9,12 @@ use super::{ ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS}, }; -static LIB_REF_FLAGS: LazyLock = LazyLock::new(|| { - FfiRefFlagList::new(&[ - FfiRefFlag::Offsetable, - FfiRefFlag::Readable, - FfiRefFlag::Dereferenceable, - FfiRefFlag::Function, - ]) -}); +const LIB_REF_FLAGS: FfiRefFlagList = FfiRefFlagList::new( + FfiRefFlag::Offsetable.value() + | FfiRefFlag::Readable.value() + | FfiRefFlag::Dereferenceable.value() + | FfiRefFlag::Function.value(), +); pub struct FfiLib(Library); @@ -50,11 +47,8 @@ impl FfiLib { .map_err(|err| LuaError::external(format!("{err}")))? }; - let luasym = lua.create_userdata(FfiRef::new( - (*sym).cast(), - (*LIB_REF_FLAGS).clone(), - UNSIZED_BOUNDS, - ))?; + let luasym = + lua.create_userdata(FfiRef::new((*sym).cast(), LIB_REF_FLAGS, UNSIZED_BOUNDS))?; set_association(lua, SYM_INNER, &luasym, &this)?; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs b/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs index a7d98dc..2f96eaa 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/readwrite.rs @@ -7,8 +7,9 @@ use super::super::{FfiBox, FfiRef}; pub trait NativeDataHandle { fn check_boundary(&self, offset: isize, size: usize) -> bool; - fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool; - fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool; + fn check_readable(&self, offset: isize, size: usize) -> bool; + fn checek_writable(&self, offset: isize, size: usize) -> bool; + fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()>; unsafe fn get_pointer(&self, offset: isize) -> *mut (); } diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs index 12055c5..114f67c 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs @@ -25,12 +25,17 @@ impl FfiRefFlagList { pub fn zero() -> Self { Self(0) } - pub fn new(flags: &[FfiRefFlag]) -> Self { - let mut value = 0; - for i in flags { - value |= i.value(); - } - Self(value) + pub const fn new(flags: u8) -> Self { + Self(flags) + } + pub const fn all() -> Self { + Self( + FfiRefFlag::Dereferenceable.value() + | FfiRefFlag::Readable.value() + | FfiRefFlag::Writable.value() + | FfiRefFlag::Offsetable.value() + | FfiRefFlag::Function.value(), + ) } fn set(&mut self, value: bool, mask: u8) { if value { diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs index 7971644..4412828 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -26,6 +26,8 @@ pub struct FfiRef { ptr: *mut (), pub flags: FfiRefFlagList, pub boundary: FfiRefBounds, + // Save lua ffibox pointer + pub inner: Option<*const dyn NativeDataHandle>, } impl FfiRef { @@ -34,6 +36,7 @@ impl FfiRef { ptr, flags, boundary: range, + inner: None, } } @@ -125,12 +128,34 @@ impl NativeDataHandle for FfiRef { fn check_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) } - fn checek_writable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { - self.flags.is_writable() + fn checek_writable(&self, offset: isize, size: usize) -> bool { + // If unreadable ref + if !self.flags.is_writable() { + return false; + } + + // If ref have inner luabox + if let Some(inner) = self.inner { + return unsafe { inner.as_ref().unwrap().checek_writable(offset, size) }; + } + + true } - // TODO: if ref points box , check box too - fn check_readable(&self, userdata: &LuaAnyUserData, offset: isize, size: usize) -> bool { - self.flags.is_readable() + fn check_readable(&self, offset: isize, size: usize) -> bool { + // If unreadable ref + if !self.flags.is_readable() { + return false; + } + + // If ref have inner luabox + if let Some(inner) = self.inner { + return unsafe { inner.as_ref().unwrap().check_readable(offset, size) }; + } + + true + } + fn mark_ref(&self, userdata: &LuaAnyUserData, offset: isize, ptr: usize) -> LuaResult<()> { + Ok(()) } unsafe fn get_pointer(&self, offset: isize) -> *mut () { self.get_ptr().byte_offset(offset)