Skip to content

Commit

Permalink
Do not use CString in the examples of CStr.
Browse files Browse the repository at this point in the history
  • Loading branch information
hkBst committed Jan 28, 2025
1 parent aa6f5ab commit 57cf30f
Showing 1 changed file with 54 additions and 36 deletions.
90 changes: 54 additions & 36 deletions library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,15 @@ use crate::{fmt, ops, slice, str};
/// Passing a Rust-originating C string:
///
/// ```
/// use std::ffi::{CString, CStr};
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// fn work(data: &CStr) {
/// # /* Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn work_with(data: *const c_char); }
/// # */ unsafe extern "C" fn work_with(s: *const c_char) {}
///
/// unsafe extern "C" fn work_with(s: *const c_char) {}
/// unsafe { work_with(data.as_ptr()) }
/// }
///
/// let s = CString::new("data data data data").expect("CString::new failed");
/// let s = c"Hello world!";
/// work(&s);
/// ```
///
Expand Down Expand Up @@ -384,13 +381,12 @@ impl CStr {
/// # Examples
///
/// ```
/// use std::ffi::{CStr, CString};
/// use std::ffi::CStr;
///
/// 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);
/// }
/// let bytes = b"Hello world!\0";
///
/// let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(bytes) };
/// assert_eq!(cstr.to_bytes_with_nul(), bytes);
/// ```
#[inline]
#[must_use]
Expand Down Expand Up @@ -449,38 +445,60 @@ impl CStr {
/// behavior when `ptr` is used inside the `unsafe` block:
///
/// ```no_run
/// # #![allow(unused_must_use)]
/// # #![expect(dangling_pointers_from_temporaries)]
/// use std::ffi::CString;
///
/// // Do not do this:
/// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
/// unsafe {
/// // `ptr` is dangling
/// *ptr;
/// }
/// let ptr = std::ffi::CStr::from_bytes_with_nul(
/// &"Hello world!"
/// .to_uppercase()
/// .chars()
/// .map(|c| c.try_into().unwrap())
/// .chain(std::iter::once(0))
/// .collect::<Vec<u8>>(),
/// )
/// .unwrap()
/// .as_ptr();
/// // above CStr temporary was dropped and `ptr` is now dangling!
///
/// // shows ptr is now garbage
/// assert_eq!(
/// (0..)
/// .map_while(|i| unsafe {
/// let p = ptr.add(i);
/// (*p != 0).then_some(*p as u8 as char)
/// })
/// .collect::<String>(),
/// "Hello world!".to_uppercase()
/// );
/// ```
///
/// 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:
/// lifetime information and the `CStr` is deallocated immediately after
/// the expression it is part of is evaluated.
/// To fix the problem, bind the `CStr` 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;
/// }
/// let c_str = std::ffi::CStr::from_bytes_with_nul(
/// &"Hello world!"
/// .to_uppercase()
/// .chars()
/// .map(|c| c.try_into().unwrap())
/// .chain(std::iter::once(0))
/// .collect::<Vec<u8>>(),
/// )
/// .unwrap();
/// // above CStr is now bound and will not be dropped immediately
/// let ptr = c_str.as_ptr();
///
/// assert_eq!(
/// (0..)
/// .map_while(|i| unsafe {
/// let p = ptr.add(i);
/// (*p != 0).then_some(*p as u8 as char)
/// })
/// .collect::<String>(),
/// "Hello world!".to_uppercase()
/// );
/// ```
///
/// 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")]
Expand Down

0 comments on commit 57cf30f

Please sign in to comment.