Remove callable boundary check (#243)

This commit is contained in:
qwreey 2024-10-23 04:29:32 +00:00
parent b442ba7985
commit 83be2bc96a
No known key found for this signature in database
GPG key ID: D28DB79297A214BD
12 changed files with 61 additions and 61 deletions

View file

@ -12,7 +12,7 @@ See [tests/ffi](../../tests/ffi/README.md)
- Add math operation. - 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 > Luau cannot handle f64, i64 or i128, so we should provide math operation for it
- Add bit operation - Add bit operation

View file

@ -150,7 +150,6 @@ impl FfiConvert for CArrInfo {
impl LuaUserData for CArrInfo { impl LuaUserData for CArrInfo {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { 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("size", |_, this| Ok(this.get_size()));
fields.add_field_method_get("length", |_, this| Ok(this.get_length())); fields.add_field_method_get("length", |_, this| Ok(this.get_length()));
fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| { fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {

View file

@ -203,9 +203,6 @@ impl CFnInfo {
} }
impl LuaUserData for 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) { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
// Subtype // Subtype
method_provider::provide_ptr(methods); method_provider::provide_ptr(methods);

View file

@ -314,17 +314,17 @@ pub fn stringify(lua: &Lua, userdata: &LuaAnyUserData) -> LuaResult<String> {
// get name tag for any c-type userdata // get name tag for any c-type userdata
pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult<String> { pub fn get_tag_name(userdata: &LuaAnyUserData) -> LuaResult<String> {
Ok(if userdata.is::<CStructInfo>() { Ok(if userdata.is::<CStructInfo>() {
String::from("CStruct") String::from("CStructInfo")
} else if userdata.is::<CArrInfo>() { } else if userdata.is::<CArrInfo>() {
String::from("CArr") String::from("CArrInfo")
} else if userdata.is::<CPtrInfo>() { } else if userdata.is::<CPtrInfo>() {
String::from("CPtr") String::from("CPtrInfo")
} else if userdata.is::<CFnInfo>() { } else if userdata.is::<CFnInfo>() {
String::from("CFn") String::from("CFnInfo")
} else if userdata.is::<CVoidInfo>() { } else if userdata.is::<CVoidInfo>() {
String::from("CVoid") String::from("CVoidInfo")
} else if ctype_helper::is_ctype(userdata) { } else if ctype_helper::is_ctype(userdata) {
String::from("CType") String::from("CTypeInfo")
} else { } else {
String::from("Unknown") String::from("Unknown")
}) })

View file

@ -5,6 +5,7 @@ mod arr_info;
mod fn_info; mod fn_info;
pub mod helper; pub mod helper;
mod ptr_info; mod ptr_info;
mod string_info;
mod struct_info; mod struct_info;
mod type_info; mod type_info;
mod types; mod types;
@ -15,6 +16,7 @@ pub use self::{
fn_info::CFnInfo, fn_info::CFnInfo,
helper::method_provider, helper::method_provider,
ptr_info::CPtrInfo, ptr_info::CPtrInfo,
string_info::CStringInfo,
struct_info::CStructInfo, struct_info::CStructInfo,
type_info::{CTypeCast, CTypeInfo}, type_info::{CTypeCast, CTypeInfo},
types::{ctype_helper, export_c_types, export_fixed_types}, types::{ctype_helper, export_c_types, export_fixed_types},
@ -44,5 +46,6 @@ pub fn export_c(lua: &Lua) -> LuaResult<LuaTable> {
.with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| { .with_function("fn", |lua, (args, ret): (LuaTable, LuaAnyUserData)| {
CFnInfo::from_table(lua, args, ret) CFnInfo::from_table(lua, args, ret)
})? })?
.with_value("string", CStringInfo::new())?
.build_readonly() .build_readonly()
} }

View file

@ -124,7 +124,6 @@ impl CPtrInfo {
impl LuaUserData for CPtrInfo { impl LuaUserData for CPtrInfo {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { 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::<usize>())); fields.add_field_method_get("size", |_, _| Ok(size_of::<usize>()));
fields.add_field_function_get("inner", |lua, this| { fields.add_field_function_get("inner", |lua, this| {
let inner = association::get(lua, CPTR_INNER, this)? let inner = association::get(lua, CPTR_INNER, this)?

View file

@ -1 +1,11 @@
use mlua::prelude::*;
pub struct CStringInfo();
impl CStringInfo {
pub fn new() -> Self {
Self()
}
}
impl LuaUserData for CStringInfo {}

View file

@ -182,7 +182,6 @@ impl FfiConvert for CStructInfo {
impl LuaUserData for CStructInfo { impl LuaUserData for CStructInfo {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { 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())); fields.add_field_method_get("size", |_, this| Ok(this.get_size()));
} }
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {

View file

@ -91,9 +91,8 @@ where
Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize, Self: CTypeCast + FfiSignedness + FfiConvert + FfiSize,
{ {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { 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_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())); fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness()));
} }

View file

@ -31,9 +31,6 @@ impl CVoidInfo {
} }
impl LuaUserData for 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) { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
method_provider::provide_to_string(methods); method_provider::provide_to_string(methods);
method_provider::provide_ptr(methods); method_provider::provide_ptr(methods);

View file

@ -23,32 +23,32 @@ pub struct CallableData {
const VOID_RESULT_PTR: *mut () = ptr::null_mut(); const VOID_RESULT_PTR: *mut () = ptr::null_mut();
const ZERO_SIZE_ARG_PTR: *mut *mut c_void = 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 { macro_rules! create_caller {
($len:expr) => { ($len:expr) => {
|callable: &CallableData, result: LuaValue, args: LuaMultiValue| unsafe { |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 { let result_pointer = if callable.result_info.size == 0 {
VOID_RESULT_PTR VOID_RESULT_PTR
} else { } else {
let result_data = result.get_ffi_data()?; result.get_ffi_data()?.get_inner_pointer()
if !result_data.check_inner_boundary(0, callable.result_info.size) {
return Err(LuaError::external("Result boundary check failed"));
}
result_data.get_inner_pointer()
} }
.cast::<c_void>(); .cast::<c_void>();
// 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() { for (index, arg) in arg_list.iter_mut().enumerate() {
let arg_value = args let arg_value = args
.get(index) .get(index)
.ok_or_else(|| LuaError::external(format!("argument {index} required")))? .ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
.as_userdata() .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::<RefData>()?;
if let Ok(arg_ref) = arg_value.borrow::<RefData>() {
arg.write(arg_ref.get_inner_pointer().cast::<c_void>()); arg.write(arg_ref.get_inner_pointer().cast::<c_void>());
} else {
return Err(LuaError::external("Argument should be a RefData"));
}
} }
ffi_call( ffi_call(
@ -65,6 +65,7 @@ macro_rules! create_caller {
}; };
} }
// Call without arguments
unsafe fn zero_size_caller( unsafe fn zero_size_caller(
callable: &CallableData, callable: &CallableData,
result: LuaValue, result: LuaValue,
@ -73,11 +74,7 @@ unsafe fn zero_size_caller(
let result_pointer = if callable.result_info.size == 0 { let result_pointer = if callable.result_info.size == 0 {
VOID_RESULT_PTR VOID_RESULT_PTR
} else { } else {
let result_data = result.get_ffi_data()?; result.get_ffi_data()?.get_inner_pointer()
if !result_data.check_inner_boundary(0, callable.result_info.size) {
return Err(LuaError::external("Result boundary check failed"));
}
result_data.get_inner_pointer()
} }
.cast::<c_void>(); .cast::<c_void>();
@ -130,31 +127,31 @@ impl CallableData {
return SIZED_CALLERS[arg_len](self, result, args); 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 { let result_pointer = if self.result_info.size == 0 {
VOID_RESULT_PTR VOID_RESULT_PTR
} else { } else {
let result_data = result.get_ffi_data()?; result.get_ffi_data()?.get_inner_pointer()
if !result_data.check_inner_boundary(0, self.result_info.size) {
return Err(LuaError::external("Result boundary check failed"));
}
result_data.get_inner_pointer()
} }
.cast::<c_void>(); .cast::<c_void>();
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 let arg_value = args
.get(index) .get(index)
.ok_or_else(|| LuaError::external(format!("argument {index} required")))? .ok_or_else(|| LuaError::external(format!("Argument {index} required")))?
.as_userdata() .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::<RefData>()?;
if let Ok(arg_ref) = arg_value.borrow::<RefData>() {
arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>()); arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>());
} else {
return Err(LuaError::external("Argument should be a RefData"));
}
} }
// Call libffi::raw::ffi_call
ffi_call( ffi_call(
self.cif, self.cif,
Some(*self.code.as_safe_fun()), Some(*self.code.as_safe_fun()),
@ -172,7 +169,7 @@ impl LuaUserData for CallableData {
LuaMetaMethod::Call, LuaMetaMethod::Call,
|_lua, this: &CallableData, mut args: LuaMultiValue| { |_lua, this: &CallableData, mut args: LuaMultiValue| {
let result = args.pop_front().ok_or_else(|| { 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) } unsafe { this.call(result, args) }
}, },

View file

@ -1,32 +1,32 @@
local ffi = require("@lune/ffi") local ffi = require("@lune/ffi")
local c = ffi.c local c = ffi.c
assert(typeof(c.int) :: string == "CType") assert(typeof(c.int) :: string == "CTypeInfo")
assert(tostring(c.int) == "int") 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:ptr()) == "int")
assert(tostring(c.int:arr(5):ptr()) == " <CArr( int, length = 5 )> ") assert(tostring(c.int:arr(5):ptr()) == " <CArrInfo( int, length = 5 )> ")
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:arr(5)) == " int, length = 5 ")
assert(tostring(c.int:ptr():arr(5)) == " <CPtr(int)>, length = 5 ") assert(tostring(c.int:ptr():arr(5)) == " <CPtrInfo(int)>, 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 }, c.int)) == " (int) -> int ")
assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ") assert(tostring(c.fn({ c.int, ffi.f32 }, c.int)) == " (int, f32) -> int ")
assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " (<CPtr(int)>) -> int ") assert(tostring(c.fn({ c.int:ptr() }, c.int)) == " (<CPtrInfo(int)>) -> int ")
assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> <CPtr(int)> ") assert(tostring(c.fn({ c.int }, c.int:ptr())) == " (int) -> <CPtrInfo(int)> ")
assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " (<CPtr(int)>) -> <CPtr(int)> ") assert(tostring(c.fn({ c.int:ptr() }, c.int:ptr())) == " (<CPtrInfo(int)>) -> <CPtrInfo(int)> ")
assert( assert(
tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr())) tostring(c.fn({ c.int:ptr(), c.int:ptr() }, c.int:ptr()))
== " (<CPtr(int)>, <CPtr(int)>) -> <CPtr(int)> " == " (<CPtrInfo(int)>, <CPtrInfo(int)>) -> <CPtrInfo(int)> "
) )
assert(typeof(c.struct({ c.int, c.char })) :: string == "CStruct") assert(typeof(c.struct({ c.int, c.char })) :: string == "CStructInfo")
assert( assert(
tostring(c.struct({ c.int, c.char:ptr() })) tostring(c.struct({ c.int, c.char:ptr() }))
== ` int, <CPtr(char)>, size = {c.struct({ c.int, c.char:ptr() }).size} ` == ` int, <CPtrInfo(char)>, size = {c.struct({ c.int, c.char:ptr() }).size} `
) )
-- FIXME: add box, ref pretty-print test -- FIXME: add box, ref pretty-print test