-1

I have a function which is written in C++ that will be called from Rust. This function constructs an array and must return it to Rust:

main.rs

extern crate libc;

use libc::c_void;

extern {
    fn construct_array(arr_ptr: *mut u32, arr_size: u32) -> c_void;
}

fn main() {
    let arr_size: usize = 4;
    let mut arr: Vec<u32> = Vec::with_capacity(arr_size);

    unsafe {
        construct_array(arr.as_mut_ptr(), arr_size as u32);
        let result = std::slice::from_raw_parts(arr.as_mut_ptr(), arr_size);
        println!("Result from rust {:?}", result);
    }
}

funcs.cpp

extern "C" void construct_array(uint32_t* arr_ptr, uint32_t arr_size) {
    uint32_t arr[arr_size];

    for (uint32_t i = 0; i < arr_size; i++) {
        arr[i] = i;
    }

    // Print array items
    printf("Result from c++ [");
    printf("%u", arr[0]);
    for (uint32_t i = 1; i < arr_size; i++) {
        printf(", %u", arr[i]);
    }
    printf("]\n");

    arr_ptr = &arr[0];
}

However, when I run it, the following gets printed:

$ cargo run
Result from c++ [0, 1, 2, 3]
Result from rust [0, 0, 0, 0]

How can I correctly construct an array in C++ and pass it to Rust via FFI?

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Octav
  • 53
  • 1
  • 9
  • `construct_array` is returning a pointer to a local automatic variable, that will immediately vanish when the function finishes. That will be Undefined Behavior in C or C++. In Rust it will not compile easily... – rodrigo Jul 14 '18 at 10:54

1 Answers1

2

Your problem can be demonstrated in C++ alone:

int main() {
    uint32_t foo[12];
    construct_array(foo, 12);

    printf("Actual result from C++:");
    for (auto i = 0; i < 12; ++i) printf("%u\n", foo[i]);
}

This prints garbage, and comes from the way you are "copying" your array:

arr_ptr = &arr[0];

This will assign the address of the array to the local variable arr_ptr and do nothing with it. Even if this worked, you'd let the address of a local array escape, and that would be UB. Instead, you can just skip the arr buffer and use the array passed to your function directly:

extern "C" void construct_array(uint32_t* arr_ptr, uint32_t arr_size) {
    for (uint32_t i = 0; i < arr_size; i++) {
        arr_ptr[i] = i;
    }

    // Print array items
    printf("Result from c++ [");
    printf("%u", arr_ptr[0]);
    for (uint32_t i = 1; i < arr_size; i++) {
        printf(", %u", i);
    }
    printf("]\n");
}
mcarton
  • 27,633
  • 5
  • 85
  • 95