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

Topic: slice-of-ZST validity


Thom Chiovoloni (Jan 09 2020 at 16:24, on Zulip):

The bitvec crate does some weird things so that the BitSlice type can work. Specifically, &BitSlice<...> ends up being (transparent wrapper around a) &[()], except both the length and pointer parts store specially encoded values (See BitPtr in https://github.com/myrrlyn/bitvec/blob/master/src/pointer.rs for how it's encoded, but the type in question is BitSlice in https://github.com/myrrlyn/bitvec/blob/master/src/slice.rs).

I would have thought this was unsound, but I can't actually think of a reason why. It's still nonnull, it respects alignment requirements (since () is 1-byte aligned), and since it's a ZST, the reference wouldn't be dereferencable to LLVM (and IDK if that attribute even gets applied to slice pointers).

So... I think this boils down to: "does &[()] have validity requirements beyond 'the pointer part can't be null'?".

gnzlbg (Jan 09 2020 at 17:00, on Zulip):

Currently std::mem::size_of::<&[()]>() returns 16 on x86_64

gnzlbg (Jan 09 2020 at 17:00, on Zulip):

AFAICT we can optimize that to 8

gnzlbg (Jan 09 2020 at 17:01, on Zulip):

(e.g. make &[ZST] store a usize only)

gnzlbg (Jan 09 2020 at 17:02, on Zulip):

Right now the proposed layout for fat pointers in the UCGs does not allow that

gnzlbg (Jan 09 2020 at 17:02, on Zulip):

But right now the layout of &T is unspecified, so we could still change that

gnzlbg (Jan 09 2020 at 17:03, on Zulip):

The validity of &[T] is also not written down anywhere yet

gnzlbg (Jan 09 2020 at 17:03, on Zulip):

The pointer needs to be nonnull, aligned, and dereferenceable

gnzlbg (Jan 09 2020 at 17:03, on Zulip):

but for &[()] all pointers except for ptr::null() satisfy that

gnzlbg (Jan 09 2020 at 17:04, on Zulip):

since the alignment of () is 1, and the slice occupies 0 bytes independently of its size, so the requirement is essentially dereferenceable(0), which as long as the pointer is not null, is a condition that's satisfied

gnzlbg (Jan 09 2020 at 17:07, on Zulip):

I've opened ucg#224 to track the optimization

RalfJ (Jan 15 2020 at 12:06, on Zulip):

but for &[()] all pointers except for ptr::null() satisfy that

I almost agree... one class of pointers that might not satisfy this is "dangling pointers LLVM knows" -- as in, dangling pointers into or derived from LLVM-controlled allocations. LLVM's spec is not clear enough to tell whether that is legal or not, and my attempt at asking them didnt work out (I think they failed to entirely understand where I was coming from -- it's a subtle question, and I have a hard time phrasing it well)

RalfJ (Jan 15 2020 at 12:07, on Zulip):

so, I wouldnt subscribe to the following code being allowed:

let x = Box::new(i32);
let ptr = &x as *const _ as *const ();
drop(x);
let zst_slice: &[()] = slice::from_raw_parts(ptr, 1024);
RalfJ (Jan 15 2020 at 12:08, on Zulip):

LLVM might be or become "smart enough" to deduce that this pointer cannot possibly be dereferencable

gnzlbg (Jan 15 2020 at 13:21, on Zulip):

hmm

gnzlbg (Jan 15 2020 at 13:21, on Zulip):

isn't this already the case ?

gnzlbg (Jan 15 2020 at 13:21, on Zulip):

That last pointer is "dereferenceable for 0 bytes"

gnzlbg (Jan 15 2020 at 13:22, on Zulip):

The trouble is that the lifetime of the allocation the pointer was derived from has ended

gnzlbg (Jan 15 2020 at 13:23, on Zulip):

Do we generate ptr reads/writes of zero-size in LLVM-Ir for pointers to ZSTs ?

gnzlbg (Jan 15 2020 at 13:26, on Zulip):

(no we don't)

RalfJ (Jan 15 2020 at 16:21, on Zulip):

That last pointer is "dereferenceable for 0 bytes"

you mean zst_slice in my example? I'd say it is not dereferencable for 0 bytes. At least not until we get explicit confirmation from LLVM that it is.

RalfJ (Jan 15 2020 at 16:22, on Zulip):

I would not be surprised at all if some LLVM dev went "after freeing an allocation, no ptr derived from that allocation can be dereferencable, and hence I can do X"

Last update: May 26 2020 at 10:45UTC