-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
CString should have a "within max length" constructor #20475
Comments
cc #20507, The purpose of |
Actually, I guess what I was really asking was for that use case to be made easier. Ideally, I think something like this would be nice:
Anyways, I think the use case of "allocate a buffer, pass it to a function, which may write a string into it" is not that uncommon for C FFI, and it's be nice if it was easy to do (and in a way that's not error-prone). (Apologies if I'm getting some of the Rust terminology wrong here. I just started learning Rust about a week ago.) |
Note that one idea I had on #20507 was that this use case could be handled with @chrish42 for your use cases I would expect:
|
This isn't just for error buffers, and this is very problematic even if the function is guaranteed to set the buffer and terminate it with a null. As part of my first Rust project, I'm trying to call ptsname_r to get a string, and pass the result to open(2). Hours later, I still haven't found a way to do this correctly, even awkwardly. The given example does not compile in current versions of Rust because CString::new doesn't take a second argument, and CString::new panics if there are any nulls in the Vec (including the trailing null). I could write my own strlen, slice the vec, and make a CString that way... but at that point it's clear the language isn't ready for this and my project would need a rewrite later. |
I believe the new (as of 1.0.0-alpha 😛) CString API supports "within max length" use cases as follows. use std::cmp;
use std::ffi::CString;
use std::mem;
use std::ptr;
unsafe fn c_function(buf: *mut u8, len: usize) {
let data = b"hello\0";
// buf may or may not end with \0 depending on whether there was room for it
ptr::copy(data.as_ptr(), buf, cmp::min(len, data.len()));
}
fn call_the_thing() -> CString {
unsafe {
let mut buf = mem::uninitialized::<[u8; 256]>();
c_function(buf.as_mut_ptr(), buf.len());
let end = buf.iter().position(|ch| *ch == b'\0').unwrap_or(buf.len());
CString::from_vec_unchecked(buf[..end].to_vec())
}
}
fn main() {
println!("{:?}", call_the_thing().as_bytes());
} I would welcome a PR to support this better. |
@Diggsey made an excellent crate to support this use case and others involving a fixed size buffer which may or may not contain a null terminator, so I think we are ready to close the issue. let mut buf = mem::uninitialized::<[c_char; 256]>();
let ptr = buf.as_ptr();
let len = buf.len();
/* ... */
// copy the fixed length stack buffer which may or may not
// have null terminator into an owned CString
CFixedStr::from_ptr(ptr, len).to_owned().into_c_string() |
The crate is https://crates.io/crates/c_fixed_string Bit early to say it's excellent just yet but thanks 😛 |
😆 I promise I meant to link to the crate. |
Also, it would be better to write |
This Stack Overflow question points out this relatively-common C idiom (trimmed down to show the interesting bits):
The questioner wonders about the case where
errbuf
is not correctly set and noNUL
bytes occur in the buffer. When we go to use the string, we might merrily walk our way through memory! Since we know the length oferrbuf
, we should be able to check that there is aNUL
in the first X bytes and fail otherwise.While looking to see how Rust handles this case, I found the following spots that could suffer from the same problem:
I propose we add a new constructor to
CString
:of_max_len
. This would make sure that aNUL
byte occurs within a certain number of bytes. If it doesn't, wepanic!
.I think we could also make this particular case easier with a constructor like
from_slice
, which could be passed the slice which would implicitly know its length.I'm more than welcome to feedback of all kinds!
The text was updated successfully, but these errors were encountered: