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

Topic: transmute vs from_raw_parts


Shnatsel (Sep 01 2019 at 13:52, on Zulip):

I'm trying to determine if let vector = std::mem::transmute::<Vec<NonZeroU8>, Vec<u8>>(vector); is OK or do I need Vec::from_raw_parts() instead.
The documentation on this exists, but it's confusing. https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives has an example with a Vec being transmuted and claims it's UB, but doesn't explain why. I also don't understand why .clone() is called on the vector being transmuted, yet the comments claim that the operation does not copy the vector.

Shnatsel (Sep 01 2019 at 14:00, on Zulip):

Also the mem::forget at the end looks fishy. I think it should be before the transmute, not after.

rkruppe (Sep 01 2019 at 14:51, on Zulip):

That code block contains three completely separate ways to perform the type punning. The mem::forget at the end goes with the from_raw_parts only. But it's true that the first (transmute) example shouldn't clone. (But either way it wouldn't need a mem::forget, since transmute is by-value.)

rkruppe (Sep 01 2019 at 14:52, on Zulip):

As for why the transmute is UB, the simple reason is that Vec doesn't guarantee that such type punning is OK. There's also the fact that we don't guarantee any kind of determinism for layout of repr(Rust) structs (of which Vec is one), but for a stdlib type that's a technicality we could side-step if we wanted to.

Shnatsel (Sep 01 2019 at 15:32, on Zulip):

.as_mut_ptr() does not consume the vector, merely returns a pointer, so when we call .from_raw_parts() in that example we actually have mutable aliasing, which I believe is UB

Shnatsel (Sep 01 2019 at 16:00, on Zulip):

I've run the first pattern through Clippy and it didn't complain, so I'll open an issue for Clippy as soon as this is clarified

rkruppe (Sep 01 2019 at 16:21, on Zulip):

Hmm, I would have said it's fine since the original Vec isn't used afterwards but it actually is, since it's passed to mem::forget.

Shnatsel (Sep 01 2019 at 16:41, on Zulip):

For some reason miri doesn't complain about this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=87a6f1f8bc386f3c80b5f6157da1b161

rkruppe (Sep 01 2019 at 16:43, on Zulip):

presumably because Vec just (transitively) contains a Unique which is currently implemented as just a plain old raw pointer for aliasing questions

Shnatsel (Sep 01 2019 at 16:45, on Zulip):

So that's a bug in miri?

rkruppe (Sep 01 2019 at 16:52, on Zulip):

I wouldn't say that, miri is making the most of what's in the liballoc source code. It's kind of a liballoc/rustc issue in that Vec's data pointer doesn't get any noalias superpowers in LLVM IR generation either, but some other factors block that too, so I guess miri is the main way that this can be observed today

Shnatsel (Sep 01 2019 at 17:34, on Zulip):

OK, I've opened an issue about the confusing docs: https://github.com/rust-lang/rust/issues/64073

RalfJ (Sep 15 2019 at 13:03, on Zulip):

I'd say it is a Miri limitation, I'd like to make Unique meaningful eventually

RalfJ (Sep 15 2019 at 13:04, on Zulip):

but so far I did not have a good idea for how to do that

RalfJ (Sep 15 2019 at 13:04, on Zulip):

@Shnatsel ^

Last update: Nov 19 2019 at 18:10UTC