2

I would like create a Rust FFI function that takes an out-parameter for arrays, analogous to this C function:

size_t arr_out_c(char ***out) {
    char *msg = "the quick brown fox";
    size_t STR_LEN = strlen(msg) +1;
    size_t count = 3;
    char** arr = calloc( count,  sizeof(char*));
    for (int i = 0; i < count; i++) {
        arr[i] = calloc(STR_LEN,  sizeof(char));
        strncpy(arr[i], msg, STR_LEN * sizeof(char));
    }
    *out = arr;
    return count;
}

Usage:

char** test;
size_t count = arr_out_c(&test);
for (int i = 0; i < count; i++) {
    printf("item: %s", test[i]);
}

I've gotten close with this:

#[no_mangle]
pub extern fn arr_out_rust(strings_out: *mut *mut *mut ::std::os::raw::c_char) -> usize {
    unsafe {
        let s1 = ::std::ffi::CString::new("the quick brown fox").unwrap();
        let s2 = ::std::ffi::CString::new("the quick brown fox").unwrap();
        let mut strs = vec![s1, s2];
        let len = strs.len();

        let mut boxed_slice = strs.into_boxed_slice();
        *strings_out = boxed_slice.as_mut_ptr() as *mut *mut ::std::os::raw::c_char;
        mem::forget(boxed_slice);
        len
    }
}

It works for the first item in the array, attempting to access the 2nd item results in a SEGV. Perhaps the CStrings are not getting packed in a contiguous block of memory... or maybe the len data in slice is part of that memory?

Also, to free this memory, can I just call the C free function on it in C space, or do I need to send it back into Rust space and call drop?

char** test;
size_t count = arr_out_rust(&test);
for (int i = 0; i < count; i++) {
    printf("item: %s", test[i]);
}

will print a single the quick brown fox, then crash.


While this question has some similarities to questions asking about returning strings to C, it's pretty unique in that it is asking about out-bound pointers in FFI. Marking it as a duplicate and closing it would go against the spirit of Stack Overflow as a repository of unique answers.

marathon
  • 7,881
  • 17
  • 74
  • 137
  • while the answer was similar, the question was not anywhere close to being the same. – marathon Aug 09 '17 at 22:47
  • Does that mean that you read the linked duplicates and solved your problem? That you cannot return a `CString` across the FFI boundary? – Shepmaster Aug 09 '17 at 23:01
  • For beginner FFI questions, I highly recommend reading my [Rust FFI Omnibus](http://jakegoulding.com/rust-ffi-omnibus/string_return/). – Shepmaster Aug 09 '17 at 23:05
  • Your general method of returning the array is just fine, therefore any answer to the question you *asked* would be "do exactly what you are doing". You didn't reduce your question enough to the core of the problem — returning `CString` instead of `* const c_char`. And yes, you always have to free Rust allocations back in Rust land. You will need to reconstitute the `Vec` and then let it drop. – Shepmaster Aug 09 '17 at 23:17

0 Answers0