Skip to content

Commit d28b358

Browse files
authored
Rollup merge of rust-lang#64069 - danielhenrymantilla:feature/cstring_from_vec_of_nonzerou8, r=KodrAus
Added From<Vec<NonZeroU8>> for CString Added a `From<Vec<NonZeroU8>>` `impl` for `CString` # Rationale - `CString::from_vec_unchecked` is a subtle function, that makes `unsafe` code harder to audit when the generated `Vec`'s creation is non-trivial. This `impl` allows to write safer `unsafe` code thanks to the very explicit semantics of the `Vec<NonZeroU8>` type. - One such situation is when trying to `.read()` a `CString`, see issue rust-lang#59229. - this lead to a PR: rust-lang#59314, that was closed for being too specific / narrow (it only targetted being able to `.read()` a `CString`, when this pattern could have been generalized). - the issue suggested another route, based on `From<Vec<NonZeroU8>>`, which is indeed a less general and more concise code pattern. - quoting @Shnatsel: - > For me the main thing about making this safe is simplifying auditing - people have spent like an hour looking at just this one unsafe block in libflate because it's not clear what exactly is unchecked, so you have to look it up when auditing anyway. This has distracted us from much more serious memory safety issues the library had. Having this trivial impl in stdlib would turn this into safe code with compiler more or less guaranteeing that it's fine, and save anyone auditing the code a whole lot of time.
2 parents 19288dd + 60274a9 commit d28b358

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

src/libstd/ffi/c_str.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::fmt::{self, Write};
66
use crate::io;
77
use crate::mem;
88
use crate::memchr;
9+
use crate::num::NonZeroU8;
910
use crate::ops;
1011
use crate::os::raw::c_char;
1112
use crate::ptr;
@@ -741,6 +742,32 @@ impl From<Box<CStr>> for CString {
741742
}
742743
}
743744

745+
#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")]
746+
impl From<Vec<NonZeroU8>> for CString {
747+
/// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without
748+
/// copying nor checking for inner null bytes.
749+
///
750+
/// [`CString`]: ../ffi/struct.CString.html
751+
/// [`NonZeroU8`]: ../num/struct.NonZeroU8.html
752+
/// [`Vec`]: ../vec/struct.Vec.html
753+
#[inline]
754+
fn from(v: Vec<NonZeroU8>) -> CString {
755+
unsafe {
756+
// Transmute `Vec<NonZeroU8>` to `Vec<u8>`.
757+
let v: Vec<u8> = {
758+
// Safety:
759+
// - transmuting between `NonZeroU8` and `u8` is sound;
760+
// - `alloc::Layout<NonZeroU8> == alloc::Layout<u8>`.
761+
let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v);
762+
Vec::from_raw_parts(ptr.cast::<u8>(), len, cap)
763+
};
764+
// Safety: `v` cannot contain null bytes, given the type-level
765+
// invariant of `NonZeroU8`.
766+
CString::from_vec_unchecked(v)
767+
}
768+
}
769+
}
770+
744771
#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
745772
impl Clone for Box<CStr> {
746773
#[inline]

src/libstd/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@
309309
#![feature(unboxed_closures)]
310310
#![feature(untagged_unions)]
311311
#![feature(unwind_attributes)]
312+
#![feature(vec_into_raw_parts)]
312313
// NB: the above list is sorted to minimize merge conflicts.
313314
#![default_lib_allocator]
314315

0 commit comments

Comments
 (0)