@@ -509,26 +509,169 @@ impl<T> MaybeUninit<T> {
509509 self . as_ptr ( ) . read ( )
510510 }
511511
512- /// Gets a reference to the contained value.
512+ /// Gets a shared reference to the contained value.
513+ ///
514+ /// This can be useful when we want to access a `MaybeUninit` that has been
515+ /// initialized but don't have ownership of the `MaybeUninit` (preventing the use
516+ /// of `.assume_init()`).
513517 ///
514518 /// # Safety
515519 ///
516- /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
517- /// state. Calling this when the content is not yet fully initialized causes undefined
518- /// behavior.
520+ /// Calling this when the content is not yet fully initialized causes undefined
521+ /// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
522+ /// is in an initialized state.
523+ ///
524+ /// # Examples
525+ ///
526+ /// ### Correct usage of this method:
527+ ///
528+ /// ```rust
529+ /// use ::std::mem::MaybeUninit;
530+ ///
531+ /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
532+ /// // Initialize `x`:
533+ /// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); }
534+ /// /* The above line can also be done without unsafe:
535+ /// x = MaybeUninit::new(vec![1, 2, 3]); // */
536+ /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to
537+ /// // create a shared reference to it:
538+ /// let x: &Vec<u32> = unsafe {
539+ /// // # Safety
540+ /// //
541+ /// // - `x` has been initialized.
542+ /// x.get_ref()
543+ /// };
544+ /// assert_eq!(x, &vec![1, 2, 3]);
545+ /// ```
546+ ///
547+ /// ### *Incorrect* usages of this method:
548+ ///
549+ /// ```rust,no_run
550+ /// use std::mem::MaybeUninit;
551+ ///
552+ /// let x = MaybeUninit::<Vec<u32>>::uninit();
553+ /// let x_vec: &Vec<u32> = unsafe { x.get_ref() };
554+ /// // We have created a reference to an uninitialized vector! This is undefined behavior.
555+ /// ```
556+ ///
557+ /// ```rust,no_run
558+ /// use std::{cell::Cell, mem::MaybeUninit};
559+ ///
560+ /// let b = MaybeUninit::<Cell<bool>>::uninit();
561+ /// // Initialize the `MaybeUninit` using `Cell::set`:
562+ /// unsafe {
563+ /// b.get_ref().set(true);
564+ /// // ^^^^^^^^^^^
565+ /// // Reference to an uninitialized `Cell<bool>`: UB!
566+ /// }
567+ /// ```
519568 #[ unstable( feature = "maybe_uninit_ref" , issue = "63568" ) ]
520569 #[ inline( always) ]
521570 pub unsafe fn get_ref ( & self ) -> & T {
522571 & * self . value
523572 }
524573
525- /// Gets a mutable reference to the contained value.
574+ /// Gets a mutable (unique) reference to the contained value.
575+ ///
576+ /// This can be useful when we want to access a `MaybeUninit` that has been
577+ /// initialized but don't have ownership of the `MaybeUninit` (preventing the use
578+ /// of `.assume_init()`).
526579 ///
527580 /// # Safety
528581 ///
529- /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
530- /// state. Calling this when the content is not yet fully initialized causes undefined
531- /// behavior.
582+ /// Calling this when the content is not yet fully initialized causes undefined
583+ /// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
584+ /// is in an initialized state. For instance, `.get_mut()` cannot be used to
585+ /// initialize a `MaybeUninit`.
586+ ///
587+ /// # Examples
588+ ///
589+ /// ### Correct usage of this method:
590+ ///
591+ /// ```rust
592+ /// use ::std::mem::MaybeUninit;
593+ ///
594+ /// # unsafe extern "C" fn initialize_buffer (buf: *mut [u8; 2048]) { *buf = [0; 2048] }
595+ /// # #[cfg(FALSE)]
596+ /// extern "C" {
597+ /// /// Initializes *all* the bytes of the input buffer.
598+ /// fn initialize_buffer (buf: *mut [u8; 2048]);
599+ /// }
600+ ///
601+ /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit();
602+ /// // Initialize `buf`:
603+ /// unsafe { initialize_buffer(buf.as_mut_ptr()); }
604+ /// // Now we know that `buf` has been initialized; so we could `.assume_init()` it.
605+ /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes.
606+ /// // To assert our buffer has been initialized without copying it, we upgrade
607+ /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`:
608+ /// let buf: &mut [u8; 2048] = unsafe {
609+ /// // # Safety
610+ /// //
611+ /// // - `buf` has been initialized.
612+ /// buf.get_mut()
613+ /// };
614+ /// // Now we can use `buf` as a normal slice:
615+ /// buf.sort_unstable();
616+ /// assert!(buf.is_sorted());
617+ /// ```
618+ ///
619+ /// ### *Incorrect* usages of this method:
620+ ///
621+ /// Do not use `.get_mut()` to initialize a value
622+ ///
623+ /// ```rust,no_run
624+ /// use std::mem::MaybeUninit;
625+ ///
626+ /// let mut b = MaybeUninit::<bool>::uninit();
627+ /// unsafe {
628+ /// *b.get_mut() = true;
629+ /// // We have created a (mutable) reference to an uninitialized `bool`!
630+ /// // This is undefined behavior.
631+ /// }
632+ /// ```
633+ ///
634+ /// For instance, you cannot [`Read`] into an uninitialized buffer.
635+ ///
636+ /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
637+ ///
638+ /// ```rust,no_run
639+ /// use std::{io, mem::MaybeUninit};
640+ ///
641+ /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]>
642+ /// {
643+ /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit();
644+ /// reader.read_exact(unsafe { buffer.get_mut() })?;
645+ /// // ^^^^^^^^^^^^^^^^
646+ /// // (mutable) reference to uninitialized memory!
647+ /// // This is undefined behavior.
648+ /// Ok(buffer.assume_init())
649+ /// }
650+ /// ```
651+ ///
652+ /// Nor can you use direct field access to do field-by-field gradual initialization.
653+ ///
654+ /// ```rust,no_run
655+ /// use std::mem::MaybeUninit;
656+ ///
657+ /// struct Foo {
658+ /// a: u32,
659+ /// b: u8,
660+ /// }
661+ ///
662+ /// let foo: Foo = unsafe {
663+ /// let foo = MaybeUninit::<Foo>::uninit();
664+ /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337);
665+ /// // ^^^^^^^^^^^^^
666+ /// // (mutable) reference to uninitialized memory!
667+ /// // This is undefined behavior.
668+ /// ptr::write(&mut foo.get_mut().b as *mut u8, 42);
669+ /// // ^^^^^^^^^^^^^
670+ /// // (mutable) reference to uninitialized memory!
671+ /// // This is undefined behavior.
672+ /// foo.assume_init()
673+ /// };
674+ /// ```
532675 // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
533676 // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
534677 // a final decision about the rules before stabilization.
0 commit comments