From: Skgland Date: Fri, 8 Aug 2025 20:45:24 +0000 (+0200) Subject: allow passing a null through a cstr arg/return X-Git-Tag: v0.10.0~29^2 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=e1a52a4dde85a260f574d25ea4eaf14369c518c2;p=scryer-prolog.git allow passing a null through a cstr arg/return --- diff --git a/src/ffi.rs b/src/ffi.rs index ad55e54e..36f290ff 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -80,8 +80,18 @@ impl FunctionImpl { } unsafe fn call_cstr(&self, args: &[Arg], _: &mut Arena) -> Result { - let ptr = unsafe { self.cif.call::<*mut c_char>(self.code_ptr, args) }; - Ok(Value::CString(unsafe { CStr::from_ptr(ptr) }.to_owned())) + let ptr = unsafe { + self.cif + .call::>>(self.code_ptr, args) + }; + + if let Some(cstr) = ptr { + Ok(Value::CString( + unsafe { CStr::from_ptr(cstr.as_ptr()) }.to_owned(), + )) + } else { + Ok(Value::Number(Number::Fixnum(Fixnum::build_with(0)))) + } } unsafe fn call_struct( @@ -353,7 +363,7 @@ impl<'args, 'val> PointerArgs<'args, 'val> { ArgValue::I64(a) => libffi::middle::arg(a), ArgValue::F32(a) => libffi::middle::arg(a), ArgValue::F64(a) => libffi::middle::arg(a), - ArgValue::Ptr(ptr, _) => unsafe { std::mem::transmute::<*mut c_void, Arg>(*ptr) }, + ArgValue::Ptr(ptr, _) => Arg::new(ptr), ArgValue::Struct(s) => unsafe { std::mem::transmute::<*mut c_void, Arg>(s.ptr.as_ptr()) }, @@ -653,7 +663,7 @@ impl Value { fn as_ptr(&mut self) -> Result<*mut c_void, FfiError> { match self { - Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void), + Value::CString(ref mut cstr) => Ok(cstr.as_ptr().cast_mut().cast()), Value::Number(Number::Fixnum(fixnum)) => Ok(std::ptr::with_exposed_provenance_mut( fixnum.get_num() as usize, )), diff --git a/tests-pl/ffi_cstr.pl b/tests-pl/ffi_cstr.pl index 08de6a73..4e6fb505 100644 --- a/tests-pl/ffi_cstr.pl +++ b/tests-pl/ffi_cstr.pl @@ -1,16 +1,21 @@ :- use_module(library(os)). :- use_module(library(ffi)). -test :- +init :- read(Body), term_variables(Body, [LIB]), Body, use_foreign_module(LIB, [ 'ffi_cstr_len'([cstr], u64), - 'ffi_example_cstr'([], cstr) - ]), + 'ffi_example_cstr'([], cstr), + 'ffi_null_cstr'([], cstr) + ]). + +test :- ffi:'ffi_cstr_len'("Scryer Prolog", Len), ffi:'ffi_example_cstr'(Str), - write((Len-Str)). + ffi:'ffi_null_cstr'(Null), + ffi:'ffi_cstr_len'(0, MaxU64), + write((Len-Str-Null-MaxU64)). -:- initialization(test). +:- initialization((init,test)). diff --git a/tests/scryer/ffi.rs b/tests/scryer/ffi.rs index fc8f4ad6..c9e0aa1e 100644 --- a/tests/scryer/ffi.rs +++ b/tests/scryer/ffi.rs @@ -257,20 +257,29 @@ fn ffi_cstr() { use std::ffi::CStr; #[unsafe(no_mangle)] - extern "C" fn ffi_cstr_len(c_str: *const core::ffi::c_char) -> u64 { - unsafe { CStr::from_ptr(c_str) }.count_bytes() as u64 + extern "C" fn ffi_cstr_len(c_str: Option>) -> u64 { + if let Some(c_str) = c_str { + unsafe { CStr::from_ptr(c_str.as_ptr()) }.count_bytes() as u64 + } else { + u64::MAX + } } #[unsafe(no_mangle)] extern "C" fn ffi_example_cstr() -> *const core::ffi::c_char { c"Rust Lang".as_ptr() } + + #[unsafe(no_mangle)] + extern "C" fn ffi_null_cstr() -> *const core::ffi::c_char { + std::ptr::null() + } "##, ); load_module_test_with_input( "tests-pl/ffi_cstr.pl", format!("LIB={dynlib_path:?}."), - r#"13-[R,u,s,t, ,L,a,n,g]"#, + format!(r#"13-[R,u,s,t, ,L,a,n,g]-0-{}"#, u64::MAX).as_str(), ); }