fix crash when trying to load and ffi library with an invalid type specification

This commit is contained in:
Bennet Bleßmann
2025-01-21 23:37:47 +01:00
committed by Bennet Bleßmann
parent db3f2717bc
commit 34eab2e73a
3 changed files with 46 additions and 11 deletions

View File

@@ -80,8 +80,11 @@ impl ForeignFunctionTable {
self.table.extend(other.table); self.table.extend(other.table);
} }
pub fn define_struct(&mut self, name: &str, atom_fields: Vec<Atom>) { pub fn define_struct(&mut self, name: &str, atom_fields: Vec<Atom>) -> Result<(), FFIError> {
let mut fields: Vec<_> = atom_fields.iter().map(|x| self.map_type_ffi(x)).collect(); let mut fields: Vec<_> = atom_fields
.iter()
.map(|x| self.map_type_ffi(x))
.collect::<Result<_, FFIError>>()?;
fields.push(std::ptr::null_mut::<ffi_type>()); fields.push(std::ptr::null_mut::<ffi_type>());
let struct_type = ffi_type { let struct_type = ffi_type {
type_: STRUCT, type_: STRUCT,
@@ -96,10 +99,11 @@ impl ForeignFunctionTable {
atom_fields, atom_fields,
}, },
); );
Ok(())
} }
fn map_type_ffi(&mut self, source: &Atom) -> *mut ffi_type { fn map_type_ffi(&mut self, source: &Atom) -> Result<*mut ffi_type, FFIError> {
match source { Ok(match source {
atom!("sint64") => addr_of_mut!(types::sint64), atom!("sint64") => addr_of_mut!(types::sint64),
atom!("sint32") => addr_of_mut!(types::sint32), atom!("sint32") => addr_of_mut!(types::sint32),
atom!("sint16") => addr_of_mut!(types::sint16), atom!("sint16") => addr_of_mut!(types::sint16),
@@ -116,9 +120,9 @@ impl ForeignFunctionTable {
atom!("f64") => addr_of_mut!(types::double), atom!("f64") => addr_of_mut!(types::double),
struct_name => match self.structs.get_mut(&*struct_name.as_str()) { struct_name => match self.structs.get_mut(&*struct_name.as_str()) {
Some(ref mut struct_type) => &mut struct_type.ffi_type, Some(ref mut struct_type) => &mut struct_type.ffi_type,
None => unreachable!(), None => return Err(FFIError::InvalidFFIType),
}, },
} })
} }
pub(crate) fn load_library( pub(crate) fn load_library(
@@ -133,18 +137,22 @@ impl ForeignFunctionTable {
let symbol_name: CString = CString::new(function.name.clone())?; let symbol_name: CString = CString::new(function.name.clone())?;
let code_ptr: Symbol<*mut c_void> = let code_ptr: Symbol<*mut c_void> =
library.get(&symbol_name.into_bytes_with_nul())?; library.get(&symbol_name.into_bytes_with_nul())?;
let mut args: Vec<_> = function.args.iter().map(|x| self.map_type_ffi(x)).collect(); let mut args: Vec<_> = function
.args
.iter()
.map(|x| self.map_type_ffi(x))
.collect::<Result<_, FFIError>>()?;
let mut cif: ffi_cif = Default::default(); let mut cif: ffi_cif = Default::default();
prep_cif( prep_cif(
&mut cif, &mut cif,
ffi_abi_FFI_DEFAULT_ABI, ffi_abi_FFI_DEFAULT_ABI,
args.len(), args.len(),
self.map_type_ffi(&function.return_value), self.map_type_ffi(&function.return_value)?,
args.as_mut_ptr(), args.as_mut_ptr(),
) )
.unwrap(); .unwrap();
let return_struct_name = if (*self.map_type_ffi(&function.return_value)).type_ let return_struct_name = if (*self.map_type_ffi(&function.return_value)?).type_
as u32 as u32
== libffi::raw::FFI_TYPE_STRUCT == libffi::raw::FFI_TYPE_STRUCT
{ {
@@ -532,3 +540,11 @@ pub enum FFIError {
FunctionNotFound, FunctionNotFound,
StructNotFound, StructNotFound,
} }
impl std::fmt::Display for FFIError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl Error for FFIError {}

View File

@@ -5148,7 +5148,11 @@ impl Machine {
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
self.foreign_function_table self.foreign_function_table
.define_struct(&struct_name.as_str(), fields); .define_struct(&struct_name.as_str(), fields)
.map_err(|err| {
let ffi_error = self.machine_st.ffi_error(err);
self.machine_st.error_form(ffi_error, stub_gen())
})?;
return Ok(()); return Ok(());
} }
self.machine_st.fail = true; self.machine_st.fail = true;

View File

@@ -163,7 +163,22 @@ fn ffi_return_values() {
// but there is currently no other easy way to get the dynamic library file path as an input into a load_module_test test // but there is currently no other easy way to get the dynamic library file path as an input into a load_module_test test
std::env::set_var("ffi_return_values_LIB", dynlib_path); std::env::set_var("ffi_return_values_LIB", dynlib_path);
// FIXME u32 and u64 have an incorrect result // i8- -42,u8-73,i16- -3054,u16-49374,i32- -200211438,u32-3235819520,i64- -859901580039547648,u64- 859901580039547648,f32-3.1415927410125732,f64-6.283185307179586
let expected = format!(
"i8- {},u8-{},i16- {},u16-{},i32- {},u32-{},i64- {},u64- {},f32-{},f64-{}",
-42,
73,
-0xBEE,
0xC0DE,
-0xBEEFBEE,
0xC0DEB000u32,
-0xBEEFBEE5C0DEB00i64,
0xBEEFBEE5C0DEB00u64,
std::f32::consts::PI as f64,
std::f64::consts::TAU
);
// FIXME all but u8, f32 and f64 are wrong!?!?
load_module_test( load_module_test(
"tests-pl/ffi_return_values.pl", "tests-pl/ffi_return_values.pl",
"i8-214,u8-73,i16-18,u16-222,i32-18,u32-0,i64-0,u64- -4789548415587584,f32-3.1415927410125732,f64-6.283185307179586", "i8-214,u8-73,i16-18,u16-222,i32-18,u32-0,i64-0,u64- -4789548415587584,f32-3.1415927410125732,f64-6.283185307179586",