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

Topic: best game: is this UB?


Jake Goulding (Sep 15 2018 at 23:13, on Zulip):

Should this Rust be valid?

use std::mem;

fn main() {
    let a = unsafe { mem::uninitialized::<&()>() };
    let b = [a];
    let c = b.iter();
    let mut d = c.cloned();
    let e = d.next();
    let _f = match e {
        Some(_) => 1,
        None => 2,
    };
}
Jake Goulding (Sep 15 2018 at 23:15, on Zulip):

Spoiler:

==2711== Conditional jump or move depends on uninitialised value(s)
==2711==    at 0x10E080: md::main (main.rs:10)
==2711==    by 0x10E16F: std::rt::lang_start::{{closure}} (rt.rs:74)
==2711==    by 0x119EF2: {{closure}} (rt.rs:59)
==2711==    by 0x119EF2: _ZN3std9panicking3try7do_call17he206d249d44a142eE.llvm.17113965321911306163 (panicking.rs:310)
==2711==    by 0x126699: __rust_maybe_catch_panic (lib.rs:105)
==2711==    by 0x10EA85: try<i32,closure> (panicking.rs:289)
==2711==    by 0x10EA85: catch_unwind<closure,i32> (panic.rs:392)
==2711==    by 0x10EA85: std::rt::lang_start_internal (rt.rs:58)
==2711==    by 0x10E147: std::rt::lang_start (rt.rs:74)
==2711==    by 0x10E0E9: main (in /tmp/md/target/debug/md)

Line 10 is Some(_) => 1,

Jake Goulding (Sep 15 2018 at 23:16, on Zulip):

but removing cloned or changing to mem::uninitialized::<()> stops the Valgrind error

Jake Goulding (Sep 15 2018 at 23:22, on Zulip):

@eddyb has evidently already looked at the original version of this.

rkruppe (Sep 15 2018 at 23:24, on Zulip):

i guess the underlying question here is: what has to be initialized so you can you check the discriminant of an enum? at minimum the bytes where the discriminant is stored must be initialized. that's why &() vs () makes a difference -- for the reference, the layout optimization puts the discriminant into the (uninit) bytes of the reference

rkruppe (Sep 15 2018 at 23:25, on Zulip):

but if we want to keep expanding the amount of layout optimizations we do with enum tags, we need to declare this sort of thing UB for all types where we may want this sort of layout optimization

Jake Goulding (Sep 15 2018 at 23:26, on Zulip):

The original context - https://stackoverflow.com/questions/52348277/vector-is-empty-after-cloning-struct-with-uninitialized-member/52349655#52349655

Jake Goulding (Sep 15 2018 at 23:27, on Zulip):

@rkruppe so the nullable pointer optimization kicking in makes sense, but why is cloned needed to trigger it?

rkruppe (Sep 15 2018 at 23:28, on Zulip):

i have not thought deeply about that because i expect it to be rooted in some uninteresting technicality of the generated code

Jake Goulding (Sep 15 2018 at 23:29, on Zulip):

One tidbit is that the original code used ManuallyDrop and the code worked in 1.28 but fails in 1.29

Jake Goulding (Sep 15 2018 at 23:30, on Zulip):

and ManuallyDrop changed in 1.29

Jake Goulding (Sep 15 2018 at 23:30, on Zulip):

So it seems that stdlib change introduced UB in end-user programs

rkruppe (Sep 15 2018 at 23:35, on Zulip):

what's the change in 1.29?
but in any case i would argue this was always UB (like most other uses of mem::uninitialized) and the change you speak of just exposed it

rkruppe (Sep 15 2018 at 23:35, on Zulip):

ManuallyDrop and MaybeUninit are separate for a reason, though admittedly MaybeUninit still isn't a thing (>_>)

Jake Goulding (Sep 15 2018 at 23:36, on Zulip):

@rkruppe https://github.com/rust-lang/rust/commit/591eeff22af299043637e75bb5735c3c65e0c7fe

rkruppe (Sep 15 2018 at 23:36, on Zulip):

ah, I had suspected that one but didn't think it was old enough to be in 1.29

Jake Goulding (Sep 15 2018 at 23:37, on Zulip):

MaybeUninit still isn't a thing (>_>)

It is not ;-)

rkruppe (Sep 15 2018 at 23:40, on Zulip):

OTOH I believe one can do the same in stable library code, using unions (and ManuallyDrop b/c unions containing Drop data are bad)

eddyb (Sep 15 2018 at 23:41, on Zulip):

cloned is just because before cloned you have Option<&&T>

eddyb (Sep 15 2018 at 23:41, on Zulip):

Some(&garbage)

rkruppe (Sep 15 2018 at 23:41, on Zulip):

oh right!

eddyb (Sep 15 2018 at 23:41, on Zulip):

which is shallowly valid

Jake Goulding (Sep 15 2018 at 23:41, on Zulip):

ah, good point

eddyb (Sep 15 2018 at 23:41, on Zulip):

you know, we figured this out hours ago on discord

Jake Goulding (Sep 15 2018 at 23:42, on Zulip):

Where's my move-out-array iterators :-p

eddyb (Sep 15 2018 at 23:42, on Zulip):

