-
Couldn't load subscription status.
- Fork 13.9k
Description
It's currently non-trivial to do a &[&str] -> **c_char conversion correctly; I think there should be a function in std::c_str that handles this (as well as optionally null terminating the **c_char).
v is a &[&str], f is a function taking a **c_char. I've put the types of intermediates for clarity.
Incorrect
a
v.as_imm_buf(|buf: *&str, _| f(buf as **c_char))The *&str → **c_char cast is wrong.
b
let ptrs: ~[*c_char] = v.map(|s: & &str| s.with_c_str(|cstr: *c_char| cstr));
ptrs.as_imm_buf(|buf: **c_char, _| f(buf))The *c_char from with_c_str shouldn't leave the closure, since it with_c_str allocates an internal buffer. (This is a general problem with methods that pass a raw pointer to a closure: it is extremely easy and tempting to just return that pointer immediately and thus (possibly) create a dangling reference.)
Correct
(at least, I think it is correct)
let c_strs: ~[CString] = v.map(|s: & &str| s.to_c_str());
let mut ptrs: ~[*c_char] = c_strs.map(|c: &CString| c.with_ref(|ptr| ptr));
if null_terminate {
ptrs.push(std::ptr::null());
}
ptrs.as_imm_buf(|buf: **c_char, _| f(buf))The c_strs vector must live at least as at least as long as the **c_char is used. In this (unusual) case, returning the *c_char from with_ref is ok (if c_strs is kept alive long enough).