From: Skgland Date: Sun, 17 Aug 2025 15:35:57 +0000 (+0200) Subject: make ffi error structure not found point to the correct culprit X-Git-Tag: v0.10.0~11^2~10 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=3b5b768f4a1d3b3d3cf71f1c6e68a73aeba1a237;p=scryer-prolog.git make ffi error structure not found point to the correct culprit --- diff --git a/src/ffi.rs b/src/ffi.rs index 0cb38189..3bd27557 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -104,7 +104,7 @@ impl FunctionImpl { ) -> Result { let struct_type = structs_table .get(&*return_type_name.as_str()) - .ok_or(FfiError::StructNotFound)?; + .ok_or(FfiError::StructNotFound(return_type_name))?; let ffi_type = unsafe { *struct_type.ffi_type.as_raw_ptr() }; let layout = Layout::from_size_align(ffi_type.size, ffi_type.alignment.into()) @@ -175,10 +175,8 @@ struct StructImpl { } impl StructImpl { - - fn layout(&self) -> Result { - let ffi_type = unsafe {*self.ffi_type.as_raw_ptr()}; + let ffi_type = unsafe { *self.ffi_type.as_raw_ptr() }; Layout::from_size_align(ffi_type.size, ffi_type.alignment.into()) .map_err(|_| FfiError::LayoutError) } @@ -190,10 +188,7 @@ impl StructImpl { ) -> Result { let args = ArgValue::build_args(struct_args, &self.fields, structs_table)?; - let alloc = FfiStruct::new( - self.layout()?, - FfiAllocator::Rust - )?; + let alloc = FfiStruct::new(self.layout()?, FfiAllocator::Rust)?; let Ok(mut current_layout) = Layout::from_size_align(0, 1) else { return Err(FfiError::LayoutError); @@ -321,7 +316,7 @@ impl StructImpl { FfiType::F64 => read_float::(ptr, &mut layout), FfiType::Struct(substruct) => { let Some(substruct_type) = struct_table.get(&*substruct.as_str()) else { - return Err(FfiError::StructNotFound); + return Err(FfiError::StructNotFound(*substruct)); }; let ffi_type = *substruct_type.ffi_type.as_raw_ptr(); @@ -350,7 +345,6 @@ impl StructImpl { } } - struct PointerArgs<'a, 'val> { memory: Vec, phantom: PhantomData<&'a mut ArgValue<'val>>, @@ -451,7 +445,7 @@ impl FfiType { Self::F64 => libffi::middle::Type::f64(), Self::Struct(struct_name) => structs_table .get(&*struct_name.as_str()) - .ok_or(FfiError::StructNotFound)? + .ok_or(FfiError::StructNotFound(struct_name))? .ffi_type .clone(), }) @@ -500,7 +494,7 @@ impl<'val> ArgValue<'val> { } let Some(struct_type) = structs_table.get(name) else { - return Err(FfiError::StructNotFound); + return Err(FfiError::StructNotFound(*atom)); }; Ok(Self::Struct(struct_type.build(structs_table, args)?)) @@ -534,7 +528,7 @@ struct FfiStruct { #[derive(Debug, Clone, Copy)] pub(crate) enum FfiAllocator { Rust, - C + C, } impl TryFrom for FfiAllocator { @@ -544,24 +538,19 @@ impl TryFrom for FfiAllocator { match value { atom!("rust") => Ok(Self::Rust), atom!("c") => Ok(Self::C), - _ => Err(()) + _ => Err(()), } } } impl FfiAllocator { - /// # Safety /// /// - layout must not have a size of 0 unsafe fn alloc(self, layout: Layout) -> Result, FfiError> { let ptr = match self { - FfiAllocator::Rust => { - unsafe { alloc::alloc(layout).cast() } - }, - FfiAllocator::C => { - unsafe { libc::malloc(layout.size()) } - }, + FfiAllocator::Rust => unsafe { alloc::alloc(layout).cast() }, + FfiAllocator::C => unsafe { libc::malloc(layout.size()) }, }; NonNull::new(ptr).ok_or(FfiError::AllocationFailed) @@ -574,15 +563,19 @@ impl FfiAllocator { unsafe fn dealloc(self, layout: Layout, ptr: NonNull) { match self { FfiAllocator::Rust => unsafe { alloc::dealloc(ptr.as_ptr().cast(), layout) }, - FfiAllocator::C => unsafe {libc::free(ptr.as_ptr())}, + FfiAllocator::C => unsafe { libc::free(ptr.as_ptr()) }, } } } impl FfiStruct { fn new(layout: Layout, allocator: FfiAllocator) -> Result { - assert_ne!(layout.size() , 0); - Ok(FfiStruct { ptr: unsafe { allocator.alloc(layout) }?, layout , allocator}) + assert_ne!(layout.size(), 0); + Ok(FfiStruct { + ptr: unsafe { allocator.alloc(layout) }?, + layout, + allocator, + }) } } @@ -684,17 +677,23 @@ impl ForeignFunctionTable { allocator: FfiAllocator, kind: Atom, mut args: Value, - arena: &mut Arena + arena: &mut Arena, ) -> Result { - - fn allocate_primitive(allocator: FfiAllocator, initial_value: T, arena: &mut Arena) -> Result { - const { assert!(std::mem::size_of::() != 0)}; + fn allocate_primitive( + allocator: FfiAllocator, + initial_value: T, + arena: &mut Arena, + ) -> Result { + const { assert!(std::mem::size_of::() != 0) }; let ptr = unsafe { allocator.alloc(Layout::new::()) }?; unsafe { ptr.cast::().write(initial_value) }; - Ok(Value::Number(fixnum!(Number, ptr.as_ptr().expose_provenance(), arena))) + Ok(Value::Number(fixnum!( + Number, + ptr.as_ptr().expose_provenance(), + arena + ))) } - match FfiType::from_atom(&kind) { FfiType::Void => Err(FfiError::InvalidFfiType), FfiType::Bool => { @@ -705,72 +704,46 @@ impl ForeignFunctionTable { _ => return Err(FfiError::ValueOutOfRange), }; allocate_primitive::(allocator, init, arena) - }, - FfiType::U8 => { - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::I8 => { - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::U16 => { - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::I16 => { - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::U32 => { - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::I32 => { - - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::U64 => { - - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::I64 => { - allocate_primitive::(allocator, args.as_int()?, arena) - }, - FfiType::F32 => { - allocate_primitive::(allocator, args.as_float()? as f32, arena) - }, - FfiType::F64 => { - allocate_primitive::(allocator, args.as_float()?, arena) - }, - FfiType::Ptr => { - allocate_primitive::<*mut c_void>(allocator, args.as_ptr()?, arena) - }, + } + FfiType::U8 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::I8 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::U16 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::I16 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::U32 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::I32 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::U64 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::I64 => allocate_primitive::(allocator, args.as_int()?, arena), + FfiType::F32 => allocate_primitive::(allocator, args.as_float()? as f32, arena), + FfiType::F64 => allocate_primitive::(allocator, args.as_float()?, arena), + FfiType::Ptr => allocate_primitive::<*mut c_void>(allocator, args.as_ptr()?, arena), FfiType::CStr => Err(FfiError::InvalidFfiType), FfiType::Struct(_) => { let Some(struct_impl) = self.structs.get(&*kind.as_str()) else { - return Err(FfiError::InvalidStruct) + return Err(FfiError::InvalidStruct); }; - let (_, args) = args.as_struct()?; let ffi_struct = struct_impl.build(&self.structs, args)?; let ptr = ManuallyDrop::new(ffi_struct).ptr; - Ok(Value::Number(fixnum!(Number, ptr.as_ptr().expose_provenance(), arena))) - }, + Ok(Value::Number(fixnum!( + Number, + ptr.as_ptr().expose_provenance(), + arena + ))) + } } } - pub fn read_ptr( &mut self, kind: Atom, mut ptr: Value, - arena: &mut Arena + arena: &mut Arena, ) -> Result { - - unsafe fn read_int( - ptr: NonNull, - arena: &mut Arena, - ) -> Value + unsafe fn read_int(ptr: NonNull, arena: &mut Arena) -> Value where T: Copy + TryInto + MightNotFitInFixnum, Integer: From, @@ -782,128 +755,87 @@ impl ForeignFunctionTable { let ptr = ptr.as_ptr()?; let Some(ptr) = NonNull::new(ptr) else { - return Err(FfiError::ValueOutOfRange) + return Err(FfiError::ValueOutOfRange); }; match FfiType::from_atom(&kind) { FfiType::Void => Err(FfiError::InvalidFfiType), - FfiType::Bool | FfiType::U8 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::I8 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::U16 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::I16 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::U32 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::I32 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::U64 => { - - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::I64 => { - Ok(unsafe {read_int::(ptr, arena)}) - }, - FfiType::F32 => { - Ok(Value::Number(Number::Float((unsafe { ptr.cast::().read() } as f64) .into()))) - }, - FfiType::F64 => { - Ok(Value::Number(Number::Float(unsafe { ptr.cast::().read() }.into()))) - }, + FfiType::Bool | FfiType::U8 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::I8 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::U16 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::I16 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::U32 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::I32 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::U64 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::I64 => Ok(unsafe { read_int::(ptr, arena) }), + FfiType::F32 => Ok(Value::Number(Number::Float( + (unsafe { ptr.cast::().read() } as f64).into(), + ))), + FfiType::F64 => Ok(Value::Number(Number::Float( + unsafe { ptr.cast::().read() }.into(), + ))), FfiType::Ptr => { let addr = unsafe { ptr.cast::<*mut c_void>().read() }.expose_provenance(); Ok(Value::Number(fixnum!(Number, addr, arena))) - }, - FfiType::CStr => { - Ok(Value::CString(unsafe { CStr::from_ptr(ptr.as_ptr().cast()) }.to_owned())) - }, + } + FfiType::CStr => Ok(Value::CString( + unsafe { CStr::from_ptr(ptr.as_ptr().cast()) }.to_owned(), + )), FfiType::Struct(_) => { let Some(struct_impl) = self.structs.get(&*kind.as_str()) else { - return Err(FfiError::InvalidStruct) + return Err(FfiError::InvalidStruct); }; struct_impl.read(ptr.as_ptr(), &kind.as_str(), &self.structs, arena) - }, + } } } - pub fn deallocate( &mut self, allocator: FfiAllocator, kind: Atom, mut ptr: Value, ) -> Result<(), FfiError> { - fn deallocate_primitive(allocator: FfiAllocator, ptr: NonNull) { - const { assert!(std::mem::size_of::() != 0)}; + const { assert!(std::mem::size_of::() != 0) }; unsafe { allocator.dealloc(Layout::new::(), ptr) }; } let ptr = ptr.as_ptr()?; let Some(ptr) = NonNull::new(ptr) else { - return Err(FfiError::ValueOutOfRange) + return Err(FfiError::ValueOutOfRange); }; match FfiType::from_atom(&kind) { FfiType::Void => return Err(FfiError::InvalidFfiType), - FfiType::Bool => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::U8 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::I8 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::U16 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::I16 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::U32 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::I32 => { - - deallocate_primitive::(allocator, ptr) - }, - FfiType::U64 => { - - deallocate_primitive::(allocator, ptr) - }, - FfiType::I64 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::F32 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::F64 => { - deallocate_primitive::(allocator, ptr) - }, - FfiType::Ptr => { - deallocate_primitive::<*mut c_void>(allocator, ptr) - }, + FfiType::Bool => deallocate_primitive::(allocator, ptr), + FfiType::U8 => deallocate_primitive::(allocator, ptr), + FfiType::I8 => deallocate_primitive::(allocator, ptr), + FfiType::U16 => deallocate_primitive::(allocator, ptr), + FfiType::I16 => deallocate_primitive::(allocator, ptr), + FfiType::U32 => deallocate_primitive::(allocator, ptr), + FfiType::I32 => deallocate_primitive::(allocator, ptr), + FfiType::U64 => deallocate_primitive::(allocator, ptr), + FfiType::I64 => deallocate_primitive::(allocator, ptr), + FfiType::F32 => deallocate_primitive::(allocator, ptr), + FfiType::F64 => deallocate_primitive::(allocator, ptr), + FfiType::Ptr => deallocate_primitive::<*mut c_void>(allocator, ptr), FfiType::CStr => return Err(FfiError::InvalidFfiType), FfiType::Struct(_) => { let Some(struct_impl) = self.structs.get(&*kind.as_str()) else { - return Err(FfiError::InvalidStruct) + return Err(FfiError::InvalidStruct); }; let layout = struct_impl.layout()?; - drop(FfiStruct { ptr, layout, allocator}) - }, + drop(FfiStruct { + ptr, + layout, + allocator, + }) + } } Ok(()) } @@ -971,7 +903,7 @@ pub enum FfiError { InvalidFfiType, InvalidStruct, FunctionNotFound, - StructNotFound, + StructNotFound(Atom), ArgCountMismatch, AllocationFailed, // LayoutError should never occour diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 208dc46e..b8e23981 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -622,13 +622,29 @@ impl MachineState { FfiError::InvalidArgument => atom!("invalid_argument"), FfiError::InvalidStruct => atom!("invalid_struct"), FfiError::FunctionNotFound => atom!("function_not_found"), - FfiError::StructNotFound => atom!("struct_not_found"), + FfiError::StructNotFound(culprit) => { + let stub = functor!( + atom!("ffi_error"), + [ + atom_as_cell((atom!("struct_not_found"))), + atom_as_cell(culprit) + ] + ); + + return MachineError { + stub, + location: None, + }; + } FfiError::ArgCountMismatch => atom!("mismatched_argument_count"), FfiError::AllocationFailed => atom!("allocation_failed"), FfiError::LayoutError => atom!("layout_error"), FfiError::UnsupportedAbi => atom!("unsupported_abi"), }; - let stub = functor!(atom!("ffi_error"), [atom_as_cell(error_atom), cell(culprit)]); + let stub = functor!( + atom!("ffi_error"), + [atom_as_cell(error_atom), cell(culprit)] + ); MachineError { stub,