Why are all my pointers pointing to the same place with to_c_str() in rust?

StackOverflow https://stackoverflow.com//questions/23053398

  •  22-12-2019
  •  | 
  •  

Question

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

Was it helpful?

Solution

What you are doing is unsafe, and it is tripping you up.

module.to_c_str() allocates space for a CString. Calling with_mut_ref on that gives an unsafe pointer (*T or *mut T) to that CString—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, the CString 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.

/// 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) {
    module.to_c_str().with_mut_ref(|mbytes| {
        method.to_c_str().with_mut_ref(|fbytes| {
            help.to_c_str().with_mut_ref(|dbytes| {
                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);
                }
            })
        })
    })
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top