summaryrefslogtreecommitdiffstats
path: root/library/core/src/ffi
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /library/core/src/ffi
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/ffi')
-rw-r--r--library/core/src/ffi/c_str.rs107
1 files changed, 73 insertions, 34 deletions
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 163a65c90..93a6716d7 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -214,6 +214,8 @@ impl CStr {
/// * The memory referenced by the returned `CStr` must not be mutated for
/// the duration of lifetime `'a`.
///
+ /// * The nul terminator must be within `isize::MAX` from `ptr`
+ ///
/// > **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.
@@ -259,42 +261,16 @@ impl CStr {
#[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
pub const 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.
+ // string with a NUL terminator less than `isize::MAX` from `ptr`.
+ let len = unsafe { const_strlen(ptr) };
+
+ // SAFETY: The caller has provided a valid pointer with length less than
+ // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid
+ // and doesn't change for the lifetime of the returned `CStr`. This
+ // means 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 {
- const fn strlen_ct(s: *const c_char) -> usize {
- let mut len = 0;
-
- // SAFETY: Outer caller has provided a pointer to a valid C string.
- while unsafe { *s.add(len) } != 0 {
- len += 1;
- }
-
- len
- }
-
- // `inline` is necessary for codegen to see strlen.
- #[inline]
- fn strlen_rt(s: *const c_char) -> usize {
- extern "C" {
- /// Provided by libc or compiler_builtins.
- fn strlen(s: *const c_char) -> usize;
- }
-
- // SAFETY: Outer caller has provided a pointer to a valid C string.
- unsafe { strlen(s) }
- }
-
- let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt);
- Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1))
- }
+ unsafe { Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1)) }
}
/// Creates a C string wrapper from a byte slice with any number of nuls.
@@ -511,10 +487,39 @@ impl CStr {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+ #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
pub const fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr()
}
+ /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator.
+ ///
+ /// > **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
+ ///
+ /// ```
+ /// #![feature(cstr_count_bytes)]
+ ///
+ /// use std::ffi::CStr;
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
+ /// assert_eq!(cstr.count_bytes(), 3);
+ ///
+ /// let cstr = CStr::from_bytes_with_nul(b"\0").unwrap();
+ /// assert_eq!(cstr.count_bytes(), 0);
+ /// ```
+ #[inline]
+ #[must_use]
+ #[doc(alias("len", "strlen"))]
+ #[unstable(feature = "cstr_count_bytes", issue = "114441")]
+ #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
+ pub const fn count_bytes(&self) -> usize {
+ self.inner.len() - 1
+ }
+
/// Returns `true` if `self.to_bytes()` has a length of 0.
///
/// # Examples
@@ -681,3 +686,37 @@ impl AsRef<CStr> for CStr {
self
}
}
+
+/// Calculate the length of a nul-terminated string. Defers to C's `strlen` when possible.
+///
+/// # Safety
+///
+/// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be
+/// located within `isize::MAX` from `ptr`.
+#[inline]
+const unsafe fn const_strlen(ptr: *const c_char) -> usize {
+ const fn strlen_ct(s: *const c_char) -> usize {
+ let mut len = 0;
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ while unsafe { *s.add(len) } != 0 {
+ len += 1;
+ }
+
+ len
+ }
+
+ #[inline]
+ fn strlen_rt(s: *const c_char) -> usize {
+ extern "C" {
+ /// Provided by libc or compiler_builtins.
+ fn strlen(s: *const c_char) -> usize;
+ }
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ unsafe { strlen(s) }
+ }
+
+ // SAFETY: the two functions always provide equivalent functionality
+ unsafe { intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) }
+}