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
@ -253,21 +253,89 @@ pub unsafe fn dropped<T>() -> T {
|
||||
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
|
||||
/// falls out of scope (due to unwinding or returning) before being initialized, then the
|
||||
/// destructor will run on uninitialized data, likely leading to crashes.
|
||||
/// **This is incredibly dangerous, and should not be done lightly. Deeply
|
||||
/// consider initializing your memory with a default value instead.**
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// Here's how to safely initialize an array of `Vec`s.
|
||||
///
|
||||
/// ```
|
||||
/// 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]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn uninitialized<T>() -> T {
|
||||
|
Loading…
Reference in New Issue
Block a user