where as you can see, my_struct has a ptr member of type char*
I did this on Rust:
struct MyStruct {
ptr: *mut libc::c_char
}
then
unsafe{*my_struct}.ptr = Box::into_raw(my_data) as *mut libc::c_char
where obviously my_struct: *mut MyStruct and my_data: MyData, an arbitraty type.
Then, to access this pointer, I do
let m: &mut MyData = unsafe{(*my_struct).ptr as *mut MyData}.unwrap()
but I'm getting either an unwrap or a segfault in this line above, I can´t debug cause it's a dinamically loadable C function into a non debugabble C program.
Did I do things right?
Here's the actual MyStruct:
I need to do my_struct->ptr = (char*) data in Rust for this .ptr
Where is your *mut MyStruct coming from? Lifetime of MyStruct also needs to be managed somehow, and it may be a dangling pointer (regardless of its content).
BTW:
#[repr(C)]
struct MyStruct {
data: Box<MyData>,
}
is binary-compatible with C struct with a char* field, and you can use that type in FFI while telling C that it's char*.
It's a very weird and dangerous way to make a MyStruct pointer. &mut is a temporary loan of a value, and it has to borrow from somewhere. Normally Rust won't let you borrow from an invalid place, but you're using a raw pointer to bypass this protection.
In your case the location you're borrowing from is a temporary on-stack value, and it becomes invalidated after the end of its temporary scope, so you're getting a dangling pointer to stack space
Note that Rust doesn't have a GC, and doesn't implicitly allocate anything on the heap, so unlike Java, C# or ObjC, a MyStruct instance isn't any kind of an object with an address. It's a bunch of bytes without a permanent location.
If *mut MyStruct needs to be a usable pointer that the FFI side can rely on having an address and live for longer than temporary scope of a variable, then you may need to create Box<MyStruct> and into_raw it the same way you do for MyData.
If you can use an on-stack MyStruct (i.e. FFI side doesn't keep the pointer, doesn't try to free it), then use this:
the example was just for reducing my problem to a compilation error. On real life, MySQL passes me a pointer to MyStruct, and MySQL itself is responsible for the life of this pointer, so I can do
unsafe{*my_struct}.ptr = Box::into_raw(my_data) as *mut libc::c_char;
because I've disabled MyData destruction on this scope. When MySQL wants to destroy MyStruct* it tell me so I can do Box::from_raw and thus drop my_data.
Per the Rust Reference, an unsafe { ... } block is just a variation of a regular block expression { ... }. And further up the same page, it notes:
Blocks are always value expressions and evaluate the last operand in value expression context.
The distinction between place expressions and value expressions is important here. They roughly correspond to lvalues and rvalues in C/C++. Since *my_struct is a place expression, unsafe { *my_struct }will copy the value:
When a place expression is evaluated in a value expression context, or is bound by value in a pattern, it denotes the value held in that memory location. If the type of that value implements Copy, then the value will be copied.
Finally, the place expression unsafe { *my_struct }.ptr refers to the ptr field of the unnamed temporary variable that has a copy of my_struct, and assigning to it writes only to the temporary, not to the original. To write to the original my_struct pointer, the full unsafe { (*my_struct).ptr = ...; } is necessary.