Auto merge of #27488 - Gankro:uninit-docs, r=bluss
Inspired by https://github.com/rust-lang/rust/issues/27484
This commit is contained in:
commit
76ba3f0dd9
1 changed files with 74 additions and 6 deletions
|
@ -253,21 +253,89 @@ pub unsafe fn dropped<T>() -> T {
|
||||||
dropped_impl()
|
dropped_impl()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an uninitialized value.
|
/// Bypasses Rust's normal memory-initialization checks by pretending to
|
||||||
|
/// produce a value of type T, while doing nothing at all.
|
||||||
///
|
///
|
||||||
/// Care must be taken when using this function, if the type `T` has a destructor and the value
|
/// **This is incredibly dangerous, and should not be done lightly. Deeply
|
||||||
/// falls out of scope (due to unwinding or returning) before being initialized, then the
|
/// consider initializing your memory with a default value instead.**
|
||||||
/// destructor will run on uninitialized data, likely leading to crashes.
|
|
||||||
///
|
///
|
||||||
/// This is useful for FFI functions sometimes, but should generally be avoided.
|
/// This is useful for FFI functions and initializing arrays sometimes,
|
||||||
|
/// but should generally be avoided.
|
||||||
|
///
|
||||||
|
/// # Undefined Behaviour
|
||||||
|
///
|
||||||
|
/// It is Undefined Behaviour to read uninitialized memory. Even just an
|
||||||
|
/// uninitialized boolean. For instance, if you branch on the value of such
|
||||||
|
/// a boolean your program may take one, both, or neither of the branches.
|
||||||
|
///
|
||||||
|
/// Note that this often also includes *writing* to the uninitialized value.
|
||||||
|
/// Rust believes the value is initialized, and will therefore try to Drop
|
||||||
|
/// the uninitialized value and its fields if you try to overwrite the memory
|
||||||
|
/// in a normal manner. The only way to safely initialize an arbitrary
|
||||||
|
/// uninitialized value is with one of the `ptr` functions: `write`, `copy`, or
|
||||||
|
/// `copy_nonoverlapping`. This isn't necessary if `T` is a primitive
|
||||||
|
/// or otherwise only contains types that don't implement Drop.
|
||||||
|
///
|
||||||
|
/// If this value *does* need some kind of Drop, it must be initialized before
|
||||||
|
/// it goes out of scope (and therefore would be dropped). Note that this
|
||||||
|
/// includes a `panic` occurring and unwinding the stack suddenly.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
/// Here's how to safely initialize an array of `Vec`s.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::mem;
|
/// use std::mem;
|
||||||
|
/// use std::ptr;
|
||||||
///
|
///
|
||||||
/// let x: i32 = unsafe { mem::uninitialized() };
|
/// // Only declare the array. This safely leaves it
|
||||||
|
/// // uninitialized in a way that Rust will track for us.
|
||||||
|
/// // However we can't initialize it element-by-element
|
||||||
|
/// // safely, and we can't use the `[value; 1000]`
|
||||||
|
/// // constructor because it only works with `Copy` data.
|
||||||
|
/// let mut data: [Vec<u32>; 1000];
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// // So we need to do this to initialize it.
|
||||||
|
/// data = mem::uninitialized();
|
||||||
|
///
|
||||||
|
/// // DANGER ZONE: if anything panics or otherwise
|
||||||
|
/// // incorrectly reads the array here, we will have
|
||||||
|
/// // Undefined Behaviour.
|
||||||
|
///
|
||||||
|
/// // It's ok to mutably iterate the data, since this
|
||||||
|
/// // doesn't involve reading it at all.
|
||||||
|
/// // (ptr and len are statically known for arrays)
|
||||||
|
/// for elem in &mut data[..] {
|
||||||
|
/// // *elem = Vec::new() would try to drop the
|
||||||
|
/// // uninitialized memory at `elem` -- bad!
|
||||||
|
/// //
|
||||||
|
/// // Vec::new doesn't allocate or do really
|
||||||
|
/// // anything. It's only safe to call here
|
||||||
|
/// // because we know it won't panic.
|
||||||
|
/// ptr::write(elem, Vec::new());
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // SAFE ZONE: everything is initialized.
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// println!("{:?}", &data[0]);
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Hopefully this example emphasizes to you exactly how delicate
|
||||||
|
/// and dangerous doing this is. Note that the `vec!` macro
|
||||||
|
/// *does* let you initialize every element with a value that
|
||||||
|
/// is only `Clone`, so the following is equivalent and vastly
|
||||||
|
/// less dangerous, as long as you can live with an extra heap
|
||||||
|
/// allocation:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let data: Vec<Vec<u32>> = vec![Vec::new(); 1000];
|
||||||
|
/// println!("{:?}", &data[0]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// For large arrays this is probably advisable
|
||||||
|
/// anyway to avoid blowing the stack.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub unsafe fn uninitialized<T>() -> T {
|
pub unsafe fn uninitialized<T>() -> T {
|
||||||
|
|
Loading…
Add table
Reference in a new issue