]> Repositorios git - scryer-prolog.git/commitdiff
allow passing a null through a cstr arg/return
authorSkgland <[email protected]>
Fri, 8 Aug 2025 20:45:24 +0000 (22:45 +0200)
committerBennet Bleßmann <[email protected]>
Fri, 8 Aug 2025 20:45:24 +0000 (22:45 +0200)
src/ffi.rs
tests-pl/ffi_cstr.pl
tests/scryer/ffi.rs

index ad55e54e3d473000578fe89ca03aadaeda3081f4..36f290ffd9b62d62496e0f7cb8371ad7e233babd 100644 (file)
@@ -80,8 +80,18 @@ impl FunctionImpl {
     }
 
     unsafe fn call_cstr(&self, args: &[Arg], _: &mut Arena) -> Result<Value, FfiError> {
-        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::<Option<NonNull<c_char>>>(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,
             )),
index 08de6a73cc2bedcb390d08ce00545885714d7047..4e6fb5050f17aac1bd6bde4f92081d66f85b3667 100644 (file)
@@ -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)).
index fc8f4ad6dfc729aee8102eae3a8e8dce71667f4f..c9e0aa1ee801bd8e67e507082bdfb80610aa87ca 100644 (file)
@@ -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<std::ptr::NonNull<core::ffi::c_char>>) -> 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(),
     );
 }