Stream: t-lang/wg-unsafe-code-guidelines

Topic: repr(transparent)


Elichai Turkel (Apr 15 2020 at 12:20, on Zulip):

Hi, I was sure that repr(transparent) allowed transmute<&Wrapper, &Inner>(...) or *const Wrapper as *Const Inner.

But going over UnsafeCell impl I've found this: https://doc.rust-lang.org/src/core/cell.rs.html#1543

    // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
    // #[repr(transparent)]. This exploits libstd's special status, there is
    // no guarantee for user code that this will work in future versions of the compiler!

Does this mean that repr(transparent) doesn't work that way for everyone?

simulacrum (Apr 15 2020 at 12:27, on Zulip):

I think that might be because repr(transparent) on UnsafeCell isn't stabilized for end-users, or at least I see no mention in the docs

Hanna Kruppe (Apr 15 2020 at 14:20, on Zulip):

This part of the comment was added in https://github.com/rust-lang/rust/pull/66248 for reasons discussed there, seems more related to what we document about UnsafeCell (treat get as being special) than repr(transparent) in particular.

Hanna Kruppe (Apr 15 2020 at 14:25, on Zulip):

However, there are significant caveats to "repr(transparent) allows type punning via pointer casts" -- e.g. transparent wrappers do not necessarily have the same safety and validity invariants as the type they wrap. Such issues can be ruled out if you control both types or the types provide sufficient documented guarantees, but libstd types don't usually give that many guarantees.

RalfJ (Apr 16 2020 at 21:12, on Zulip):

Indeed the main reason for that comment is the special status of UnsafeCell::get. That is the only way to get an interior mutable pointer. This trumps repr(transparent).

Lokathor (Apr 16 2020 at 21:19, on Zulip):

ah, so transmuting &mut UnsafeCell<T> to *mut T wouldn't also do it? Interesting. If so, is that written down somewhere?

Lokathor (Apr 16 2020 at 21:20, on Zulip):

(i mean somewhere outside of that one code comment on the unsafecell impl)

RalfJ (Apr 16 2020 at 21:25, on Zulip):

Lokathor said:

ah, so transmuting &mut UnsafeCell<T> to *mut T wouldn't also do it? Interesting. If so, is that written down somewhere?

wait no that is no problem

RalfJ (Apr 16 2020 at 21:25, on Zulip):

the issue is about interior mutability

RalfJ (Apr 16 2020 at 21:25, on Zulip):

so, you cannot transmute &UnsafeCell<T> to *mut T and write to it

Lokathor (Apr 16 2020 at 21:39, on Zulip):

oh, right right, &UnsafeCell<T>

Okay but is that noted anywhere outside of the docs of libcore? Perhaps we should write it down somewhere.

RalfJ (Apr 17 2020 at 16:08, on Zulip):

well it's noted in UnsafeCell docs

RalfJ (Apr 17 2020 at 16:08, on Zulip):

not sure which other place would fit?

Hanna Kruppe (Apr 17 2020 at 16:24, on Zulip):

FWIW I'd rather just get rid of this rule altogether. I'm pretty sure there's no good reason for it nowadays.

RalfJ (Apr 17 2020 at 16:30, on Zulip):

well, Stacked Borrows doesn't need it

RalfJ (Apr 17 2020 at 16:30, on Zulip):

but I am not sure if we are willing to commit to "whatever Stacked Borrows does" for interior mutability

Hanna Kruppe (Apr 17 2020 at 16:41, on Zulip):

get() isn't special to the compiler either, and I can't see why we'd ever want to change that. The special casing for UnsafeCell that we have (e.g., whether statics are read-only memory, or whether aliasing attributes are added to LLVM IR) is all just based on "does this type contain an UnsafeCell".

RalfJ (Apr 17 2020 at 16:42, on Zulip):

earlier versions of stacked borrows relied on some really weird sequence of casts in get to make things work

RalfJ (Apr 17 2020 at 16:42, on Zulip):

so just a normal transmute from &UnsafeCell<T> to *mut T would not have worked

RalfJ (Apr 17 2020 at 16:43, on Zulip):

current Stacked Borrows handles this better and the transmute would be fine, but who knows what final model we end up with

RalfJ (Apr 17 2020 at 16:44, on Zulip):

(the transmute is still somewhat odd as the pointer remains "tagged", so if you ever lose provenance -- such as through an integer roundtrip -- you get UB.)

RalfJ (Apr 17 2020 at 16:44, on Zulip):

so maybe &UnsafeCell<T> as *const _ as *mut T is the better "non-get" alternative. and that is entirely equivalent to get as far as latest Stacked Borrows is concerned.

Hanna Kruppe (Apr 17 2020 at 16:49, on Zulip):

Hm, I see. Then I won't push further for this change right now. But still, get should definitely not be magic : transmute may be weird around pointer provenance in general, but the obvious as cast really ought to work and IMO a formal model that can't make them work probably won't be satisfactory.

RalfJ (Apr 17 2020 at 16:54, on Zulip):

I agree

Last update: Jun 05 2020 at 22:30UTC