]> Repositorios git - scryer-prolog.git/commitdiff
fix crash when trying to load and ffi library with an invalid type specification
authorBennet Bleßmann <[email protected]>
Tue, 21 Jan 2025 22:37:47 +0000 (23:37 +0100)
committerBennet Bleßmann <[email protected]>
Fri, 1 Aug 2025 16:22:15 +0000 (18:22 +0200)
src/ffi.rs
src/machine/system_calls.rs
tests/scryer/ffi.rs

index 55bb525b37cef87804c0fcda10d92b87ccccd41c..926a14ec471d696c5d256c9f9ab9828fa5f7617d 100644 (file)
@@ -80,8 +80,11 @@ impl ForeignFunctionTable {
         self.table.extend(other.table);
     }
 
-    pub fn define_struct(&mut self, name: &str, atom_fields: Vec<Atom>) {
-        let mut fields: Vec<_> = atom_fields.iter().map(|x| self.map_type_ffi(x)).collect();
+    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::<Result<_, FFIError>>()?;
         fields.push(std::ptr::null_mut::<ffi_type>());
         let struct_type = ffi_type {
             type_: STRUCT,
@@ -96,10 +99,11 @@ impl ForeignFunctionTable {
                 atom_fields,
             },
         );
+        Ok(())
     }
 
-    fn map_type_ffi(&mut self, source: &Atom) -> *mut ffi_type {
-        match source {
+    fn map_type_ffi(&mut self, source: &Atom) -> Result<*mut ffi_type, FFIError> {
+        Ok(match source {
             atom!("sint64") => addr_of_mut!(types::sint64),
             atom!("sint32") => addr_of_mut!(types::sint32),
             atom!("sint16") => addr_of_mut!(types::sint16),
@@ -116,9 +120,9 @@ impl ForeignFunctionTable {
             atom!("f64") => addr_of_mut!(types::double),
             struct_name => match self.structs.get_mut(&*struct_name.as_str()) {
                 Some(ref mut struct_type) => &mut struct_type.ffi_type,
-                None => unreachable!(),
+                None => return Err(FFIError::InvalidFFIType),
             },
-        }
+        })
     }
 
     pub(crate) fn load_library(
@@ -133,18 +137,22 @@ impl ForeignFunctionTable {
                 let symbol_name: CString = CString::new(function.name.clone())?;
                 let code_ptr: Symbol<*mut c_void> =
                     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();
                 prep_cif(
                     &mut cif,
                     ffi_abi_FFI_DEFAULT_ABI,
                     args.len(),
-                    self.map_type_ffi(&function.return_value),
+                    self.map_type_ffi(&function.return_value)?,
                     args.as_mut_ptr(),
                 )
                 .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
                     == libffi::raw::FFI_TYPE_STRUCT
                 {
@@ -532,3 +540,11 @@ pub enum FFIError {
     FunctionNotFound,
     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 {}
index 8c0eee0a78d651db5909fc66369b963d4ae1f8f1..307ca648ded9ba39e18c932ddb18f945d8e41c89 100644 (file)
@@ -5148,7 +5148,11 @@ impl Machine {
                 Err(e) => return Err(e),
             };
             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(());
         }
         self.machine_st.fail = true;
index 04bef2cf490d0db84cfc25c231d0717bfe4d0d25..e79e636d6e59c230ce48d2fc87d5417d48483c11 100644 (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
     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(
         "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",