Hey there,
This is a repost from this reddit post.
After playing around in safe rust for a few projects I decided to attempt to do something more serious, porting a C++ library from my work to rust. Somethings have worked out of the box, some not so much. Here is the problem:
I have the following data struct in C++:
struct SomeStruct {
string data
double value
}
and the following signitures:
void* start(string, size_t, SomeStruct[])
void step(size_t, size_t, SomeStruct[], SomeStruct[], void*)
dealocate(void*)
In rust SomeStruct became:
#[repr(C)]
struct SomeStruct {
data: CString,
value: f64
}
So, my questions function by function:
start
I rewrote it as:
#[no_mangle]
pub extern fn start(xml: CString, size: usize, array: *const SomeStruct) -> *mut c_void
I have the following problems:
If I use this code inside it:
let someString = xml.into_string().unwrap();
println!("string: {:?}", someString);
...
and call it in C++:
extern "C" {
void* start(string, size_t, SomeString*);
}
start("text", 0, nullptr);
I get the output
string: ""
i.e., it reads as an empty string. And what's worst, it seems like it's overflowing the argument stack or something like that, because if I try to print the size argument I end up getting some gibberish.
But what I really found interesting is that if I remove this argument from the function signature (of course both on rust and C++) and actually pass something to size and array and print the CString inside SomeStruct it will work fine. Why is that?
I also tried calling it from C++ using the c_str() for the string (changing the function parameter signature to const char*), but got the same results.
Finally, the return type. The output from start should be passed to step and dealocate. It's a pointer to an allocated memory space containing the state of the library. I was able to replicate this behavior by creating some state inside the library (by creating some random struct) and using transmuting it at the end of the function:
start(...) -> *mut c_void {
...
let someState = State {...};
unsafe {transmute(someState)}
}
step
Step became:
#[no_mangle]
pub extern step(size1: usize, size2: usize, array1: *const SomeStruct, array2: *const SomeStruct, ptr: *mut c_void) -> ()
I seem to be able to read the state from the start function just fine by transmuting it back. But I read everywhere that transmute is overkill in most cases. What is the non-overkill way of doing this? and how it actually works?
dealocate
#[no_mangle]
pub extern dealocate(ptr: *mut c_void) -> ()
And finally, how should I implement the dealocate function? As in, how to make sure in rust that the whater the void pointer points to is dropped?
Thanks!