Skip to content

vastly expand on the mem::uninitialized docs #27488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 74 additions & 6 deletions src/libcore/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The beginning of this sentence sounds a lot like an attempt to appeal to one’s conscience/morality. Dropping the “Hopefully” and “to you” would make this sound much more professional IMO.

This example emphasizes exactly how delicate and dangerous this function is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

/// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is not equivalent from the type mismatch standpoint: the original was an array of vectors, and the example below produces a Vec of Vec. Probably s/equivalent/functionally equivalent/.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I meant semantically equivalent.

/// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d drop this. Its just another justification to use Vec instead of array+mem::uninitialized in this specific example and is not at all applicable in general case. We already have a very strong justification to avoid uninitialized explained in previous paragraphs (both generally and in this specific example), so this is simply redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to appeal to "this might actually be better for perf/execution even though it has an extra allocation" in case someone dismisses the Vec solution for the extra indirection.

/// anyway to avoid blowing the stack.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn uninitialized<T>() -> T {
Expand Down