Skip to content

Commit 76ba3f0

Browse files
committed
Auto merge of #27488 - Gankro:uninit-docs, r=bluss
Inspired by #27484
2 parents ea5cc76 + 5e6973d commit 76ba3f0

File tree

1 file changed

+74
-6
lines changed

1 file changed

+74
-6
lines changed

src/libcore/mem.rs

+74-6
Original file line numberDiff line numberDiff line change
@@ -253,21 +253,89 @@ pub unsafe fn dropped<T>() -> T {
253253
dropped_impl()
254254
}
255255

256-
/// Creates an uninitialized value.
256+
/// Bypasses Rust's normal memory-initialization checks by pretending to
257+
/// produce a value of type T, while doing nothing at all.
257258
///
258-
/// Care must be taken when using this function, if the type `T` has a destructor and the value
259-
/// falls out of scope (due to unwinding or returning) before being initialized, then the
260-
/// destructor will run on uninitialized data, likely leading to crashes.
259+
/// **This is incredibly dangerous, and should not be done lightly. Deeply
260+
/// consider initializing your memory with a default value instead.**
261261
///
262-
/// This is useful for FFI functions sometimes, but should generally be avoided.
262+
/// This is useful for FFI functions and initializing arrays sometimes,
263+
/// but should generally be avoided.
264+
///
265+
/// # Undefined Behaviour
266+
///
267+
/// It is Undefined Behaviour to read uninitialized memory. Even just an
268+
/// uninitialized boolean. For instance, if you branch on the value of such
269+
/// a boolean your program may take one, both, or neither of the branches.
270+
///
271+
/// Note that this often also includes *writing* to the uninitialized value.
272+
/// Rust believes the value is initialized, and will therefore try to Drop
273+
/// the uninitialized value and its fields if you try to overwrite the memory
274+
/// in a normal manner. The only way to safely initialize an arbitrary
275+
/// uninitialized value is with one of the `ptr` functions: `write`, `copy`, or
276+
/// `copy_nonoverlapping`. This isn't necessary if `T` is a primitive
277+
/// or otherwise only contains types that don't implement Drop.
278+
///
279+
/// If this value *does* need some kind of Drop, it must be initialized before
280+
/// it goes out of scope (and therefore would be dropped). Note that this
281+
/// includes a `panic` occurring and unwinding the stack suddenly.
263282
///
264283
/// # Examples
265284
///
285+
/// Here's how to safely initialize an array of `Vec`s.
286+
///
266287
/// ```
267288
/// use std::mem;
289+
/// use std::ptr;
268290
///
269-
/// let x: i32 = unsafe { mem::uninitialized() };
291+
/// // Only declare the array. This safely leaves it
292+
/// // uninitialized in a way that Rust will track for us.
293+
/// // However we can't initialize it element-by-element
294+
/// // safely, and we can't use the `[value; 1000]`
295+
/// // constructor because it only works with `Copy` data.
296+
/// let mut data: [Vec<u32>; 1000];
297+
///
298+
/// unsafe {
299+
/// // So we need to do this to initialize it.
300+
/// data = mem::uninitialized();
301+
///
302+
/// // DANGER ZONE: if anything panics or otherwise
303+
/// // incorrectly reads the array here, we will have
304+
/// // Undefined Behaviour.
305+
///
306+
/// // It's ok to mutably iterate the data, since this
307+
/// // doesn't involve reading it at all.
308+
/// // (ptr and len are statically known for arrays)
309+
/// for elem in &mut data[..] {
310+
/// // *elem = Vec::new() would try to drop the
311+
/// // uninitialized memory at `elem` -- bad!
312+
/// //
313+
/// // Vec::new doesn't allocate or do really
314+
/// // anything. It's only safe to call here
315+
/// // because we know it won't panic.
316+
/// ptr::write(elem, Vec::new());
317+
/// }
318+
///
319+
/// // SAFE ZONE: everything is initialized.
320+
/// }
321+
///
322+
/// println!("{:?}", &data[0]);
270323
/// ```
324+
///
325+
/// Hopefully this example emphasizes to you exactly how delicate
326+
/// and dangerous doing this is. Note that the `vec!` macro
327+
/// *does* let you initialize every element with a value that
328+
/// is only `Clone`, so the following is equivalent and vastly
329+
/// less dangerous, as long as you can live with an extra heap
330+
/// allocation:
331+
///
332+
/// ```
333+
/// let data: Vec<Vec<u32>> = vec![Vec::new(); 1000];
334+
/// println!("{:?}", &data[0]);
335+
/// ```
336+
///
337+
/// For large arrays this is probably advisable
338+
/// anyway to avoid blowing the stack.
271339
#[inline]
272340
#[stable(feature = "rust1", since = "1.0.0")]
273341
pub unsafe fn uninitialized<T>() -> T {

0 commit comments

Comments
 (0)