Skip to content

Is assignment to an uninit but non-Drop place okay? #596

Open

Description

@ChayimFriedman2

I don't see an issue about this (although #307) is close, and I'm pretty sure this is undecided.

Can we use assignment (and not ptr::write()) to write to an uninitialized place of a type that does not have a drop glue? That is, this:

fn main() {
    let mut v = std::mem::MaybeUninit::<i32>::uninit();
    unsafe {
        *v.as_mut_ptr() = 123;
    }
}

Miri does not flag this.

Activity

  1. RalfJung commented on Dec 30, 2025

    @RalfJung
    Member

    Seems fairly clear to me that this is fine. How could this code plausibly have UB?

  2. ChayimFriedman2 commented on Dec 30, 2025

    @ChayimFriedman2
    Author

    If we say that dropping a value always touches it, even if it does not has a drop glue.

  3. LoganDark commented on Jan 29, 2026

    @LoganDark

    If we say that dropping a value always touches it, even if it does not has a drop glue.

    I would assume dropping a MaybeUninit<T> does touch the MaybeUninit<T>, but MaybeUninit<T> does not touch the T.

  4. ia0 commented on Jan 29, 2026

    @ia0

    The OP code does not drop a MaybeUninit<T>. It drops a T because MaybeUninit::as_mut_ptr() returns a *mut T. The question is whether dropping that invalid value (and thus also unsafe value) is UB, knowing that there's no drop glue. And it seems the answer is that it's not UB. If there's no drop glue, the value to be dropped does not get materialized and its validity is thus irrelevant.

  5. LoganDark commented on Jan 29, 2026

    @LoganDark

    In that case I would assume dereferencing the pointer is immediate UB even if it's only used in a place for an assignment expression. I don't think it's valid to dereference a pointer to a value that contains uninitialized memory anywhere not valid for its type. I'm not sure that place expressions are immune to this, to me they read similarly to a borrow.

    I think I would agree that drop semantics don't exist when there's no drop glue.

  6. ia0 commented on Jan 29, 2026

    @ia0

    In that case I would assume dereferencing the pointer is immediate UB even if it's only used in a place for an assignment expression.

    It's not UB exactly because it builds a place, not a value. There's no load so there's no materialization of the value.

    Regarding the OP question, this is actually more general than just types with no drop glue. Dropping is about a place, and the place is never implicitly loaded during the destruction procedure. In the following example, Foo implements Drop but only loads the first 2 bytes:

    #[repr(C)]
    struct Foo(u16, u16);
    
    impl Drop for Foo {
        fn drop(&mut self) {
            println!("drop {}", self.0);
        }
    }
    
    fn main() {
        let mut x: MaybeUninit<u32> = MaybeUninit::uninit();
        unsafe { *x.as_mut_ptr().cast::<u16>() = 11 };
        unsafe { *x.as_mut_ptr().cast::<Foo>() = Foo(22, 33) };
    }

    There's no UB in this code according to the reference and to Miri, because:

    • The call to Foo::drop() does not load the place and mutable references don't have recursive validity.
    • The body of Foo::drop() only loads the first 2 bytes.
    • The fields of Foo are dropped in order, but for each of those fields there's no drop glue, so no load.
  7. LoganDark commented on Jan 29, 2026

    @LoganDark

    Interesting, I didn't know there needed to be a load for uninitialized memory to become UB. (Looking at the issue you linked, it appears the reference taught me wrong.) Thank you for the clarification.

  8. RalfJung commented on Jan 29, 2026

    @RalfJung
    Member

    Note that at the moment the Reference still says that it is UB to have a reference pointing to an invalid value. Calling the destructor involves creating a reference, so according to the Reference your last example is UB @ia0. However if we do eventually resolve the question of recursive reference validity to match what Miri currently does, then yeah that code should be fine.

  9. ia0 commented on Jan 29, 2026

    @ia0

    Ah my bad, I forgot the reference was conservative on that aspect. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions