Rollup merge of #99084 - RalfJung:write_bytes, r=thomcc
clarify how write_bytes can lead to UB due to invalid values Fixes https://github.com/rust-lang/unsafe-code-guidelines/issues/330 Cc ``@5225225``
This commit is contained in:
commit
aeca079d7e
@ -2566,14 +2566,23 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
///
|
||||
/// * `dst` must be properly aligned.
|
||||
///
|
||||
/// Additionally, the caller must ensure that writing `count *
|
||||
/// size_of::<T>()` bytes to the given region of memory results in a valid
|
||||
/// value of `T`. Using a region of memory typed as a `T` that contains an
|
||||
/// invalid value of `T` is undefined behavior.
|
||||
///
|
||||
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
|
||||
/// `0`, the pointer must be non-null and properly aligned.
|
||||
///
|
||||
/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
|
||||
/// later if the written bytes are not a valid representation of some `T`. For instance, the
|
||||
/// following is an **incorrect** use of this function:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// unsafe {
|
||||
/// let mut value: u8 = 0;
|
||||
/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
|
||||
/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
|
||||
/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
|
||||
/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [valid]: crate::ptr#safety
|
||||
///
|
||||
/// # Examples
|
||||
@ -2590,38 +2599,6 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
/// }
|
||||
/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
|
||||
/// ```
|
||||
///
|
||||
/// Creating an invalid value:
|
||||
///
|
||||
/// ```
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// let mut v = Box::new(0i32);
|
||||
///
|
||||
/// unsafe {
|
||||
/// // Leaks the previously held value by overwriting the `Box<T>` with
|
||||
/// // a null pointer.
|
||||
/// ptr::write_bytes(&mut v as *mut Box<i32>, 0, 1);
|
||||
/// }
|
||||
///
|
||||
/// // At this point, using or dropping `v` results in undefined behavior.
|
||||
/// // drop(v); // ERROR
|
||||
///
|
||||
/// // Even leaking `v` "uses" it, and hence is undefined behavior.
|
||||
/// // mem::forget(v); // ERROR
|
||||
///
|
||||
/// // In fact, `v` is invalid according to basic type layout invariants, so *any*
|
||||
/// // operation touching it is undefined behavior.
|
||||
/// // let v2 = v; // ERROR
|
||||
///
|
||||
/// unsafe {
|
||||
/// // Let us instead put in a valid value
|
||||
/// ptr::write(&mut v as *mut Box<i32>, Box::new(42i32));
|
||||
/// }
|
||||
///
|
||||
/// // Now the box is fine
|
||||
/// assert_eq!(*v, 42);
|
||||
/// ```
|
||||
#[doc(alias = "memset")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user