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

Topic: MaybeUninit is not repr(transparent)


gnzlbg (Nov 20 2018 at 21:29, on Zulip):

@RalfJ so the problem is that MaybeUninit<T> does not have the same repr as T, which has performance implications (e.g. if T is repr(simd)) and also means that one cannot use MaybeUninit<T> in C FFI where a T is expected.

gnzlbg (Nov 20 2018 at 21:30, on Zulip):

Given that MaybeUninit<T> is an union with two variants with potentially two different reprs, I don't think that repr(transparent) makes sense here :/

gnzlbg (Nov 20 2018 at 21:31, on Zulip):

Maybe a way to select from which variant the union gets its repr ?

rkruppe (Nov 20 2018 at 21:33, on Zulip):

What's been done in #55834 is to restrict any ABI fiddling to unions with only one non-(size=0, align=1) field, analogously to how transparent structs can have only one such field

rkruppe (Nov 20 2018 at 21:33, on Zulip):

But I am puzzled by the mention of FFI. Passing or receiving uninitalized data is UB in C, isn't it?

rkruppe (Nov 20 2018 at 21:34, on Zulip):

oh no i misrepresented #55834 but anyway it doesn't try to handle arbitrary unions with arbitrary fields and that's the key

RalfJ (Nov 20 2018 at 21:43, on Zulip):

right but its the same restrictions as for repr(transparent) structs as you said

RalfJ (Nov 20 2018 at 21:43, on Zulip):

so it seems the same attribute would make a lot of sense for unions as well

RalfJ (Nov 20 2018 at 21:44, on Zulip):

also this is just about deciding which ABI to use to pass these guys around; which further restrictions there are in terms of the values you have in there depends on the language on the other side of the FFI interface

RalfJ (Nov 20 2018 at 21:44, on Zulip):

and uninitialized data in C is a complicated topic...

rkruppe (Nov 20 2018 at 21:45, on Zulip):

It's quite complex, yes, but at the end what matters to me is: are there any reasonable Rust programs that benefit from passing MaybeUninit by value across the FFI boundary? Because that is all repr(transparent) is about, you can get any memory layout compatibility you want with repr(C) or (preferably) by Rust deciding to not try to be too clever by half about union memory layout

RalfJ (Nov 20 2018 at 21:48, on Zulip):

ack

RalfJ (Nov 20 2018 at 21:48, on Zulip):

for structs, newtypes are a pretty good argument. but "new-unions" would be a new pattern to me and I dont think I'd like it^^

RalfJ (Nov 20 2018 at 21:55, on Zulip):

@rkruppe I guess the slightly higher-level question is whether there is a good reason for passing what is known to be uninitialized data by value across an FFI boundary. With very few (if any) exceptions, uninitialized data should be inside a MaybeUninit

rkruppe (Nov 20 2018 at 21:56, on Zulip):

well let's hear it from @gnzlbg since they brough up ffi

gnzlbg (Nov 20 2018 at 21:57, on Zulip):

so in stdsimd we use C FFI to call LLVM intrinsics directly...

gnzlbg (Nov 20 2018 at 21:58, on Zulip):

I don't remember if there was a way to obtain undef by doing so, but that's what I had in mind

gnzlbg (Nov 20 2018 at 21:59, on Zulip):

or in other words, just because it is called C FFI does not mean that we are actually doing FFI with C, but for something that exposes the C ABI

gnzlbg (Nov 20 2018 at 21:59, on Zulip):

i don't know what the different C ABIs say about uninitialized memory, but probably they just say nothing

gnzlbg (Nov 20 2018 at 22:00, on Zulip):

it seems reasonable to expect these ABIs to require behaving as if the code being called was C, which would mean that callers can assume that the values being passed cannot be uninitialized, don't know

rkruppe (Nov 20 2018 at 22:05, on Zulip):

so for stdsimd we don't really need any feature, it can just rely on rustc codegen details (as it already does, heavily, in many other places)

rkruppe (Nov 20 2018 at 22:06, on Zulip):

non-C code using "the C ABI" is interesting, for example one could imagine a Rust library exposing a C ABI, but OTOH I still struggle to imagine needing to pass uninitialized data in those cases

gnzlbg (Nov 21 2018 at 00:03, on Zulip):

yeah, me too, i only had in mind using this when interfacing with LLVM

RalfJ (Nov 21 2018 at 08:34, on Zulip):

where'd you need it when interfacing with LLVM?

gnzlbg (Nov 21 2018 at 13:08, on Zulip):

See: https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_undefined&expand=5955

All these intrinsics return vectors with "undefined" elements.

gnzlbg (Nov 21 2018 at 13:08, on Zulip):

Some of these intrinsics are already in stable, and they should be returning MaybeUninit<__m128> instead of just __m128.

gnzlbg (Nov 21 2018 at 13:09, on Zulip):

Once we can use MaybeUninit in stable APIs, we should try to fix those in a backwards incompatible way (doing a crater run, etc.)

RalfJ (Nov 21 2018 at 13:09, on Zulip):

@gnzlbg but to construct an MaybeUninit<__m128> you don't need an intrinsic

RalfJ (Nov 21 2018 at 13:09, on Zulip):

just use MaybeUninit::uninitialized()

gnzlbg (Nov 21 2018 at 13:10, on Zulip):

indeed, I don't know why I have in mind that we were calling into LLVM intrinsics for any of those

gnzlbg (Nov 21 2018 at 13:11, on Zulip):

@RalfJ can we use MaybeUninit in stable APIs already ?

gnzlbg (Nov 21 2018 at 13:12, on Zulip):

that is, is MaybeUninit already stable ?

gnzlbg (Nov 21 2018 at 13:12, on Zulip):

Also, the intrinsics "construct a vector with uninitialized elements".

gnzlbg (Nov 21 2018 at 13:13, on Zulip):

Checking the source code for some, they are built by using __m128(uninitialized(), uninitialized(), ...)

gnzlbg (Nov 21 2018 at 13:13, on Zulip):

and not just uninitialized::<__m128>() for some reason

RalfJ (Nov 21 2018 at 13:15, on Zulip):

that is, is MaybeUninit already stable ?

no

RalfJ (Nov 21 2018 at 13:15, on Zulip):

we should first get https://github.com/rust-lang/rust/pull/54668 landed

RalfJ (Nov 21 2018 at 13:15, on Zulip):

and there are some API discussions in the tracking issue

Last update: Nov 19 2019 at 18:05UTC