diff --git a/std/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs
similarity index 63%
rename from std/src/ffi/c_str.rs
rename to alloc/src/ffi/c_str.rs
index a68def1e8..172a008e8 100644
--- a/std/src/ffi/c_str.rs
+++ b/alloc/src/ffi/c_str.rs
@@ -1,25 +1,25 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-
#[cfg(test)]
mod tests;
-use crate::ascii;
-use crate::borrow::{Borrow, Cow};
-use crate::cmp::Ordering;
-use crate::error::Error;
-use crate::fmt::{self, Write};
-use crate::io;
-use crate::mem;
-use crate::num::NonZeroU8;
-use crate::ops;
-use crate::os::raw::c_char;
-use crate::ptr;
+use crate::borrow::{Cow, ToOwned};
+use crate::boxed::Box;
use crate::rc::Rc;
-use crate::slice;
-use crate::str::{self, Utf8Error};
+use crate::slice::hack::into_vec;
+use crate::string::String;
+use crate::vec::Vec;
+use core::borrow::Borrow;
+use core::ffi::{c_char, CStr};
+use core::fmt;
+use core::mem;
+use core::num::NonZeroU8;
+use core::ops;
+use core::ptr;
+use core::slice;
+use core::slice::memchr;
+use core::str::{self, Utf8Error};
+
+#[cfg(target_has_atomic = "ptr")]
use crate::sync::Arc;
-use crate::sys;
-use crate::sys_common::memchr;
/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
/// middle.
@@ -108,7 +108,7 @@ use crate::sys_common::memchr;
/// and other memory errors.
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")]
-#[stable(feature = "rust1", since = "1.0.0")]
+#[unstable(feature = "alloc_c_string", issue = "94079")]
pub struct CString {
// Invariant 1: the slice ends with a zero byte and has a length of at least one.
// Invariant 2: the slice contains only one zero byte.
@@ -116,90 +116,6 @@ pub struct CString {
inner: Box<[u8]>,
}
-/// Representation of a borrowed C string.
-///
-/// This type represents a borrowed reference to a nul-terminated
-/// array of bytes. It can be constructed safely from a &[[u8]]
-/// slice, or unsafely from a raw `*const c_char`. It can then be
-/// converted to a Rust &[str]
by performing UTF-8 validation, or
-/// into an owned [`CString`].
-///
-/// `&CStr` is to [`CString`] as &[str]
is to [`String`]: the former
-/// in each pair are borrowed references; the latter are owned
-/// strings.
-///
-/// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
-/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
-/// a safe interface to other consumers.
-///
-/// # Examples
-///
-/// Inspecting a foreign C string:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// extern "C" { fn my_string() -> *const c_char; }
-///
-/// unsafe {
-/// let slice = CStr::from_ptr(my_string());
-/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
-/// }
-/// ```
-///
-/// Passing a Rust-originating C string:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::{CString, CStr};
-/// use std::os::raw::c_char;
-///
-/// fn work(data: &CStr) {
-/// extern "C" { fn work_with(data: *const c_char); }
-///
-/// unsafe { work_with(data.as_ptr()) }
-/// }
-///
-/// let s = CString::new("data data data data").expect("CString::new failed");
-/// work(&s);
-/// ```
-///
-/// Converting a foreign C string into a Rust [`String`]:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// extern "C" { fn my_string() -> *const c_char; }
-///
-/// fn my_string_safe() -> String {
-/// unsafe {
-/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
-/// }
-/// }
-///
-/// println!("string: {}", my_string_safe());
-/// ```
-///
-/// [str]: prim@str "str"
-#[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
-#[stable(feature = "rust1", since = "1.0.0")]
-// FIXME:
-// `fn from` in `impl From<&CStr> for Box` current implementation relies
-// on `CStr` being layout-compatible with `[u8]`.
-// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
-// Anyway, `CStr` representation and layout are considered implementation detail, are
-// not documented and must not be relied upon.
-pub struct CStr {
- // FIXME: this should not be represented with a DST slice but rather with
- // just a raw `c_char` along with some form of marker to make
- // this an unsized type. Essentially `sizeof(&CStr)` should be the
- // same as `sizeof(&c_char)` but `CStr` should be an unsized type.
- inner: [c_char],
-}
-
/// An error indicating that an interior nul byte was found.
///
/// While Rust strings may contain nul bytes in the middle, C strings
@@ -216,28 +132,13 @@ pub struct CStr {
/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err();
/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
+#[unstable(feature = "alloc_c_string", issue = "94079")]
pub struct NulError(usize, Vec);
-/// An error indicating that a nul byte was not in the expected position.
-///
-/// The slice used to create a [`CStr`] must have one and only one nul byte,
-/// positioned at the end.
-///
-/// This error is created by the [`CStr::from_bytes_with_nul`] method.
-/// See its documentation for more.
-///
-/// # Examples
-///
-/// ```
-/// use std::ffi::{CStr, FromBytesWithNulError};
-///
-/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
-/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-pub struct FromBytesWithNulError {
- kind: FromBytesWithNulErrorKind,
+enum FromBytesWithNulErrorKind {
+ InteriorNul(usize),
+ NotNulTerminated,
}
/// An error indicating that a nul byte was not in the expected position.
@@ -256,27 +157,12 @@ pub struct FromBytesWithNulError {
/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
+#[unstable(feature = "alloc_c_string", issue = "94079")]
pub struct FromVecWithNulError {
error_kind: FromBytesWithNulErrorKind,
bytes: Vec,
}
-#[derive(Clone, PartialEq, Eq, Debug)]
-enum FromBytesWithNulErrorKind {
- InteriorNul(usize),
- NotNulTerminated,
-}
-
-impl FromBytesWithNulError {
- fn interior_nul(pos: usize) -> FromBytesWithNulError {
- FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
- }
- fn not_nul_terminated() -> FromBytesWithNulError {
- FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
- }
-}
-
#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
impl FromVecWithNulError {
/// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
@@ -328,27 +214,6 @@ impl FromVecWithNulError {
}
}
-/// An error indicating that no nul byte was present.
-///
-/// A slice used to create a [`CStr`] must contain a nul byte somewhere
-/// within the slice.
-///
-/// This error is created by the [`CStr::from_bytes_until_nul`] method.
-///
-#[derive(Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-pub struct FromBytesUntilNulError(());
-
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-impl Error for FromBytesUntilNulError {}
-
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-impl fmt::Display for FromBytesUntilNulError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "data provided does not contain a nul")
- }
-}
-
/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
///
/// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
@@ -358,7 +223,7 @@ impl fmt::Display for FromBytesUntilNulError {
/// This `struct` is created by [`CString::into_string()`]. See
/// its documentation for more.
#[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "cstring_into", since = "1.7.0")]
+#[unstable(feature = "alloc_c_string", issue = "94079")]
pub struct IntoStringError {
inner: CString,
error: Utf8Error,
@@ -536,7 +401,11 @@ impl CString {
// information about the size of the allocation is correct on Rust's
// side.
unsafe {
- let len = sys::strlen(ptr) + 1; // Including the NUL byte
+ extern "C" {
+ /// Provided by libc or compiler_builtins.
+ fn strlen(s: *const c_char) -> usize;
+ }
+ let len = strlen(ptr) + 1; // Including the NUL byte
let slice = slice::from_raw_parts_mut(ptr, len as usize);
CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
}
@@ -626,7 +495,7 @@ impl CString {
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_bytes(self) -> Vec {
- let mut vec = self.into_inner().into_vec();
+ let mut vec = into_vec(self.into_inner());
let _nul = vec.pop();
debug_assert_eq!(_nul, Some(0u8));
vec
@@ -647,7 +516,7 @@ impl CString {
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_bytes_with_nul(self) -> Vec {
- self.into_inner().into_vec()
+ into_vec(self.into_inner())
}
/// Returns the contents of this `CString` as a slice of bytes.
@@ -842,7 +711,7 @@ impl ops::Deref for CString {
#[inline]
fn deref(&self) -> &CStr {
- unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+ unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
}
}
@@ -864,25 +733,6 @@ impl From for Vec {
}
}
-#[stable(feature = "cstr_debug", since = "1.3.0")]
-impl fmt::Debug for CStr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "\"")?;
- for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
- f.write_char(byte as char)?;
- }
- write!(f, "\"")
- }
-}
-
-#[stable(feature = "cstr_default", since = "1.10.0")]
-impl Default for &CStr {
- fn default() -> Self {
- const SLICE: &[c_char] = &[0];
- unsafe { CStr::from_ptr(SLICE.as_ptr()) }
- }
-}
-
#[stable(feature = "cstr_default", since = "1.10.0")]
impl Default for CString {
/// Creates an empty `CString`.
@@ -910,6 +760,7 @@ impl<'a> From> for CString {
}
}
+#[cfg(not(test))]
#[stable(feature = "box_from_c_str", since = "1.17.0")]
impl From<&CStr> for Box {
/// Converts a `&CStr` into a `Box`,
@@ -938,7 +789,8 @@ impl From> for CString {
/// Converts a [Box]<[CStr]>
into a [`CString`] without copying or allocating.
#[inline]
fn from(s: Box) -> CString {
- s.into_c_string()
+ let raw = Box::into_raw(s) as *mut [u8];
+ CString { inner: unsafe { Box::from_raw(raw) } }
}
}
@@ -964,6 +816,7 @@ impl From> for CString {
}
}
+#[cfg(not(test))]
#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
impl Clone for Box {
#[inline]
@@ -1008,6 +861,7 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> {
}
}
+#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From for Arc {
/// Converts a [`CString`] into an [Arc]<[CStr]>
by moving the [`CString`]
@@ -1019,6 +873,7 @@ impl From for Arc {
}
}
+#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<&CStr> for Arc {
/// Converts a `&CStr` into a `Arc`,
@@ -1052,6 +907,7 @@ impl From<&CStr> for Rc {
}
}
+#[cfg(not(test))]
#[stable(feature = "default_box_extra", since = "1.17.0")]
impl Default for Box {
fn default() -> Box {
@@ -1099,14 +955,6 @@ impl NulError {
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for NulError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "nul byte found in data"
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for NulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1114,42 +962,6 @@ impl fmt::Display for NulError {
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl From for io::Error {
- /// Converts a [`NulError`] into a [`io::Error`].
- fn from(_: NulError) -> io::Error {
- io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
- }
-}
-
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl Error for FromBytesWithNulError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- match self.kind {
- FromBytesWithNulErrorKind::InteriorNul(..) => {
- "data provided contains an interior nul byte"
- }
- FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
- }
- }
-}
-
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl fmt::Display for FromBytesWithNulError {
- #[allow(deprecated, deprecated_in_future)]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(self.description())?;
- if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
- write!(f, " at byte pos {pos}")?;
- }
- Ok(())
- }
-}
-
-#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
-impl Error for FromVecWithNulError {}
-
#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
impl fmt::Display for FromVecWithNulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1179,18 +991,18 @@ impl IntoStringError {
pub fn utf8_error(&self) -> Utf8Error {
self.error
}
+
+ #[doc(hidden)]
+ #[unstable(feature = "cstr_internals", issue = "none")]
+ pub fn __source(&self) -> &Utf8Error {
+ &self.error
+ }
}
-#[stable(feature = "cstring_into", since = "1.7.0")]
-impl Error for IntoStringError {
- #[allow(deprecated)]
+impl IntoStringError {
fn description(&self) -> &str {
"C string contained non-utf8 bytes"
}
-
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- Some(&self.error)
- }
}
#[stable(feature = "cstring_into", since = "1.7.0")]
@@ -1201,327 +1013,126 @@ impl fmt::Display for IntoStringError {
}
}
-impl CStr {
- /// Wraps a raw C string with a safe C string wrapper.
- ///
- /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
- /// allows inspection and interoperation of non-owned C strings. The total
- /// size of the raw C string must be smaller than `isize::MAX` **bytes**
- /// in memory due to calling the `slice::from_raw_parts` function.
- /// This method is unsafe for a number of reasons:
- ///
- /// * There is no guarantee to the validity of `ptr`.
- /// * The returned lifetime is not guaranteed to be the actual lifetime of
- /// `ptr`.
- /// * There is no guarantee that the memory pointed to by `ptr` contains a
- /// valid nul terminator byte at the end of the string.
- /// * It is not guaranteed that the memory pointed by `ptr` won't change
- /// before the `CStr` has been destroyed.
- ///
- /// > **Note**: This operation is intended to be a 0-cost cast but it is
- /// > currently implemented with an up-front calculation of the length of
- /// > the string. This is not guaranteed to always be the case.
- ///
- /// # Examples
- ///
- /// ```ignore (extern-declaration)
- /// # fn main() {
- /// use std::ffi::CStr;
- /// use std::os::raw::c_char;
- ///
- /// extern "C" {
- /// fn my_string() -> *const c_char;
- /// }
- ///
- /// unsafe {
- /// let slice = CStr::from_ptr(my_string());
- /// println!("string returned: {}", slice.to_str().unwrap());
- /// }
- /// # }
- /// ```
- #[inline]
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
- // SAFETY: The caller has provided a pointer that points to a valid C
- // string with a NUL terminator of size less than `isize::MAX`, whose
- // content remain valid and doesn't change for the lifetime of the
- // returned `CStr`.
- //
- // Thus computing the length is fine (a NUL byte exists), the call to
- // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
- // the call to `from_bytes_with_nul_unchecked` is correct.
- //
- // The cast from c_char to u8 is ok because a c_char is always one byte.
- unsafe {
- let len = sys::strlen(ptr);
- let ptr = ptr as *const u8;
- Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
- }
- }
+#[stable(feature = "cstr_borrow", since = "1.3.0")]
+impl ToOwned for CStr {
+ type Owned = CString;
- /// Creates a C string wrapper from a byte slice.
- ///
- /// This method will create a `CStr` from any byte slice that contains at
- /// least one nul byte. The caller does not need to know or specify where
- /// the nul byte is located.
- ///
- /// If the first byte is a nul character, this method will return an
- /// empty `CStr`. If multiple nul characters are present, the `CStr` will
- /// end at the first one.
- ///
- /// If the slice only has a single nul byte at the end, this method is
- /// equivalent to [`CStr::from_bytes_with_nul`].
- ///
- /// # Examples
- /// ```
- /// #![feature(cstr_from_bytes_until_nul)]
- ///
- /// use std::ffi::CStr;
- ///
- /// let mut buffer = [0u8; 16];
- /// unsafe {
- /// // Here we might call an unsafe C function that writes a string
- /// // into the buffer.
- /// let buf_ptr = buffer.as_mut_ptr();
- /// buf_ptr.write_bytes(b'A', 8);
- /// }
- /// // Attempt to extract a C nul-terminated string from the buffer.
- /// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
- /// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
- /// ```
- ///
- #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
- pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
- let nul_pos = memchr::memchr(0, bytes);
- match nul_pos {
- Some(nul_pos) => {
- // SAFETY: We know there is a nul byte at nul_pos, so this slice
- // (ending at the nul byte) is a well-formed C string.
- let subslice = &bytes[..nul_pos + 1];
- Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
- }
- None => Err(FromBytesUntilNulError(())),
- }
+ fn to_owned(&self) -> CString {
+ CString { inner: self.to_bytes_with_nul().into() }
}
- /// Creates a C string wrapper from a byte slice.
- ///
- /// This function will cast the provided `bytes` to a `CStr`
- /// wrapper after ensuring that the byte slice is nul-terminated
- /// and does not contain any interior nul bytes.
- ///
- /// If the nul byte may not be at the end,
- /// [`CStr::from_bytes_until_nul`] can be used instead.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
- /// assert!(cstr.is_ok());
- /// ```
- ///
- /// Creating a `CStr` without a trailing nul terminator is an error:
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"hello");
- /// assert!(cstr.is_err());
- /// ```
- ///
- /// Creating a `CStr` with an interior nul byte is an error:
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
- /// assert!(cstr.is_err());
- /// ```
- #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
- let nul_pos = memchr::memchr(0, bytes);
- match nul_pos {
- Some(nul_pos) if nul_pos + 1 == bytes.len() => {
- // SAFETY: We know there is only one nul byte, at the end
- // of the byte slice.
- Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) })
- }
- Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
- None => Err(FromBytesWithNulError::not_nul_terminated()),
- }
+ fn clone_into(&self, target: &mut CString) {
+ let mut b = into_vec(mem::take(&mut target.inner));
+ self.to_bytes_with_nul().clone_into(&mut b);
+ target.inner = b.into_boxed_slice();
}
+}
- /// Unsafely creates a C string wrapper from a byte slice.
- ///
- /// This function will cast the provided `bytes` to a `CStr` wrapper without
- /// performing any sanity checks. The provided slice **must** be nul-terminated
- /// and not contain any interior nul bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::{CStr, CString};
- ///
- /// unsafe {
- /// let cstring = CString::new("hello").expect("CString::new failed");
- /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
- /// assert_eq!(cstr, &*cstring);
- /// }
- /// ```
- #[inline]
- #[must_use]
- #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
- pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- // We're in a const fn, so this is the best we can do
- debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
- unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl From<&CStr> for CString {
+ fn from(s: &CStr) -> CString {
+ s.to_owned()
}
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl ops::Index for CString {
+ type Output = CStr;
#[inline]
- const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
- // SAFETY: Casting to CStr is safe because its internal representation
- // is a [u8] too (safe only inside std).
- // Dereferencing the obtained pointer is safe because it comes from a
- // reference. Making a reference is then safe because its lifetime
- // is bound by the lifetime of the given `bytes`.
- unsafe { &*(bytes as *const [u8] as *const Self) }
+ fn index(&self, _index: ops::RangeFull) -> &CStr {
+ self
}
+}
- /// Returns the inner pointer to this C string.
- ///
- /// The returned pointer will be valid for as long as `self` is, and points
- /// to a contiguous region of memory terminated with a 0 byte to represent
- /// the end of the string.
- ///
- /// **WARNING**
- ///
- /// The returned pointer is read-only; writing to it (including passing it
- /// to C code that writes to it) causes undefined behavior.
- ///
- /// It is your responsibility to make sure that the underlying memory is not
- /// freed too early. For example, the following code will cause undefined
- /// behavior when `ptr` is used inside the `unsafe` block:
- ///
- /// ```no_run
- /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
- /// use std::ffi::CString;
- ///
- /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
- /// unsafe {
- /// // `ptr` is dangling
- /// *ptr;
- /// }
- /// ```
- ///
- /// This happens because the pointer returned by `as_ptr` does not carry any
- /// lifetime information and the [`CString`] is deallocated immediately after
- /// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
- /// expression is evaluated.
- /// To fix the problem, bind the `CString` to a local variable:
- ///
- /// ```no_run
- /// # #![allow(unused_must_use)]
- /// use std::ffi::CString;
- ///
- /// let hello = CString::new("Hello").expect("CString::new failed");
- /// let ptr = hello.as_ptr();
- /// unsafe {
- /// // `ptr` is valid because `hello` is in scope
- /// *ptr;
- /// }
- /// ```
- ///
- /// This way, the lifetime of the [`CString`] in `hello` encompasses
- /// the lifetime of `ptr` and the `unsafe` block.
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl AsRef for CString {
#[inline]
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
- pub const fn as_ptr(&self) -> *const c_char {
- self.inner.as_ptr()
+ fn as_ref(&self) -> &CStr {
+ self
}
+}
- /// Converts this C string to a byte slice.
+#[cfg(bootstrap)]
+#[doc(hidden)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+pub trait CStrExt {
+ /// Converts a `CStr` into a [Cow]<[str]>
.
///
- /// The returned slice will **not** contain the trailing nul terminator that this C
- /// string has.
+ /// If the contents of the `CStr` are valid UTF-8 data, this
+ /// function will return a [Cow]::[Borrowed]\(&[str])
+ /// with the corresponding &[str]
slice. Otherwise, it will
+ /// replace any invalid UTF-8 sequences with
+ /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
+ /// [Cow]::[Owned]\(&[str])
with the result.
///
- /// > **Note**: This method is currently implemented as a constant-time
- /// > cast, but it is planned to alter its definition in the future to
- /// > perform the length calculation whenever this method is called.
+ /// [str]: prim@str "str"
+ /// [Borrowed]: Cow::Borrowed
+ /// [Owned]: Cow::Owned
+ /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
///
/// # Examples
///
+ /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
+ ///
/// ```
+ /// use std::borrow::Cow;
/// use std::ffi::CStr;
///
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_bytes(), b"foo");
+ /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
+ /// .expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
/// ```
- #[inline]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn to_bytes(&self) -> &[u8] {
- let bytes = self.to_bytes_with_nul();
- // SAFETY: to_bytes_with_nul returns slice with length at least 1
- unsafe { bytes.get_unchecked(..bytes.len() - 1) }
- }
-
- /// Converts this C string to a byte slice containing the trailing 0 byte.
///
- /// This function is the equivalent of [`CStr::to_bytes`] except that it
- /// will retain the trailing nul terminator instead of chopping it off.
- ///
- /// > **Note**: This method is currently implemented as a 0-cost cast, but
- /// > it is planned to alter its definition in the future to perform the
- /// > length calculation whenever this method is called.
- ///
- /// # Examples
+ /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
///
/// ```
+ /// use std::borrow::Cow;
/// use std::ffi::CStr;
///
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
+ /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
+ /// .expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(
+ /// cstr.to_string_lossy(),
+ /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
+ /// );
/// ```
- #[inline]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn to_bytes_with_nul(&self) -> &[u8] {
- unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
- }
+ #[stable(feature = "cstr_to_str", since = "1.4.0")]
+ fn to_string_lossy(&self) -> Cow<'_, str>;
- /// Yields a &[str]
slice if the `CStr` contains valid UTF-8.
- ///
- /// If the contents of the `CStr` are valid UTF-8 data, this
- /// function will return the corresponding &[str]
slice. Otherwise,
- /// it will return an error with details of where UTF-8 validation failed.
- ///
- /// [str]: prim@str "str"
+ /// Converts a [Box]<[CStr]>
into a [`CString`] without copying or allocating.
///
/// # Examples
///
/// ```
- /// use std::ffi::CStr;
+ /// use std::ffi::CString;
///
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_str(), Ok("foo"));
+ /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
+ /// let boxed = c_string.into_boxed_c_str();
+ /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
/// ```
- #[stable(feature = "cstr_to_str", since = "1.4.0")]
- pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
- // N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
- // instead of in `from_ptr()`, it may be worth considering if this should
- // be rewritten to do the UTF-8 check inline with the length calculation
- // instead of doing it afterwards.
- str::from_utf8(self.to_bytes())
+ #[must_use = "`self` will be dropped if the result is not used"]
+ #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
+ fn into_c_string(self: Box) -> CString;
+}
+
+#[cfg(bootstrap)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+impl CStrExt for CStr {
+ fn to_string_lossy(&self) -> Cow<'_, str> {
+ String::from_utf8_lossy(self.to_bytes())
}
+ fn into_c_string(self: Box) -> CString {
+ CString::from(self)
+ }
+}
+
+#[cfg(not(bootstrap))]
+#[cfg(not(test))]
+impl CStr {
/// Converts a `CStr` into a [Cow]<[str]>
.
///
/// If the contents of the `CStr` are valid UTF-8 data, this
@@ -1534,7 +1145,7 @@ impl CStr {
/// [str]: prim@str "str"
/// [Borrowed]: Cow::Borrowed
/// [Owned]: Cow::Owned
- /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
+ /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
///
/// # Examples
///
@@ -1562,6 +1173,7 @@ impl CStr {
/// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
/// );
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "cstr_to_str", since = "1.4.0")]
@@ -1580,101 +1192,10 @@ impl CStr {
/// let boxed = c_string.into_boxed_c_str();
/// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
- pub fn into_c_string(self: Box) -> CString {
- let raw = Box::into_raw(self) as *mut [u8];
- CString { inner: unsafe { Box::from_raw(raw) } }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialEq for CStr {
- fn eq(&self, other: &CStr) -> bool {
- self.to_bytes().eq(other.to_bytes())
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Eq for CStr {}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for CStr {
- fn partial_cmp(&self, other: &CStr) -> Option {
- self.to_bytes().partial_cmp(&other.to_bytes())
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for CStr {
- fn cmp(&self, other: &CStr) -> Ordering {
- self.to_bytes().cmp(&other.to_bytes())
- }
-}
-
-#[stable(feature = "cstr_borrow", since = "1.3.0")]
-impl ToOwned for CStr {
- type Owned = CString;
-
- fn to_owned(&self) -> CString {
- CString { inner: self.to_bytes_with_nul().into() }
- }
-
- fn clone_into(&self, target: &mut CString) {
- let mut b = Vec::from(mem::take(&mut target.inner));
- self.to_bytes_with_nul().clone_into(&mut b);
- target.inner = b.into_boxed_slice();
- }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl From<&CStr> for CString {
- /// Copies the contents of the `&CStr` into a newly allocated `CString`.
- fn from(s: &CStr) -> CString {
- s.to_owned()
- }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl ops::Index for CString {
- type Output = CStr;
-
- #[inline]
- fn index(&self, _index: ops::RangeFull) -> &CStr {
- self
- }
-}
-
-#[stable(feature = "cstr_range_from", since = "1.47.0")]
-impl ops::Index> for CStr {
- type Output = CStr;
-
- fn index(&self, index: ops::RangeFrom) -> &CStr {
- let bytes = self.to_bytes_with_nul();
- // we need to manually check the starting index to account for the null
- // byte, since otherwise we could get an empty string that doesn't end
- // in a null.
- if index.start < bytes.len() {
- unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) }
- } else {
- panic!(
- "index out of bounds: the len is {} but the index is {}",
- bytes.len(),
- index.start
- );
- }
- }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl AsRef for CStr {
- #[inline]
- fn as_ref(&self) -> &CStr {
- self
- }
-}
-
-#[stable(feature = "cstring_asref", since = "1.7.0")]
-impl AsRef for CString {
- #[inline]
- fn as_ref(&self) -> &CStr {
- self
+ pub fn into_c_string(self: Box) -> CString {
+ CString::from(self)
}
}
diff --git a/std/src/ffi/c_str/tests.rs b/alloc/src/ffi/c_str/tests.rs
similarity index 87%
rename from std/src/ffi/c_str/tests.rs
rename to alloc/src/ffi/c_str/tests.rs
index c20da138a..0b7476d5c 100644
--- a/std/src/ffi/c_str/tests.rs
+++ b/alloc/src/ffi/c_str/tests.rs
@@ -1,10 +1,12 @@
use super::*;
-use crate::borrow::Cow::{Borrowed, Owned};
-use crate::collections::hash_map::DefaultHasher;
-use crate::hash::{Hash, Hasher};
-use crate::os::raw::c_char;
use crate::rc::Rc;
use crate::sync::Arc;
+use core::assert_matches::assert_matches;
+use core::ffi::FromBytesUntilNulError;
+use core::hash::{Hash, Hasher};
+
+#[allow(deprecated)]
+use core::hash::SipHasher13 as DefaultHasher;
#[test]
fn c_to_rust() {
@@ -47,22 +49,6 @@ fn borrowed() {
}
}
-#[test]
-fn to_str() {
- let data = b"123\xE2\x80\xA6\0";
- let ptr = data.as_ptr() as *const c_char;
- unsafe {
- assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
- assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
- }
- let data = b"123\xE2\0";
- let ptr = data.as_ptr() as *const c_char;
- unsafe {
- assert!(CStr::from_ptr(ptr).to_str().is_err());
- assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}")));
- }
-}
-
#[test]
fn to_owned() {
let data = b"123\0";
@@ -78,9 +64,11 @@ fn equal_hash() {
let ptr = data.as_ptr() as *const c_char;
let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
+ #[allow(deprecated)]
let mut s = DefaultHasher::new();
cstr.hash(&mut s);
let cstr_hash = s.finish();
+ #[allow(deprecated)]
let mut s = DefaultHasher::new();
CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
let cstring_hash = s.finish();
@@ -122,11 +110,11 @@ fn cstr_from_bytes_until_nul() {
// Test an empty slice. This should fail because it
// does not contain a nul byte.
let b = b"";
- assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
+ assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. }));
// Test a non-empty slice, that does not contain a nul byte.
let b = b"hello";
- assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
+ assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. }));
// Test an empty nul-terminated string
let b = b"\0";
diff --git a/alloc/src/ffi/mod.rs b/alloc/src/ffi/mod.rs
new file mode 100644
index 000000000..eed2851c1
--- /dev/null
+++ b/alloc/src/ffi/mod.rs
@@ -0,0 +1,91 @@
+//! Utilities related to FFI bindings.
+//!
+//! This module provides utilities to handle data across non-Rust
+//! interfaces, like other programming languages and the underlying
+//! operating system. It is mainly of use for FFI (Foreign Function
+//! Interface) bindings and code that needs to exchange C-like strings
+//! with other languages.
+//!
+//! # Overview
+//!
+//! Rust represents owned strings with the [`String`] type, and
+//! borrowed slices of strings with the [`str`] primitive. Both are
+//! always in UTF-8 encoding, and may contain nul bytes in the middle,
+//! i.e., if you look at the bytes that make up the string, there may
+//! be a `\0` among them. Both `String` and `str` store their length
+//! explicitly; there are no nul terminators at the end of strings
+//! like in C.
+//!
+//! C strings are different from Rust strings:
+//!
+//! * **Encodings** - Rust strings are UTF-8, but C strings may use
+//! other encodings. If you are using a string from C, you should
+//! check its encoding explicitly, rather than just assuming that it
+//! is UTF-8 like you can do in Rust.
+//!
+//! * **Character size** - C strings may use `char` or `wchar_t`-sized
+//! characters; please **note** that C's `char` is different from Rust's.
+//! The C standard leaves the actual sizes of those types open to
+//! interpretation, but defines different APIs for strings made up of
+//! each character type. Rust strings are always UTF-8, so different
+//! Unicode characters will be encoded in a variable number of bytes
+//! each. The Rust type [`char`] represents a '[Unicode scalar
+//! value]', which is similar to, but not the same as, a '[Unicode
+//! code point]'.
+//!
+//! * **Nul terminators and implicit string lengths** - Often, C
+//! strings are nul-terminated, i.e., they have a `\0` character at the
+//! end. The length of a string buffer is not stored, but has to be
+//! calculated; to compute the length of a string, C code must
+//! manually call a function like `strlen()` for `char`-based strings,
+//! or `wcslen()` for `wchar_t`-based ones. Those functions return
+//! the number of characters in the string excluding the nul
+//! terminator, so the buffer length is really `len+1` characters.
+//! Rust strings don't have a nul terminator; their length is always
+//! stored and does not need to be calculated. While in Rust
+//! accessing a string's length is an *O*(1) operation (because the
+//! length is stored); in C it is an *O*(*n*) operation because the
+//! length needs to be computed by scanning the string for the nul
+//! terminator.
+//!
+//! * **Internal nul characters** - When C strings have a nul
+//! terminator character, this usually means that they cannot have nul
+//! characters in the middle — a nul character would essentially
+//! truncate the string. Rust strings *can* have nul characters in
+//! the middle, because nul does not have to mark the end of the
+//! string in Rust.
+//!
+//! # Representations of non-Rust strings
+//!
+//! [`CString`] and [`CStr`] are useful when you need to transfer
+//! UTF-8 strings to and from languages with a C ABI, like Python.
+//!
+//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
+//! string: it is nul-terminated, and has no internal nul characters.
+//! Rust code can create a [`CString`] out of a normal string (provided
+//! that the string doesn't have nul characters in the middle), and
+//! then use a variety of methods to obtain a raw \*mut [u8]
that can
+//! then be passed as an argument to functions which use the C
+//! conventions for strings.
+//!
+//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
+//! is what you would use to wrap a raw \*const [u8]
that you got from
+//! a C function. A [`CStr`] is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a [`CStr`], you can convert it to a Rust
+//! &[str]
if it's valid UTF-8, or lossily convert it by adding
+//! replacement characters.
+//!
+//! [`String`]: crate::string::String
+//! [`CStr`]: core::ffi::CStr
+
+#![unstable(feature = "alloc_ffi", issue = "94079")]
+
+#[cfg(bootstrap)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+pub use self::c_str::CStrExt;
+#[unstable(feature = "alloc_c_string", issue = "94079")]
+pub use self::c_str::FromVecWithNulError;
+#[unstable(feature = "alloc_c_string", issue = "94079")]
+pub use self::c_str::{CString, IntoStringError, NulError};
+
+mod c_str;
diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs
index c54001dce..4d2dc4ece 100644
--- a/alloc/src/lib.rs
+++ b/alloc/src/lib.rs
@@ -86,11 +86,13 @@
#![allow(explicit_outlives_requirements)]
//
// Library features:
+#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))]
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_windows)]
+#![feature(assert_matches)]
#![feature(async_iterator)]
#![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
@@ -104,9 +106,12 @@
#![feature(const_maybe_uninit_write)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_refs_to_cell)]
+#![feature(core_c_str)]
#![feature(core_intrinsics)]
+#![feature(core_ffi_c)]
#![feature(const_eval_select)]
#![feature(const_pin)]
+#![feature(cstr_from_bytes_until_nul)]
#![feature(dispatch_from_dyn)]
#![feature(exact_size_is_empty)]
#![feature(extend_one)]
@@ -152,6 +157,7 @@
#![feature(exclusive_range_pattern)]
#![feature(fundamental)]
#![cfg_attr(not(test), feature(generator_trait))]
+#![feature(hashmap_internals)]
#![feature(lang_items)]
#![feature(let_else)]
#![feature(min_specialization)]
@@ -160,6 +166,7 @@
#![feature(nll)] // Not necessary, but here to test the `nll` feature.
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)]
+#![feature(slice_internals)]
#![feature(staged_api)]
#![cfg_attr(test, feature(test))]
#![feature(unboxed_closures)]
@@ -205,6 +212,8 @@ mod boxed {
}
pub mod borrow;
pub mod collections;
+#[cfg(not(no_global_oom_handling))]
+pub mod ffi;
pub mod fmt;
pub mod rc;
pub mod slice;
diff --git a/alloc/src/slice.rs b/alloc/src/slice.rs
index 31edbe0c5..02a47c57b 100644
--- a/alloc/src/slice.rs
+++ b/alloc/src/slice.rs
@@ -153,7 +153,7 @@ pub use hack::to_vec;
// functions are actually methods that are in `impl [T]` but not in
// `core::slice::SliceExt` - we need to supply these functions for the
// `test_permutations` test
-mod hack {
+pub(crate) mod hack {
use core::alloc::Allocator;
use crate::boxed::Box;
diff --git a/alloc/tests/c_str.rs b/alloc/tests/c_str.rs
new file mode 100644
index 000000000..8fbb10e1d
--- /dev/null
+++ b/alloc/tests/c_str.rs
@@ -0,0 +1,18 @@
+use std::borrow::Cow::{Borrowed, Owned};
+use std::ffi::{c_char, CStr};
+
+#[test]
+fn to_str() {
+ let data = b"123\xE2\x80\xA6\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
+ }
+ let data = b"123\xE2\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert!(CStr::from_ptr(ptr).to_str().is_err());
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}")));
+ }
+}
diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs
index 16d3b3685..8de159246 100644
--- a/alloc/tests/lib.rs
+++ b/alloc/tests/lib.rs
@@ -12,6 +12,8 @@
#![feature(const_nonnull_slice_from_raw_parts)]
#![feature(const_ptr_write)]
#![feature(const_try)]
+#![feature(core_c_str)]
+#![feature(core_ffi_c)]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
@@ -49,6 +51,7 @@ mod binary_heap;
mod borrow;
mod boxed;
mod btree_set_hash;
+mod c_str;
mod const_fns;
mod cow_str;
mod fmt;
diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs
new file mode 100644
index 000000000..15d9d0139
--- /dev/null
+++ b/core/src/ffi/c_str.rs
@@ -0,0 +1,570 @@
+use crate::ascii;
+use crate::cmp::Ordering;
+use crate::ffi::c_char;
+use crate::fmt::{self, Write};
+use crate::ops;
+use crate::slice;
+use crate::slice::memchr;
+use crate::str;
+
+/// Representation of a borrowed C string.
+///
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a &[[u8]]
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust &[str]
by performing UTF-8 validation, or
+/// into an owned `CString`.
+///
+/// `&CStr` is to `CString` as &[str]
is to `String`: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
+///
+/// Note that this structure is **not** `repr(C)` and is not recommended to be
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
+/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
+/// a safe interface to other consumers.
+///
+/// # Examples
+///
+/// Inspecting a foreign C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern "C" { fn my_string() -> *const c_char; }
+///
+/// unsafe {
+/// let slice = CStr::from_ptr(my_string());
+/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
+/// }
+/// ```
+///
+/// Passing a Rust-originating C string:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::{CString, CStr};
+/// use std::os::raw::c_char;
+///
+/// fn work(data: &CStr) {
+/// extern "C" { fn work_with(data: *const c_char); }
+///
+/// unsafe { work_with(data.as_ptr()) }
+/// }
+///
+/// let s = CString::new("data data data data").expect("CString::new failed");
+/// work(&s);
+/// ```
+///
+/// Converting a foreign C string into a Rust `String`:
+///
+/// ```ignore (extern-declaration)
+/// use std::ffi::CStr;
+/// use std::os::raw::c_char;
+///
+/// extern "C" { fn my_string() -> *const c_char; }
+///
+/// fn my_string_safe() -> String {
+/// unsafe {
+/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
+/// }
+/// }
+///
+/// println!("string: {}", my_string_safe());
+/// ```
+///
+/// [str]: prim@str "str"
+#[derive(Hash)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
+#[unstable(feature = "core_c_str", issue = "94079")]
+#[cfg_attr(not(bootstrap), lang = "CStr")]
+// FIXME:
+// `fn from` in `impl From<&CStr> for Box` current implementation relies
+// on `CStr` being layout-compatible with `[u8]`.
+// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
+// Anyway, `CStr` representation and layout are considered implementation detail, are
+// not documented and must not be relied upon.
+pub struct CStr {
+ // FIXME: this should not be represented with a DST slice but rather with
+ // just a raw `c_char` along with some form of marker to make
+ // this an unsized type. Essentially `sizeof(&CStr)` should be the
+ // same as `sizeof(&c_char)` but `CStr` should be an unsized type.
+ inner: [c_char],
+}
+
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul byte,
+/// positioned at the end.
+///
+/// This error is created by the [`CStr::from_bytes_with_nul`] method.
+/// See its documentation for more.
+///
+/// # Examples
+///
+/// ```
+/// use std::ffi::{CStr, FromBytesWithNulError};
+///
+/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "core_c_str", issue = "94079")]
+pub struct FromBytesWithNulError {
+ kind: FromBytesWithNulErrorKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum FromBytesWithNulErrorKind {
+ InteriorNul(usize),
+ NotNulTerminated,
+}
+
+impl FromBytesWithNulError {
+ fn interior_nul(pos: usize) -> FromBytesWithNulError {
+ FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
+ }
+ fn not_nul_terminated() -> FromBytesWithNulError {
+ FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
+ }
+
+ #[doc(hidden)]
+ #[unstable(feature = "cstr_internals", issue = "none")]
+ pub fn __description(&self) -> &str {
+ match self.kind {
+ FromBytesWithNulErrorKind::InteriorNul(..) => {
+ "data provided contains an interior nul byte"
+ }
+ FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
+ }
+ }
+}
+
+/// An error indicating that no nul byte was present.
+///
+/// A slice used to create a [`CStr`] must contain a nul byte somewhere
+/// within the slice.
+///
+/// This error is created by the [`CStr::from_bytes_until_nul`] method.
+///
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+pub struct FromBytesUntilNulError(());
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl fmt::Display for FromBytesUntilNulError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "data provided does not contain a nul")
+ }
+}
+
+#[stable(feature = "cstr_debug", since = "1.3.0")]
+impl fmt::Debug for CStr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "\"")?;
+ for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
+ f.write_char(byte as char)?;
+ }
+ write!(f, "\"")
+ }
+}
+
+#[stable(feature = "cstr_default", since = "1.10.0")]
+impl Default for &CStr {
+ fn default() -> Self {
+ const SLICE: &[c_char] = &[0];
+ // SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string.
+ unsafe { CStr::from_ptr(SLICE.as_ptr()) }
+ }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl fmt::Display for FromBytesWithNulError {
+ #[allow(deprecated, deprecated_in_future)]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.__description())?;
+ if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
+ write!(f, " at byte pos {pos}")?;
+ }
+ Ok(())
+ }
+}
+
+impl CStr {
+ /// Wraps a raw C string with a safe C string wrapper.
+ ///
+ /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
+ /// allows inspection and interoperation of non-owned C strings. The total
+ /// size of the raw C string must be smaller than `isize::MAX` **bytes**
+ /// in memory due to calling the `slice::from_raw_parts` function.
+ /// This method is unsafe for a number of reasons:
+ ///
+ /// * There is no guarantee to the validity of `ptr`.
+ /// * The returned lifetime is not guaranteed to be the actual lifetime of
+ /// `ptr`.
+ /// * There is no guarantee that the memory pointed to by `ptr` contains a
+ /// valid nul terminator byte at the end of the string.
+ /// * It is not guaranteed that the memory pointed by `ptr` won't change
+ /// before the `CStr` has been destroyed.
+ ///
+ /// > **Note**: This operation is intended to be a 0-cost cast but it is
+ /// > currently implemented with an up-front calculation of the length of
+ /// > the string. This is not guaranteed to always be the case.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore (extern-declaration)
+ /// # fn main() {
+ /// use std::ffi::CStr;
+ /// use std::os::raw::c_char;
+ ///
+ /// extern "C" {
+ /// fn my_string() -> *const c_char;
+ /// }
+ ///
+ /// unsafe {
+ /// let slice = CStr::from_ptr(my_string());
+ /// println!("string returned: {}", slice.to_str().unwrap());
+ /// }
+ /// # }
+ /// ```
+ #[inline]
+ #[must_use]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+ // SAFETY: The caller has provided a pointer that points to a valid C
+ // string with a NUL terminator of size less than `isize::MAX`, whose
+ // content remain valid and doesn't change for the lifetime of the
+ // returned `CStr`.
+ //
+ // Thus computing the length is fine (a NUL byte exists), the call to
+ // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
+ // the call to `from_bytes_with_nul_unchecked` is correct.
+ //
+ // The cast from c_char to u8 is ok because a c_char is always one byte.
+ unsafe {
+ extern "C" {
+ /// Provided by libc or compiler_builtins.
+ fn strlen(s: *const c_char) -> usize;
+ }
+ let len = strlen(ptr);
+ let ptr = ptr as *const u8;
+ CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+ }
+ }
+
+ /// Creates a C string wrapper from a byte slice.
+ ///
+ /// This method will create a `CStr` from any byte slice that contains at
+ /// least one nul byte. The caller does not need to know or specify where
+ /// the nul byte is located.
+ ///
+ /// If the first byte is a nul character, this method will return an
+ /// empty `CStr`. If multiple nul characters are present, the `CStr` will
+ /// end at the first one.
+ ///
+ /// If the slice only has a single nul byte at the end, this method is
+ /// equivalent to [`CStr::from_bytes_with_nul`].
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(cstr_from_bytes_until_nul)]
+ ///
+ /// use std::ffi::CStr;
+ ///
+ /// let mut buffer = [0u8; 16];
+ /// unsafe {
+ /// // Here we might call an unsafe C function that writes a string
+ /// // into the buffer.
+ /// let buf_ptr = buffer.as_mut_ptr();
+ /// buf_ptr.write_bytes(b'A', 8);
+ /// }
+ /// // Attempt to extract a C nul-terminated string from the buffer.
+ /// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
+ /// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
+ /// ```
+ ///
+ #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+ pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
+ let nul_pos = memchr::memchr(0, bytes);
+ match nul_pos {
+ Some(nul_pos) => {
+ let subslice = &bytes[..nul_pos + 1];
+ // SAFETY: We know there is a nul byte at nul_pos, so this slice
+ // (ending at the nul byte) is a well-formed C string.
+ Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
+ }
+ None => Err(FromBytesUntilNulError(())),
+ }
+ }
+
+ /// Creates a C string wrapper from a byte slice.
+ ///
+ /// This function will cast the provided `bytes` to a `CStr`
+ /// wrapper after ensuring that the byte slice is nul-terminated
+ /// and does not contain any interior nul bytes.
+ ///
+ /// If the nul byte may not be at the end,
+ /// [`CStr::from_bytes_until_nul`] can be used instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
+ /// assert!(cstr.is_ok());
+ /// ```
+ ///
+ /// Creating a `CStr` without a trailing nul terminator is an error:
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"hello");
+ /// assert!(cstr.is_err());
+ /// ```
+ ///
+ /// Creating a `CStr` with an interior nul byte is an error:
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
+ /// assert!(cstr.is_err());
+ /// ```
+ #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+ pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
+ let nul_pos = memchr::memchr(0, bytes);
+ match nul_pos {
+ Some(nul_pos) if nul_pos + 1 == bytes.len() => {
+ // SAFETY: We know there is only one nul byte, at the end
+ // of the byte slice.
+ Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
+ }
+ Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
+ None => Err(FromBytesWithNulError::not_nul_terminated()),
+ }
+ }
+
+ /// Unsafely creates a C string wrapper from a byte slice.
+ ///
+ /// This function will cast the provided `bytes` to a `CStr` wrapper without
+ /// performing any sanity checks. The provided slice **must** be nul-terminated
+ /// and not contain any interior nul bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{CStr, CString};
+ ///
+ /// unsafe {
+ /// let cstring = CString::new("hello").expect("CString::new failed");
+ /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
+ /// assert_eq!(cstr, &*cstring);
+ /// }
+ /// ```
+ #[inline]
+ #[must_use]
+ #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+ #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
+ pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ // We're in a const fn, so this is the best we can do
+ debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
+ // SAFETY: Calling an inner function with the same prerequisites.
+ unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
+ }
+
+ #[inline]
+ const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ // SAFETY: Casting to CStr is safe because its internal representation
+ // is a [u8] too (safe only inside std).
+ // Dereferencing the obtained pointer is safe because it comes from a
+ // reference. Making a reference is then safe because its lifetime
+ // is bound by the lifetime of the given `bytes`.
+ unsafe { &*(bytes as *const [u8] as *const CStr) }
+ }
+
+ /// Returns the inner pointer to this C string.
+ ///
+ /// The returned pointer will be valid for as long as `self` is, and points
+ /// to a contiguous region of memory terminated with a 0 byte to represent
+ /// the end of the string.
+ ///
+ /// **WARNING**
+ ///
+ /// The returned pointer is read-only; writing to it (including passing it
+ /// to C code that writes to it) causes undefined behavior.
+ ///
+ /// It is your responsibility to make sure that the underlying memory is not
+ /// freed too early. For example, the following code will cause undefined
+ /// behavior when `ptr` is used inside the `unsafe` block:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
+ /// use std::ffi::CString;
+ ///
+ /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
+ /// unsafe {
+ /// // `ptr` is dangling
+ /// *ptr;
+ /// }
+ /// ```
+ ///
+ /// This happens because the pointer returned by `as_ptr` does not carry any
+ /// lifetime information and the `CString` is deallocated immediately after
+ /// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
+ /// expression is evaluated.
+ /// To fix the problem, bind the `CString` to a local variable:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_must_use)]
+ /// use std::ffi::CString;
+ ///
+ /// let hello = CString::new("Hello").expect("CString::new failed");
+ /// let ptr = hello.as_ptr();
+ /// unsafe {
+ /// // `ptr` is valid because `hello` is in scope
+ /// *ptr;
+ /// }
+ /// ```
+ ///
+ /// This way, the lifetime of the `CString` in `hello` encompasses
+ /// the lifetime of `ptr` and the `unsafe` block.
+ #[inline]
+ #[must_use]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+ pub const fn as_ptr(&self) -> *const c_char {
+ self.inner.as_ptr()
+ }
+
+ /// Converts this C string to a byte slice.
+ ///
+ /// The returned slice will **not** contain the trailing nul terminator that this C
+ /// string has.
+ ///
+ /// > **Note**: This method is currently implemented as a constant-time
+ /// > cast, but it is planned to alter its definition in the future to
+ /// > perform the length calculation whenever this method is called.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(cstr.to_bytes(), b"foo");
+ /// ```
+ #[inline]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_bytes(&self) -> &[u8] {
+ let bytes = self.to_bytes_with_nul();
+ // SAFETY: to_bytes_with_nul returns slice with length at least 1
+ unsafe { bytes.get_unchecked(..bytes.len() - 1) }
+ }
+
+ /// Converts this C string to a byte slice containing the trailing 0 byte.
+ ///
+ /// This function is the equivalent of [`CStr::to_bytes`] except that it
+ /// will retain the trailing nul terminator instead of chopping it off.
+ ///
+ /// > **Note**: This method is currently implemented as a 0-cost cast, but
+ /// > it is planned to alter its definition in the future to perform the
+ /// > length calculation whenever this method is called.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
+ /// ```
+ #[inline]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn to_bytes_with_nul(&self) -> &[u8] {
+ // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
+ // is safe on all supported targets.
+ unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
+ }
+
+ /// Yields a &[str]
slice if the `CStr` contains valid UTF-8.
+ ///
+ /// If the contents of the `CStr` are valid UTF-8 data, this
+ /// function will return the corresponding &[str]
slice. Otherwise,
+ /// it will return an error with details of where UTF-8 validation failed.
+ ///
+ /// [str]: prim@str "str"
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ /// assert_eq!(cstr.to_str(), Ok("foo"));
+ /// ```
+ #[stable(feature = "cstr_to_str", since = "1.4.0")]
+ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+ // N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
+ // instead of in `from_ptr()`, it may be worth considering if this should
+ // be rewritten to do the UTF-8 check inline with the length calculation
+ // instead of doing it afterwards.
+ str::from_utf8(self.to_bytes())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for CStr {
+ fn eq(&self, other: &CStr) -> bool {
+ self.to_bytes().eq(other.to_bytes())
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for CStr {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for CStr {
+ fn partial_cmp(&self, other: &CStr) -> Option {
+ self.to_bytes().partial_cmp(&other.to_bytes())
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for CStr {
+ fn cmp(&self, other: &CStr) -> Ordering {
+ self.to_bytes().cmp(&other.to_bytes())
+ }
+}
+
+#[stable(feature = "cstr_range_from", since = "1.47.0")]
+impl ops::Index> for CStr {
+ type Output = CStr;
+
+ fn index(&self, index: ops::RangeFrom) -> &CStr {
+ let bytes = self.to_bytes_with_nul();
+ // we need to manually check the starting index to account for the null
+ // byte, since otherwise we could get an empty string that doesn't end
+ // in a null.
+ if index.start < bytes.len() {
+ // SAFETY: Non-empty tail of a valid `CStr` is still a valid `CStr`.
+ unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
+ } else {
+ panic!(
+ "index out of bounds: the len is {} but the index is {}",
+ bytes.len(),
+ index.start
+ );
+ }
+ }
+}
+
+#[stable(feature = "cstring_asref", since = "1.7.0")]
+impl AsRef for CStr {
+ #[inline]
+ fn as_ref(&self) -> &CStr {
+ self
+ }
+}
diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs
index e61ea9ce8..6c49521c2 100644
--- a/core/src/ffi/mod.rs
+++ b/core/src/ffi/mod.rs
@@ -14,6 +14,11 @@ use crate::marker::PhantomData;
use crate::num::*;
use crate::ops::{Deref, DerefMut};
+#[unstable(feature = "core_c_str", issue = "94079")]
+pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError};
+
+mod c_str;
+
macro_rules! type_alias_no_nz {
{
$Docfile:tt, $Alias:ident = $Real:ty;
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 6546a5244..78d01c268 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -20,7 +20,7 @@
// FIXME: Fill me in with more detail when the interface settles
//! This library is built on the assumption of a few existing symbols:
//!
-//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
+//! * `memcpy`, `memcmp`, `memset`, `strlen` - These are core memory routines which are
//! often generated by LLVM. Additionally, this library can make explicit
//! calls to these functions. Their signatures are the same as found in C.
//! These functions are often provided by the system libc, but can also be
diff --git a/std/Cargo.toml b/std/Cargo.toml
index dd9b035e8..f2d658320 100644
--- a/std/Cargo.toml
+++ b/std/Cargo.toml
@@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.116", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.69" }
+compiler_builtins = { version = "0.1.71" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
diff --git a/std/src/error.rs b/std/src/error.rs
index 4fb94908c..3f85c2095 100644
--- a/std/src/error.rs
+++ b/std/src/error.rs
@@ -26,6 +26,7 @@ use crate::borrow::Cow;
use crate::cell;
use crate::char;
use crate::fmt::{self, Debug, Display, Write};
+use crate::io;
use crate::mem::transmute;
use crate::num;
use crate::str;
@@ -612,6 +613,48 @@ impl Error for alloc::collections::TryReserveError {}
#[unstable(feature = "duration_checked_float", issue = "83400")]
impl Error for time::FromFloatSecsError {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for alloc::ffi::NulError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "nul byte found in data"
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From for io::Error {
+ /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`].
+ fn from(_: alloc::ffi::NulError) -> io::Error {
+ io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
+ }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for core::ffi::FromBytesWithNulError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl Error for core::ffi::FromBytesUntilNulError {}
+
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
+impl Error for alloc::ffi::FromVecWithNulError {}
+
+#[stable(feature = "cstring_into", since = "1.7.0")]
+impl Error for alloc::ffi::IntoStringError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "C string contained non-utf8 bytes"
+ }
+
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Some(self.__source())
+ }
+}
+
// Copied from `any.rs`.
impl dyn Error + 'static {
/// Returns `true` if the inner type is the same as `T`.
diff --git a/std/src/ffi/mod.rs b/std/src/ffi/mod.rs
index 13e3dacc3..0141a2bcc 100644
--- a/std/src/ffi/mod.rs
+++ b/std/src/ffi/mod.rs
@@ -146,12 +146,24 @@
#![stable(feature = "rust1", since = "1.0.0")]
-#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-pub use self::c_str::FromBytesWithNulError;
+/// See [alloc::ffi::FromVecWithNulError].
#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
-pub use self::c_str::FromVecWithNulError;
+pub type FromVecWithNulError = alloc::ffi::FromVecWithNulError;
+/// See [alloc::ffi::CString].
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type CString = alloc::ffi::CString;
+/// See [alloc::ffi::IntoStringError].
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type IntoStringError = alloc::ffi::IntoStringError;
+/// See [alloc::ffi::NulError].
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::c_str::{CStr, CString, IntoStringError, NulError};
+pub type NulError = alloc::ffi::NulError;
+/// See [core::ffi::CStr].
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type CStr = core::ffi::CStr;
+/// See [core::ffi::FromBytesWithNulError].
+#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
+pub type FromBytesWithNulError = core::ffi::FromBytesWithNulError;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsStr, OsString};
@@ -176,5 +188,4 @@ pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t};
)]
pub use core::ffi::{VaList, VaListImpl};
-mod c_str;
mod os_str;
diff --git a/std/src/lib.rs b/std/src/lib.rs
index 60e7c2af8..039e3d59a 100644
--- a/std/src/lib.rs
+++ b/std/src/lib.rs
@@ -260,7 +260,10 @@
#![feature(atomic_mut_ptr)]
#![feature(char_error_internals)]
#![feature(char_internals)]
+#![feature(core_c_str)]
#![feature(core_intrinsics)]
+#![feature(cstr_from_bytes_until_nul)]
+#![feature(cstr_internals)]
#![feature(duration_checked_float)]
#![feature(duration_constants)]
#![feature(exact_size_is_empty)]
@@ -286,6 +289,7 @@
//
// Library features (alloc):
#![feature(alloc_layout_extra)]
+#![feature(alloc_c_string)]
#![feature(allocator_api)]
#![feature(get_mut_unchecked)]
#![feature(map_try_insert)]
diff --git a/std/src/prelude/v1.rs b/std/src/prelude/v1.rs
index 0226c4d7a..f7533696d 100644
--- a/std/src/prelude/v1.rs
+++ b/std/src/prelude/v1.rs
@@ -95,3 +95,7 @@ pub use crate::string::{String, ToString};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use crate::vec::Vec;
+
+#[cfg(bootstrap)]
+#[unstable(feature = "cstr_internals", issue = "none")]
+pub use alloc::ffi::CStrExt;
diff --git a/std/src/sys/hermit/mod.rs b/std/src/sys/hermit/mod.rs
index 08eca4238..60b7a973c 100644
--- a/std/src/sys/hermit/mod.rs
+++ b/std/src/sys/hermit/mod.rs
@@ -71,16 +71,6 @@ pub fn unsupported_err() -> crate::io::Error {
)
}
-pub unsafe fn strlen(start: *const c_char) -> usize {
- let mut str = start;
-
- while *str != 0 {
- str = str.offset(1);
- }
-
- (str as usize) - (start as usize)
-}
-
#[no_mangle]
pub extern "C" fn floor(x: f64) -> f64 {
unsafe { intrinsics::floorf64(x) }
diff --git a/std/src/sys/sgx/mod.rs b/std/src/sys/sgx/mod.rs
index 1333edb98..696400670 100644
--- a/std/src/sys/sgx/mod.rs
+++ b/std/src/sys/sgx/mod.rs
@@ -5,7 +5,6 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::io::ErrorKind;
-use crate::os::raw::c_char;
use crate::sync::atomic::{AtomicBool, Ordering};
pub mod abi;
@@ -130,15 +129,6 @@ pub fn decode_error_kind(code: i32) -> ErrorKind {
}
}
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
- let mut n = 0;
- while unsafe { *s } != 0 {
- n += 1;
- s = unsafe { s.offset(1) };
- }
- return n;
-}
-
pub fn abort_internal() -> ! {
abi::usercalls::exit(true)
}
diff --git a/std/src/sys/solid/mod.rs b/std/src/sys/solid/mod.rs
index 492b1a554..5ffa381f2 100644
--- a/std/src/sys/solid/mod.rs
+++ b/std/src/sys/solid/mod.rs
@@ -99,5 +99,3 @@ pub fn hashmap_random_keys() -> (u64, u64) {
(x1, x2)
}
}
-
-pub use libc::strlen;
diff --git a/std/src/sys/unix/mod.rs b/std/src/sys/unix/mod.rs
index 3ad03a886..aedeb02e6 100644
--- a/std/src/sys/unix/mod.rs
+++ b/std/src/sys/unix/mod.rs
@@ -3,7 +3,6 @@
use crate::io::ErrorKind;
pub use self::rand::hashmap_random_keys;
-pub use libc::strlen;
#[cfg(not(target_os = "espidf"))]
#[macro_use]
diff --git a/std/src/sys/unsupported/common.rs b/std/src/sys/unsupported/common.rs
index 5274f53a7..4c9ade4a8 100644
--- a/std/src/sys/unsupported/common.rs
+++ b/std/src/sys/unsupported/common.rs
@@ -4,10 +4,6 @@ pub mod memchr {
pub use core::slice::memchr::{memchr, memrchr};
}
-// This is not necessarily correct. May want to consider making it part of the
-// spec definition?
-use crate::os::raw::c_char;
-
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
@@ -38,15 +34,3 @@ pub fn abort_internal() -> ! {
pub fn hashmap_random_keys() -> (u64, u64) {
(1, 2)
}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
- // SAFETY: The caller must guarantee `s` points to a valid 0-terminated string.
- unsafe {
- let mut n = 0;
- while *s != 0 {
- n += 1;
- s = s.offset(1);
- }
- n
- }
-}
diff --git a/std/src/sys/windows/mod.rs b/std/src/sys/windows/mod.rs
index 47917e57b..31c7208bb 100644
--- a/std/src/sys/windows/mod.rs
+++ b/std/src/sys/windows/mod.rs
@@ -7,7 +7,6 @@ use crate::path::PathBuf;
use crate::time::Duration;
pub use self::rand::hashmap_random_keys;
-pub use libc::strlen;
#[macro_use]
pub mod compat;