@@ -214,6 +214,8 @@ impl CStr {
214
214
/// * The memory referenced by the returned `CStr` must not be mutated for
215
215
/// the duration of lifetime `'a`.
216
216
///
217
+ /// * The nul terminator must be within `isize::MAX` from `ptr`
218
+ ///
217
219
/// > **Note**: This operation is intended to be a 0-cost cast but it is
218
220
/// > currently implemented with an up-front calculation of the length of
219
221
/// > the string. This is not guaranteed to always be the case.
@@ -259,42 +261,16 @@ impl CStr {
259
261
#[ rustc_const_unstable( feature = "const_cstr_from_ptr" , issue = "113219" ) ]
260
262
pub const unsafe fn from_ptr < ' a > ( ptr : * const c_char ) -> & ' a CStr {
261
263
// SAFETY: The caller has provided a pointer that points to a valid C
262
- // string with a NUL terminator of size less than `isize::MAX`, whose
263
- // content remain valid and doesn't change for the lifetime of the
264
- // returned `CStr`.
265
- //
266
- // Thus computing the length is fine (a NUL byte exists), the call to
267
- // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
268
- // the call to `from_bytes_with_nul_unchecked` is correct.
264
+ // string with a NUL terminator less than `isize::MAX` from `ptr`.
265
+ let len = unsafe { const_strlen ( ptr ) } ;
266
+
267
+ // SAFETY: The caller has provided a valid pointer with length less than
268
+ // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid
269
+ // and doesn't change for the lifetime of the returned `CStr`. This
270
+ // means the call to `from_bytes_with_nul_unchecked` is correct.
269
271
//
270
272
// The cast from c_char to u8 is ok because a c_char is always one byte.
271
- unsafe {
272
- const fn strlen_ct ( s : * const c_char ) -> usize {
273
- let mut len = 0 ;
274
-
275
- // SAFETY: Outer caller has provided a pointer to a valid C string.
276
- while unsafe { * s. add ( len) } != 0 {
277
- len += 1 ;
278
- }
279
-
280
- len
281
- }
282
-
283
- // `inline` is necessary for codegen to see strlen.
284
- #[ inline]
285
- fn strlen_rt ( s : * const c_char ) -> usize {
286
- extern "C" {
287
- /// Provided by libc or compiler_builtins.
288
- fn strlen ( s : * const c_char ) -> usize ;
289
- }
290
-
291
- // SAFETY: Outer caller has provided a pointer to a valid C string.
292
- unsafe { strlen ( s) }
293
- }
294
-
295
- let len = intrinsics:: const_eval_select ( ( ptr, ) , strlen_ct, strlen_rt) ;
296
- Self :: from_bytes_with_nul_unchecked ( slice:: from_raw_parts ( ptr. cast ( ) , len + 1 ) )
297
- }
273
+ unsafe { Self :: from_bytes_with_nul_unchecked ( slice:: from_raw_parts ( ptr. cast ( ) , len + 1 ) ) }
298
274
}
299
275
300
276
/// Creates a C string wrapper from a byte slice with any number of nuls.
@@ -681,3 +657,37 @@ impl AsRef<CStr> for CStr {
681
657
self
682
658
}
683
659
}
660
+
661
+ /// Calculate the length of a nul-terminated string. Defers to C's `strlen` when possible.
662
+ ///
663
+ /// # Safety
664
+ ///
665
+ /// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be
666
+ /// located within `isize::MAX` from `ptr`.
667
+ #[ inline]
668
+ const unsafe fn const_strlen ( ptr : * const c_char ) -> usize {
669
+ const fn strlen_ct ( s : * const c_char ) -> usize {
670
+ let mut len = 0 ;
671
+
672
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
673
+ while unsafe { * s. add ( len) } != 0 {
674
+ len += 1 ;
675
+ }
676
+
677
+ len
678
+ }
679
+
680
+ #[ inline]
681
+ fn strlen_rt ( s : * const c_char ) -> usize {
682
+ extern "C" {
683
+ /// Provided by libc or compiler_builtins.
684
+ fn strlen ( s : * const c_char ) -> usize ;
685
+ }
686
+
687
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
688
+ unsafe { strlen ( s) }
689
+ }
690
+
691
+ // SAFETY: the two functions always provide equivalent functionality
692
+ unsafe { intrinsics:: const_eval_select ( ( ptr, ) , strlen_ct, strlen_rt) }
693
+ }
0 commit comments