-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Converting a [string] to a **c_char is subtlely difficult #9564
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The simplest thing to do would be to add a function to
|
@erickt I agree. I'm not worried about someone returning an interior pointer though, because they can't dereference it without |
Updated (although missing some of the bells and whistles): fn with_c_strings<T: ToCStr, U>(x: &[T], f: |*const *const libc::c_char| -> U) -> U {
let c_strings: Vec<CString> = x.iter().map(|s| s.to_c_str()).collect();
let mut ptrs: Vec<*const libc::c_char> = c_strings.iter().map(|cs| cs.as_ptr()).collect();
ptrs.push(ptr::null());
f(ptrs.as_ptr())
} |
@huonw In the interests of avoiding a reallocation on the pub fn with_c_strings<T: ToCStr, U>(x: &[T], f: |*const *const libc::c_char| -> U) -> U {
let c_strings: Vec<CString> = x.iter().map(|s| s.to_c_str()).collect();
let ptrs = c_strings.iter().map(|cs| cs.as_ptr())
.chain(Some(ptr::null::<libc::c_char>()).move_iter())
.collect::<Vec<*const libc::c_char>>();
f(ptrs.as_ptr())
} |
This has some complications in today's rust - it would look like this: #![feature(libc)]
extern crate libc;
use std::ptr;
use std::ffi::CString;
pub fn with_c_strings<T: Copy+Into<Vec<u8>>, U, F>(ts: &[T], f: F) -> U where
F: FnOnce(*const *const libc::c_char) -> U {
let c_strs: Vec<_> = ts.iter().map(|&t| {
CString::new(t).unwrap()
}).collect();
let ptrs: Vec<_> = c_strs.iter().map(|c_str| c_str.as_ptr())
.chain(Some(ptr::null()))
.collect();
f(ptrs.as_ptr())
} Unfortunately
I'm not sure there's a sane way to address this issue without violating the static guarantee of null-termination. |
Triage: this is still a papercut, but not enough of one for someone to have commented in almost two years. As such, I'm going to give this a close. If someone wants to write a library function to make this easier, please do so! |
It's currently non-trivial to do a
&[&str]
->**c_char
conversion correctly; I think there should be a function instd::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
The
*&str
→**c_char
cast is wrong.b
The
*c_char
fromwith_c_str
shouldn't leave the closure, since itwith_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)
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
fromwith_ref
is ok (ifc_strs
is kept alive long enough).The text was updated successfully, but these errors were encountered: