3

I need pass a vector of Rust string to a C variadic function. But I can't figure out what is the expected(CString, [u8]..) format.

References:

My api16 example code version:

strcpy (ids[0], "evento");
length = (short)  isc_event_block((char **) &event_buffer, (char **) &result_buffer, 1, ids[0], 0);
printf("event_buffer: '%s' %d\n", event_buffer, sizeof(event_buffer));
printf("result_buffer: '%s' %d\n", result_buffer, sizeof(result_buffer));

Result of version of api16:

event_buffer: 'evento' 8
result_buffer: '' 8

My Rust code:

let mut event_buffer: Vec<u8> = Vec::with_capacity(256);
let mut result_buffer: Vec<u8> = Vec::with_capacity(256);
let mut len = 0;
let names = "evento".to_string();

unsafe {
   len = self.ibase.isc_event_block()(
      event_buffer.as_mut_ptr() as *mut _,
      result_buffer.as_mut_ptr() as *mut _,
      names.len() as u16,
      names.as_ptr()
   );
   event_buffer.set_len(len as usize);
   result_buffer.set_len(len as usize);
}

println!("{:?} {:?}", len, names);
println!("{:x?} {:x?}", event_buffer, result_buffer);
println!("{:?} {:?}", String::from_utf8_lossy(&event_buffer.clone()), String::from_utf8_lossy(&result_buffer.clone()));

Result of my Rust code:

12 ["evento"]
[e0, 4f, 51, 28, a8, 7f, 0, 0, 0, 0, 0, 0] [0, 50, 51, 28, a8, 7f, 0, 0, 0, 0, 0, 0]
"�OQ(�\u{7f}\0\0\0\0\0\0" "\0PQ(�\u{7f}\0\0\0\0\0\0"

I already tried use CString or CStr, like here.

What am I doing wrong?

1 Answer 1

3

You're doing multiple things wrong in the rust version. For the first two arguments, you're intended to pass a pointer to a location that can hold a single pointer to a byte buffer. Instead, you're passing in a pointer to a byte buffer, so a pointer is getting written into that buffer, which isn't what you want.

Secondly, the id_count parameter corresponds to the number of strings you're passing as the variadic parameters, rather than the length of a single variadic string, meaning your c code just reads a bunch of uninitialized memory, which definitely isn't what you want. Additionally, that string does need to be null-terminated, and it isn't in your example, you do need CString. What you really want is something like this:

use std::ffi::{c_char, c_long, c_ushort, CStr, CString};
use std::ptr;
use std::slice;
use std::str;
fn main() {
    let mut event_buffer = ptr::null_mut();
    let mut result_buffer = ptr::null_mut();
    let names = CString::new("evento").unwrap();
    let len = unsafe {
        isc_event_block(
            &mut event_buffer,
            &mut result_buffer,
            1,
            names.as_ptr() as *mut c_char,
        )
    };
    debug_assert!(!event_buffer.is_null() && !result_buffer.is_null());
    let event_slice = unsafe { slice::from_raw_parts(event_buffer.cast(), len as usize) };
    let result_slice = unsafe { slice::from_raw_parts(event_buffer.cast(), len as usize) };
    let event_str = str::from_utf8(event_slice).unwrap();
    let result_str = str::from_utf8(result_slice).unwrap();
    println!("event: {event_str}");
    println!("result: {result_str}");
}

Playground

Adding a simple stub to print the string passed in, and write a couple of strings into the buffers, I got this:

"evento"
event: some events
result: some events
Sign up to request clarification or add additional context in comments.

3 Comments

"Secondly, the id_count parameter corresponds to the number of strings" My fail. In my original code I use the names as a vec<String> instead a single String. I forgot to change here.
For a single CString your answer works like a charm, but how I can use Vec<CString> in this place?
@Batels You'll have to use libffi or similar to call it with a dynamic number of arguments. If you only have a small number of different expected arg counts, manually writing out each of the possibilities by hand is an option, too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.