somwthing soemtjong frafmented chat platforms

eddyb (Sep 15 2018 at 23:42, on Zulip):

alsp, mobile keyboards apparently

Jake Goulding (Sep 15 2018 at 23:42, on Zulip):

@eddyb in fact, no, I didn't, because the original poster asked a question on SO bu t didn't post their own answer

Jake Goulding (Sep 15 2018 at 23:42, on Zulip):

leaving it there, unanswered

eddyb (Sep 15 2018 at 23:43, on Zulip):

idk why people ask on SO first

eddyb (Sep 15 2018 at 23:43, on Zulip):

and then come to me

Jake Goulding (Sep 15 2018 at 23:43, on Zulip):

only after posting here and submitting an answer did I see that they mentioned they talked to you

eddyb (Sep 15 2018 at 23:43, on Zulip):

anyway you can find the discussion in #compiler on discord

Jake Goulding (Sep 15 2018 at 23:43, on Zulip):

@eddyb by that logic, there would never be any questions on SO. Do you not want a front-line defense?

eddyb (Sep 15 2018 at 23:43, on Zulip):

the gist of it is that mem::uninitialized is utterly useless

eddyb (Sep 15 2018 at 23:44, on Zulip):

no, I mean, they already were gonna ask me

eddyb (Sep 15 2018 at 23:44, on Zulip):

because they knew I was aware of them and slotmap

Jake Goulding (Sep 15 2018 at 23:44, on Zulip):

Why they posted and then immediately asked you, I dunno. You gotta wait for time and thinking for a Q.

eddyb (Sep 15 2018 at 23:44, on Zulip):

like, we had discussed it before lol

eddyb (Sep 15 2018 at 23:45, on Zulip):

anyway, yeah, this is an impossible problem on stable without using space or restricting the types of values significantly

eddyb (Sep 15 2018 at 23:45, on Zulip):

and on nightly you have to keep your own copy of MaybeUninit

rkruppe (Sep 15 2018 at 23:46, on Zulip):

what why would you need nightly for copying MaybeUninit?

eddyb (Sep 15 2018 at 23:46, on Zulip):

copy restriction on unions

Jake Goulding (Sep 15 2018 at 23:46, on Zulip):

the OP is the author of slotmap

rkruppe (Sep 15 2018 at 23:46, on Zulip):

oh it requires Copy not absence of drop glue

eddyb (Sep 15 2018 at 23:47, on Zulip):

yeah the RFC isn't even in FCP yet

eddyb (Sep 15 2018 at 23:50, on Zulip):

@Jake Goulding you should be linking https://github.com/rust-lang/rust/issues/53491 or related threads

eddyb (Sep 15 2018 at 23:51, on Zulip):

or maybe just https://github.com/rust-lang/rust/pull/53508

Jake Goulding (Sep 15 2018 at 23:51, on Zulip):

@eddyb linking ... from where? in my answer?

eddyb (Sep 15 2018 at 23:51, on Zulip):

something in there should explain how useless mem::uninitialized is

eddyb (Sep 15 2018 at 23:51, on Zulip):

yeah, somewhere on the SO post

Jake Goulding (Sep 15 2018 at 23:51, on Zulip):

just in general? Is this my new .sig? :wink:

eddyb (Sep 15 2018 at 23:51, on Zulip):

lol

eddyb (Sep 15 2018 at 23:52, on Zulip):

I just want to go to sleep

eddyb (Sep 15 2018 at 23:52, on Zulip):

point is, this is not an isolated case. you can't use mem::uninitialized safely, with generics

eddyb (Sep 15 2018 at 23:52, on Zulip):

and if you think you can, chances are you're wrong

eddyb (Sep 15 2018 at 23:52, on Zulip):

there's a reason we're trying to deprecate it into oblivion

eddyb (Sep 15 2018 at 23:53, on Zulip):

(and mem::zeroed is almost entirely as bad)

nikomatsakis (Sep 17 2018 at 15:40, on Zulip):

@Jake Goulding in terms of @RalfJ's blog post, this code is incorrect because the validity predicate (which must always hold, even in unsafe code) of &T will require that it be non-null (though this is not "formally decided" or even discussed; but it's needed to justify the Option-layout optimizations)

RalfJ (Sep 17 2018 at 17:46, on Zulip):

mem::uninitialized::<&()>() is insta-UB...

RalfJ (Sep 17 2018 at 17:48, on Zulip):

why is cloned needed to trigger it?

this is a question you can never answer with UB. or rather, the answer always is "because otherwise LLVM was not yet smart enough to see youwere doing it wrong"

RalfJ (Sep 17 2018 at 17:49, on Zulip):

only if you e.g. run this code in miri you can start doing actual statements of the form "adding X makes a difference"

RalfJ (Sep 17 2018 at 17:49, on Zulip):

(though miri does not yet implement enough validation to notice the insta-UB in the first line here)

RalfJ (Sep 17 2018 at 17:55, on Zulip):

But at least at this point we are close to having MaybeUninit in nightly

RalfJ (Sep 17 2018 at 17:55, on Zulip):

might just take another year or so tog et it on stable... ;)

Last update: Nov 20 2019 at 13:30UTC