@@ -509,26 +509,169 @@ impl<T> MaybeUninit<T> {
509
509
self . as_ptr ( ) . read ( )
510
510
}
511
511
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()`).
513
517
///
514
518
/// # Safety
515
519
///
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
+ /// ```
519
568
#[ unstable( feature = "maybe_uninit_ref" , issue = "63568" ) ]
520
569
#[ inline( always) ]
521
570
pub unsafe fn get_ref ( & self ) -> & T {
522
571
& * self . value
523
572
}
524
573
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()`).
526
579
///
527
580
/// # Safety
528
581
///
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
+ /// ```
532
675
// FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
533
676
// to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
534
677
// a final decision about the rules before stabilization.
0 commit comments