Skip to content

Commit 57cf30f

Browse files
committed
Do not use CString in the examples of CStr.
Fixes rust-lang#83999.
1 parent aa6f5ab commit 57cf30f

File tree

1 file changed

+54
-36
lines changed

1 file changed

+54
-36
lines changed

library/core/src/ffi/c_str.rs

+54-36
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,15 @@ use crate::{fmt, ops, slice, str};
5555
/// Passing a Rust-originating C string:
5656
///
5757
/// ```
58-
/// use std::ffi::{CString, CStr};
58+
/// use std::ffi::CStr;
5959
/// use std::os::raw::c_char;
6060
///
6161
/// fn work(data: &CStr) {
62-
/// # /* Extern functions are awkward in doc comments - fake it instead
63-
/// extern "C" { fn work_with(data: *const c_char); }
64-
/// # */ unsafe extern "C" fn work_with(s: *const c_char) {}
65-
///
62+
/// unsafe extern "C" fn work_with(s: *const c_char) {}
6663
/// unsafe { work_with(data.as_ptr()) }
6764
/// }
6865
///
69-
/// let s = CString::new("data data data data").expect("CString::new failed");
66+
/// let s = c"Hello world!";
7067
/// work(&s);
7168
/// ```
7269
///
@@ -384,13 +381,12 @@ impl CStr {
384381
/// # Examples
385382
///
386383
/// ```
387-
/// use std::ffi::{CStr, CString};
384+
/// use std::ffi::CStr;
388385
///
389-
/// unsafe {
390-
/// let cstring = CString::new("hello").expect("CString::new failed");
391-
/// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
392-
/// assert_eq!(cstr, &*cstring);
393-
/// }
386+
/// let bytes = b"Hello world!\0";
387+
///
388+
/// let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(bytes) };
389+
/// assert_eq!(cstr.to_bytes_with_nul(), bytes);
394390
/// ```
395391
#[inline]
396392
#[must_use]
@@ -449,38 +445,60 @@ impl CStr {
449445
/// behavior when `ptr` is used inside the `unsafe` block:
450446
///
451447
/// ```no_run
452-
/// # #![allow(unused_must_use)]
453448
/// # #![expect(dangling_pointers_from_temporaries)]
454-
/// use std::ffi::CString;
455-
///
456449
/// // Do not do this:
457-
/// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
458-
/// unsafe {
459-
/// // `ptr` is dangling
460-
/// *ptr;
461-
/// }
450+
/// let ptr = std::ffi::CStr::from_bytes_with_nul(
451+
/// &"Hello world!"
452+
/// .to_uppercase()
453+
/// .chars()
454+
/// .map(|c| c.try_into().unwrap())
455+
/// .chain(std::iter::once(0))
456+
/// .collect::<Vec<u8>>(),
457+
/// )
458+
/// .unwrap()
459+
/// .as_ptr();
460+
/// // above CStr temporary was dropped and `ptr` is now dangling!
461+
///
462+
/// // shows ptr is now garbage
463+
/// assert_eq!(
464+
/// (0..)
465+
/// .map_while(|i| unsafe {
466+
/// let p = ptr.add(i);
467+
/// (*p != 0).then_some(*p as u8 as char)
468+
/// })
469+
/// .collect::<String>(),
470+
/// "Hello world!".to_uppercase()
471+
/// );
462472
/// ```
463473
///
464474
/// This happens because the pointer returned by `as_ptr` does not carry any
465-
/// lifetime information and the `CString` is deallocated immediately after
466-
/// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
467-
/// expression is evaluated.
468-
/// To fix the problem, bind the `CString` to a local variable:
475+
/// lifetime information and the `CStr` is deallocated immediately after
476+
/// the expression it is part of is evaluated.
477+
/// To fix the problem, bind the `CStr` to a local variable:
469478
///
470479
/// ```no_run
471-
/// # #![allow(unused_must_use)]
472-
/// use std::ffi::CString;
473-
///
474-
/// let hello = CString::new("Hello").expect("CString::new failed");
475-
/// let ptr = hello.as_ptr();
476-
/// unsafe {
477-
/// // `ptr` is valid because `hello` is in scope
478-
/// *ptr;
479-
/// }
480+
/// let c_str = std::ffi::CStr::from_bytes_with_nul(
481+
/// &"Hello world!"
482+
/// .to_uppercase()
483+
/// .chars()
484+
/// .map(|c| c.try_into().unwrap())
485+
/// .chain(std::iter::once(0))
486+
/// .collect::<Vec<u8>>(),
487+
/// )
488+
/// .unwrap();
489+
/// // above CStr is now bound and will not be dropped immediately
490+
/// let ptr = c_str.as_ptr();
491+
///
492+
/// assert_eq!(
493+
/// (0..)
494+
/// .map_while(|i| unsafe {
495+
/// let p = ptr.add(i);
496+
/// (*p != 0).then_some(*p as u8 as char)
497+
/// })
498+
/// .collect::<String>(),
499+
/// "Hello world!".to_uppercase()
500+
/// );
480501
/// ```
481-
///
482-
/// This way, the lifetime of the `CString` in `hello` encompasses
483-
/// the lifetime of `ptr` and the `unsafe` block.
484502
#[inline]
485503
#[must_use]
486504
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)