I have this rust method:
/* Define a python method on a given module */
pub fn method(data: *mut Struct_ppyData, module: ~str, method: ~str, callback: PyCFunction, flags: Method, help: ~str) {
let mbytes = module.to_c_str().with_mut_ref(|a: * mut c_char| { a });
let fbytes = method.to_c_str().with_mut_ref(|b: * mut c_char| { b });
let dbytes = help.to_c_str().with_mut_ref(|c: * mut c_char| { c });
println!("Incoming! {} {} {}\n", module, method, help);
println!("Invoking! {} {} {}\n", mbytes, fbytes, dbytes);
let cflags = flags as c_int;
unsafe {
ppy_method(data, mbytes, fbytes, callback, cflags, dbytes);
}
}
And the output I get is:
Incoming! yyy xxx A callback.
Invoking! 0x7f85084077d0 0x7f85084077d0 0x7f85084077d0
What? That's what the ffi c call sees too:
Received a value
Pointer: 7f85084077d0
length: 11
--------> value: A callback.
Received a value
Pointer: 7f85084077d0
length: 11
--------> value: A callback.
Received a value
Pointer: 7f85084077d0
length: 11
--------> value: A callback.
Why on earth are the values of mbytes, fbytes and dbytes all the same? O_o
What you are doing is unsafe, and it is tripping you up.
module.to_c_str()
allocates space for aCString
. Callingwith_mut_ref
on that gives an unsafe pointer (*T
or*mut T
) to thatCString
—but that*mut c_char
is only valid for the closure that you pass in. You have kept it alive beyond the end of the closure, and so all bets are off; as it is, theCString
is immediately freed after that expression, because it is not stored anywhere. In consequence, you have a dangling unsafe pointer (*T
are called unsafe for a reason!). Then, the next line goes making a similar allocation and lo! it is in the same place. End result: three identical pointers, all pointing to the same junk data.What you should do instead, if you do in fact need such an unsafe pointer, is to nest the things.
Also, as observed by dbaupp, you don't need to take ownership of the strings; you might as well use
&str
instead of~str
.