reference
reference copied to clipboard
Add trait_upcasting related languages changes
I applied review comments from #1259 and added updates from https://github.com/rust-lang/rust/pull/120248.
cc @crlf0710 @compiler-errors @RalfJung
https://github.com/rust-lang/rust/issues/101336 is still open, did we actually end up committing to something?
@WaffleLapkin: Yes, it's just pending documentation https://github.com/rust-lang/rust/issues/101336#issuecomment-1251216579 -- presumably this is (A.) on Niko's list.
You may also want to edit https://doc.rust-lang.org/reference/behavior-considered-undefined.html as Niko mentioned in the issue you linked; you may want to re-read the FCP, but I believe it's UB to conjure up a vtable now since it must be valid for upcasting.
What exactly are you referring to here? I assume the "issue" is https://github.com/rust-lang/rust/issues/101336 (a link would have been good, it took clicking on 4 links to track this down :D ). Niko says a lot of things there, though. :)
@compiler-errors doc.rust-lang.org/reference/behavior-considered-undefined.html already mentions invalid metadata in any kind of pointer makes an invalid value, so I don't think we need to add anything on top of that?
- Invalid metadata in a wide reference,
Box<T>, or raw pointer. The requirement for the metadata is determined by the type of the unsized tail:
dyn Traitmetadata is invalid if it is not a pointer to a vtable forTrait.Slice([T]) metadata is invalid if the length is not a validusize(i.e., it must not be read from uninitialized memory). Furthermore, for wide references andBox<T>, slice metadata is invalid if it makes the total size of the pointed-to value bigger thanisize::MAX.
:umbrella: The latest upstream changes (possibly bf115a45b6bbc97cafa9e7c90106c5856fd965ea) made this pull request unmergeable. Please resolve the merge conflicts.
Any movement on this?
@PoignardAzur I'm working on a stabilization PR (after which this can be merged)
@compiler-errors could you take another look, do the changes still make sense?
@rustbot ready
In the original PR for this...
- https://github.com/rust-lang/reference/pull/1259
...there's a discussion about adding a line to the behavior considered undefined of:
- Performing non-nop coercion on a dangling or unaligned raw pointer.
There was some back and forth and it's not clear where that landed. Thoughts on that?
@compiler-errors @RalfJung @WaffleLapkin
The comment here is the answer https://github.com/rust-lang/reference/pull/1259/files#r1404804424. I don't think this needs further changing. It doesn't really matter if the pointer is bad; upcasting only cares about the vtable metadata.
@compiler-errors doc.rust-lang.org/reference/behavior-considered-undefined.html already mentions invalid metadata in any kind of pointer makes an invalid value, so I don't think we need to add anything on top of that?
Invalid metadata in a wide reference,
Box<T>, or raw pointer. The requirement for the metadata is determined by the type of the unsized tail:
dyn Traitmetadata is invalid if it is not a pointer to a vtable forTrait.Slice([T]) metadata is invalid if the length is not a validusize(i.e., it must not be read from uninitialized memory). Furthermore, for wide references andBox<T>, slice metadata is invalid if it makes the total size of the pointed-to value bigger thanisize::MAX.
@WaffleLapkin I think this isn't quite right. How I read the Behaviors Considered Undefined section, it says...
Producing an invalid value. “Producing” a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation.
where "producing an invalid value is hence immediate UB". But the consensus from https://github.com/rust-lang/rust/issues/101336 was that having an invalid vtable is not a failure of the validity invariant. Rather, the UB occurs when a dyn pointer (raw, reference, whatever) with a malformed vtable is upcast or has a method invoked on it. Because safe code can perform those operations (including on raw pointers, in the case of upcast and potentially method calls in the future), this implies that the safety invariant (the conditions required to release such a value to safe code) requires a valid vtable. But if you can keep the *const dyn Foo confined to unsafe code and be absolutely sure nobody upcasts it, it doesn't require a valid vtable. Quoting https://github.com/rust-lang/rust/issues/101336:
The proposal is as follows:
- Vtable-adjusting upcasts are safe operations. The upcast is UB if performed on a value without a valid vtable
- As such, the "safety invariant" requires a fully valid vtable.
- The "validity invariant" requires
*dynmetadata to be word-aligned and non-null.Vtable-adjusting upcasts are defined as:
- Trait upcasts that alter the set of methods that can be invoked on the resulting value at runtime (e.g.,
dyn Bartodyn Foofrom the introduction). In particular, upcasts that simply add or remove auto-traits are not vtable-adjusting (e.g.,dyn Debug + Sendtodyn Debug).
But the consensus from https://github.com/rust-lang/rust/issues/101336 was that having an invalid vtable is not a failure of the validity invariant.
To be clear, consensus was that we are not ruling on the validity invariant at this point. The validity invariant for vtable metadata is an open question, discussed at https://github.com/rust-lang/unsafe-code-guidelines/issues/516. Meanwhile, the reference says that the vtable pointer must point to a vtable of the right trait and Miri enforces this; this is following our usual strategy of having a bit more UB for now and possibly relaxing this in the future.
Hmm, OK, that's not what I thought the consensus was. =) Maybe I'm misremembering, though when I read the text I quoted it seems clear-ish. We need to find some clearer way though to describe the "upper/lower bounds" of what is and is not UB, I think it's going to be very hard to keep things in sync over time the way it is now (where it is e.g. difficult to tell if the reference is out of date or over approximating).
On Thu, Dec 19, 2024, at 1:51 AM, Ralf Jung wrote:
But the consensus from rust-lang/rust#101336 https://github.com/rust-lang/rust/issues/101336 was that having an invalid vtable is not a failure of the validity invariant.
To be clear, consensus was that we are not ruling on the validity invariant at this point. The validity invariant for vtable metadata is an open question, discussed at rust-lang/unsafe-code-guidelines#516 https://github.com/rust-lang/unsafe-code-guidelines/issues/516. Meanwhile, the reference says that the vtable pointer must point to a vtable of the right trait and Miri enforces this; this is following our usual strategy of having a bit more UB for now and possibly relaxing this in the future.
— Reply to this email directly, view it on GitHub https://github.com/rust-lang/reference/pull/1622#issuecomment-2552917895, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABF4ZX7ZXAI3MZZOHKHJNL2GJUI7AVCNFSM6AAAAABORRYCSKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKNJSHEYTOOBZGU. You are receiving this because you commented.Message ID: @.***>
We currently say this above the UB list
The following list is not exhaustive; it may grow or shrink.
So the entire thing should be considered as approximating. Maybe we should start slowly widdling this down to just a few items in the list, though I think we should always reserve the right to remove UB.
Anyway this is getting off-topic for this PR. The validity invariant for vtables doesn't have to be settled for this one.
@rustbot labels +I-lang-nominated
When we handled the nomination for starting the FCP on https://github.com/rust-lang/rust/pull/134367, we reviewed this text, leading to some back and forth. Let's nominate to double check we're OK with where that landed.
As a note I'm working on rewriting most of src/type-coercions.md, when reading it carefully I found a lot of outdated/incorrect/misleading info. I'd like to land that as a follow up to this.
OK, so I re-read https://github.com/rust-lang/rust/issues/101336 and in particular found this comment which was asking whether the validity invariant for vtables was a "decision" or just a "strong recommendation". I guess @RalfJung interpreted it as the latter, which seems fine. I have edited the issue to clarify. I agree then that no edits are needed to the list of UB, as no new validity invariants have been decided.
Wearing lang-team hat: +1
EDIT: Well, +1 to the substance, I have some concerns lingering in comments actually that I would like to see resolved. Specifically the as point.
@rustbot label -I-lang-nominated
I've also prepared a refactor of the unsizing section: de3ffc3e19c141ac7d6cf08beba4545a3f4e0a9f. I'll open a PR once this is merged.
https://github.com/rust-lang/rust/pull/134367#event-16230091099 has been merged, so this can be merged as well :)
I rebased to collapse some back and forth, to fix an author name, to make some minor stylistic tweaks (capitalization and line unwrapping), and to remove the note section mentioned above.
We're anticipating further work on this to address some things raised in the threads here in a follow-up PR that Waffle has in progress.
Follow-up: https://github.com/rust-lang/reference/pull/1731