Skip to content

Promotion introduces UB into otherwise well-defined code #493

Open
@RalfJung

Description

@RalfJung

While investigating rust-lang/rust#121610, I noticed something problematic... we currently accept code like this:

let x: &'static Option<Cell<i32>> = &None;

Promotion kicks in despite interior mutability, because it sees the None variant and considers that one variant to not have interior mutability.

But also, both Stacked Borrows and Tree Borrows consider this to be legal:

    let o: Option<Cell<i32>> = None;
    let x = &o;
    ptr::from_ref(x).cast_mut().write(Some(Cell::new(0)));

They allow this because we avoid making "do we allow mutation" value-dependent. This is for two reasons: (a) we don't even want to require the reference to point to a valid value, but if the memory might store any sequence of bytes then the concept of value-dependency doesn't even make sense, and (b) checking the value stored behind the reference would introduce something very close to a cyclic argument into the memory model. So when creating a reference to o, we can't know whether o is None or Some, and therefore we just conservatively assume that interior mutability is allowed.

It should follow that this is also legal:

    let x: &Option<Cell<i32>> = &None;
    ptr::from_ref(x).cast_mut().write(Some(Cell::new(0)));

But this is UB, due to promotion putting the None into read-only memory. That's Not Good, promotion is introducing UB!

This is related to #236 but seems worth a separate sub-issue.
See rust-lang/rust#122789 for a crater run of at attempt to fix this.
Cc @oli-obk

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