From 83be2bc96a1b504463632f992311debe62d39103 Mon Sep 17 00:00:00 2001 From: qwreey Date: Wed, 23 Oct 2024 04:29:32 +0000 Subject: [PATCH] Remove callable boundary check (#243) --- crates/lune-std-ffi/README.md | 2 +- crates/lune-std-ffi/src/c/arr_info.rs | 1 - crates/lune-std-ffi/src/c/fn_info.rs | 3 - crates/lune-std-ffi/src/c/helper.rs | 12 ++-- crates/lune-std-ffi/src/c/mod.rs | 3 + crates/lune-std-ffi/src/c/ptr_info.rs | 1 - crates/lune-std-ffi/src/c/string_info.rs | 10 ++++ crates/lune-std-ffi/src/c/struct_info.rs | 1 - crates/lune-std-ffi/src/c/type_info.rs | 3 +- crates/lune-std-ffi/src/c/void_info.rs | 3 - crates/lune-std-ffi/src/data/callable_data.rs | 59 +++++++++---------- tests/ffi/pretty_print.luau | 24 ++++---- 12 files changed, 61 insertions(+), 61 deletions(-) diff --git a/crates/lune-std-ffi/README.md b/crates/lune-std-ffi/README.md index 8f0ace1..83d1abf 100644 --- a/crates/lune-std-ffi/README.md +++ b/crates/lune-std-ffi/README.md @@ -12,7 +12,7 @@ See [tests/ffi](../../tests/ffi/README.md) - Add math operation. - > `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` + > Provide related methods: `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow` `:max` `:min` `:gt` `:lt` > Luau cannot handle f64, i64 or i128, so we should provide math operation for it - Add bit operation diff --git a/crates/lune-std-ffi/src/c/arr_info.rs b/crates/lune-std-ffi/src/c/arr_info.rs index cfd7259..4a109ff 100644 --- a/crates/lune-std-ffi/src/c/arr_info.rs +++ b/crates/lune-std-ffi/src/c/arr_info.rs @@ -150,7 +150,6 @@ impl FfiConvert for CArrInfo { impl LuaUserData for CArrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CArr"); fields.add_field_method_get("size", |_, this| Ok(this.get_size())); fields.add_field_method_get("length", |_, this| Ok(this.get_length())); fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { diff --git a/crates/lune-std-ffi/src/c/fn_info.rs b/crates/lune-std-ffi/src/c/fn_info.rs index ca78740..43b7f54 100644 --- a/crates/lune-std-ffi/src/c/fn_info.rs +++ b/crates/lune-std-ffi/src/c/fn_info.rs @@ -203,9 +203,6 @@ impl CFnInfo { } impl LuaUserData for CFnInfo { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CFn"); - } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { // Subtype method_provider::provide_ptr(methods); diff --git a/crates/lune-std-ffi/src/c/helper.rs b/crates/lune-std-ffi/src/c/helper.rs index 8a54fdc..760e582 100644 --- a/crates/lune-std-ffi/src/c/helper.rs +++ b/crates/lune-std-ffi/src/c/helper.rs @@ -314,17 +314,17 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult { // get name tag for any c-type userdata pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult { Ok(if userdata.is::() { - String::from("CStruct") + String::from("CStructInfo") } else if userdata.is::() { - String::from("CArr") + String::from("CArrInfo") } else if userdata.is::() { - String::from("CPtr") + String::from("CPtrInfo") } else if userdata.is::() { - String::from("CFn") + String::from("CFnInfo") } else if userdata.is::() { - String::from("CVoid") + String::from("CVoidInfo") } else if ctype_helper::is_ctype(userdata) { - String::from("CType") + String::from("CTypeInfo") } else { String::from("Unknown") }) diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 6db6a69..911cdb6 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -5,6 +5,7 @@ mod arr_info; mod fn_info; pub mod helper; mod ptr_info; +mod string_info; mod struct_info; mod type_info; mod types; @@ -15,6 +16,7 @@ pub use self::{ fn_info::CFnInfo, helper::method_provider, ptr_info::CPtrInfo, + string_info::CStringInfo, struct_info::CStructInfo, type_info::{CTypeCast, CTypeInfo}, types::{ctype_helper, export_c_types, export_fixed_types}, @@ -44,5 +46,6 @@ pub fn export_c(lua: &Lua) -> LuaResult { .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { CFnInfo::from_table(lua, args, ret) })? + .with_value("string", CStringInfo::new())? .build_readonly() } diff --git a/crates/lune-std-ffi/src/c/ptr_info.rs b/crates/lune-std-ffi/src/c/ptr_info.rs index d66c394..f39b425 100644 --- a/crates/lune-std-ffi/src/c/ptr_info.rs +++ b/crates/lune-std-ffi/src/c/ptr_info.rs @@ -124,7 +124,6 @@ impl CPtrInfo { impl LuaUserData for CPtrInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CPtr"); fields.add_field_method_get("size", |_, _| Ok(size_of::())); fields.add_field_function_get("inner", |lua, this| { let inner = association::get(lua, CPTR_INNER, this)? diff --git a/crates/lune-std-ffi/src/c/string_info.rs b/crates/lune-std-ffi/src/c/string_info.rs index 8b13789..2a4da64 100644 --- a/crates/lune-std-ffi/src/c/string_info.rs +++ b/crates/lune-std-ffi/src/c/string_info.rs @@ -1 +1,11 @@ +use mlua::prelude::*; +pub struct CStringInfo(); + +impl CStringInfo { + pub fn new() -> Self { + Self() + } +} + +impl LuaUserData for CStringInfo {} diff --git a/crates/lune-std-ffi/src/c/struct_info.rs b/crates/lune-std-ffi/src/c/struct_info.rs index 8917eb5..3abbe73 100644 --- a/crates/lune-std-ffi/src/c/struct_info.rs +++ b/crates/lune-std-ffi/src/c/struct_info.rs @@ -182,7 +182,6 @@ impl FfiConvert for CStructInfo { impl LuaUserData for CStructInfo { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CStruct"); fields.add_field_method_get("size", |_, this| Ok(this.get_size())); } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { diff --git a/crates/lune-std-ffi/src/c/type_info.rs b/crates/lune-std-ffi/src/c/type_info.rs index b12eebf..374f09b 100644 --- a/crates/lune-std-ffi/src/c/type_info.rs +++ b/crates/lune-std-ffi/src/c/type_info.rs @@ -91,9 +91,8 @@ where Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CType"); + fields.add_meta_field(LuaMetaMethod::Type, "CTypeInfo"); fields.add_field_method_get("size", |_, this| Ok(this.get_size())); - fields.add_meta_field(LuaMetaMethod::Type, "CType"); fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness())); } diff --git a/crates/lune-std-ffi/src/c/void_info.rs b/crates/lune-std-ffi/src/c/void_info.rs index b0008e2..05ad57d 100644 --- a/crates/lune-std-ffi/src/c/void_info.rs +++ b/crates/lune-std-ffi/src/c/void_info.rs @@ -31,9 +31,6 @@ impl CVoidInfo { } impl LuaUserData for CVoidInfo { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_meta_field(LuaMetaMethod::Type, "CVoid"); - } fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { method_provider::provide_to_string(methods); method_provider::provide_ptr(methods); diff --git a/crates/lune-std-ffi/src/data/callable_data.rs b/crates/lune-std-ffi/src/data/callable_data.rs index f94d420..fab6c7e 100644 --- a/crates/lune-std-ffi/src/data/callable_data.rs +++ b/crates/lune-std-ffi/src/data/callable_data.rs @@ -23,32 +23,32 @@ pub struct CallableData { const VOID_RESULT_PTR: *mut () = ptr::null_mut(); const ZERO_SIZE_ARG_PTR: *mut *mut c_void = ptr::null_mut(); +// Use known size array in stack instead of creating new Vec on heap macro_rules! create_caller { ($len:expr) => { |callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe { - let mut arg_list: [MaybeUninit<*mut c_void>; $len] = [MaybeUninit::uninit(); $len]; - + // Get `rvalue: *mut c_void` result pointer let result_pointer = if callable.result_info.size == 0 { VOID_RESULT_PTR } else { - let result_data = result.get_ffi_data()?; - if !result_data.check_inner_boundary(0, callable.result_info.size) { - return Err(LuaError::external("Result boundary check failed")); - } - result_data.get_inner_pointer() + result.get_ffi_data()?.get_inner_pointer() } .cast::(); + // Create `avalue: *mut *mut c_void` argument list + let mut arg_list: [MaybeUninit<*mut c_void>; $len] = [MaybeUninit::uninit(); $len]; for (index, arg) in arg_list.iter_mut().enumerate() { let arg_value = args .get(index) - .ok_or_else(|| LuaError::external(format!("argument {index} required")))? + .ok_or_else(|| LuaError::external(format!("Argument {index} required")))? .as_userdata() - .ok_or_else(|| LuaError::external("argument should be Ref"))?; + .ok_or_else(|| LuaError::external("Argument should be a RefData"))?; - let arg_ref = arg_value.borrow::()?; - - arg.write(arg_ref.get_inner_pointer().cast::()); + if let Ok(arg_ref) = arg_value.borrow::() { + arg.write(arg_ref.get_inner_pointer().cast::()); + } else { + return Err(LuaError::external("Argument should be a RefData")); + } } ffi_call( @@ -65,6 +65,7 @@ macro_rules! create_caller { }; } +// Call without arguments unsafe fn zero_size_caller( callable: &CallableData, result: LuaValue, @@ -73,11 +74,7 @@ unsafe fn zero_size_caller( let result_pointer = if callable.result_info.size == 0 { VOID_RESULT_PTR } else { - let result_data = result.get_ffi_data()?; - if !result_data.check_inner_boundary(0, callable.result_info.size) { - return Err(LuaError::external("Result boundary check failed")); - } - result_data.get_inner_pointer() + result.get_ffi_data()?.get_inner_pointer() } .cast::(); @@ -130,31 +127,31 @@ impl CallableData { return SIZED_CALLERS[arg_len](self, result, args); } - let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_len); - + // Get `rvalue: *mut c_void` result pointer let result_pointer = if self.result_info.size == 0 { VOID_RESULT_PTR } else { - let result_data = result.get_ffi_data()?; - if !result_data.check_inner_boundary(0, self.result_info.size) { - return Err(LuaError::external("Result boundary check failed")); - } - result_data.get_inner_pointer() + result.get_ffi_data()?.get_inner_pointer() } .cast::(); - for index in 0..self.arg_info_list.len() { + // Create `avalue: *mut *mut c_void` argument list + let mut arg_list = Vec::<*mut c_void>::with_capacity(arg_len); + for index in 0..arg_len { let arg_value = args .get(index) - .ok_or_else(|| LuaError::external(format!("argument {index} required")))? + .ok_or_else(|| LuaError::external(format!("Argument {index} required")))? .as_userdata() - .ok_or_else(|| LuaError::external("argument should be Ref"))?; + .ok_or_else(|| LuaError::external("Argument should be a RefData"))?; - let arg_ref = arg_value.borrow::()?; - - arg_list.push(arg_ref.get_inner_pointer().cast::()); + if let Ok(arg_ref) = arg_value.borrow::() { + arg_list.push(arg_ref.get_inner_pointer().cast::()); + } else { + return Err(LuaError::external("Argument should be a RefData")); + } } + // Call libffi::raw::ffi_call ffi_call( self.cif, Some(*self.code.as_safe_fun()), @@ -172,7 +169,7 @@ impl LuaUserData for CallableData { LuaMetaMethod::Call, |_lua, this: &CallableData, mut args: LuaMultiValue| { let result = args.pop_front().ok_or_else(|| { - LuaError::external("First argument must be result data handle or nil") + LuaError::external("First argument 'result' must be a RefData, BoxData or nil") })?; unsafe { this.call(result, args) } }, diff --git a/tests/ffi/pretty_print.luau b/tests/ffi/pretty_print.luau index 815c261..6019089 100644 --- a/tests/ffi/pretty_print.luau +++ b/tests/ffi/pretty_print.luau @@ -1,32 +1,32 @@ local ffi = require("@lune/ffi") local c = ffi.c -assert(typeof(c.int) :: string == "CType") +assert(typeof(c.int) :: string == "CTypeInfo") assert(tostring(c.int) == "int") -assert(typeof(c.int:ptr()) :: string == "CPtr") +assert(typeof(c.int:ptr()) :: string == "CPtrInfo") assert(tostring(c.int:ptr()) == "int") -assert(tostring(c.int:arr(5):ptr()) == " ") +assert(tostring(c.int:arr(5):ptr()) == " ") -assert(typeof(c.int:arr(5)) :: string == "CArr") +assert(typeof(c.int:arr(5)) :: string == "CArrInfo") assert(tostring(c.int:arr(5)) == " int, length = 5 ") -assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") +assert(tostring(c.int:ptr():arr(5)) == " , length = 5 ") -assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFn") +assert(typeof(c.fn({ c.int }, c.int)) :: string == "CFnInfo") assert(tostring(c.fn({ c.int }, c.int)) == " (int) -> int ") assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ") -assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") -assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") -assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") +assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " () -> int ") +assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> ") +assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " () -> ") assert( tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr())) - == " (, ) -> " + == " (, ) -> " ) -assert(typeof(c.struct({ c.int, c.char })) :: string == "CStruct") +assert(typeof(c.struct({ c.int, c.char })) :: string == "CStructInfo") assert( tostring(c.struct({ c.int, c.char:ptr() })) - == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` + == ` int, , size = {c.struct({ c.int, c.char:ptr() }).size} ` ) -- FIXME: add box, ref pretty-print test