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

Topic: Array pointers


DutchGhost (Aug 03 2019 at 10:37, on Zulip):

I was trying to simplify working with array's that contain MaybeUninit`s, and wrote a simple wrapper.
Here's the wrapper: https://github.com/DutchGhost/partialarray/blob/master/src/lib.rs

The question is about the first_ptr function on https://github.com/DutchGhost/partialarray/blob/master/src/lib.rs#L77

However, I wondered; Given N is 0, is the pointer returned from first_ptr and first_ptr_mut valid?
Those function could look like:

fn first_ptr(&self) -> *const T {
    if N == 0 {
        mem::align_of::<T>() as *const T
    } else {
        self.nth_ptr(0)
    }
}

so that for N being 0, an aligned pointer is returned, which can be used by for example slice::from_raw_parts(ptr, 0)

RalfJ (Aug 03 2019 at 10:39, on Zulip):

nth_ptr is unsound, it can be used for OOB arithmetic

RalfJ (Aug 03 2019 at 10:39, on Zulip):

that is UB completely independent of any initialization concerns

RalfJ (Aug 03 2019 at 10:40, on Zulip):

but I dont see any problem with the 0 case, why would there be a problem there?

DutchGhost (Aug 03 2019 at 10:40, on Zulip):

It can be used for OOB arithmatic yeah, however in order to use the pointer, unsafe must be written anyway, which is why I didnt mark it unsafe.

RalfJ (Aug 03 2019 at 10:41, on Zulip):

creating an OOB reference is insta-UB

RalfJ (Aug 03 2019 at 10:41, on Zulip):

and get_unchecked returns a reference

RalfJ (Aug 03 2019 at 10:42, on Zulip):

so it doesnt matter if you dont use the result. OOB with get_unchecked is UB.

DutchGhost (Aug 03 2019 at 10:42, on Zulip):

Why it would be a problem? Because Im not sure what it does? [T; 0] doesnt really exist at runtime, so having a ptr to the 0th element...eh? calling array[0] panics for an array of 0 elements

DutchGhost (Aug 03 2019 at 10:44, on Zulip):

Thanks for pointing that out. I guess I have to use let base = &self.array as *const MaybeUninit<T>, and then call .add(index) on that then?

RalfJ (Aug 03 2019 at 10:47, on Zulip):

Quoting from the add docs:

Both the starting and resulting pointer must be either in bounds or one byte past the end of the same allocated object.

RalfJ (Aug 03 2019 at 10:47, on Zulip):

if you really want this to be safe without bounds checking you need to use wrapping_add

RalfJ (Aug 03 2019 at 10:47, on Zulip):

like, self.array.as_ptr().wrapping_add(n)

RalfJ (Aug 03 2019 at 10:47, on Zulip):

then you also don't need unsafe

RalfJ (Aug 03 2019 at 10:48, on Zulip):

Because Im not sure what it does?

it adds 0 to a pointer. not sure how that is special in any way here.

RalfJ (Aug 03 2019 at 10:48, on Zulip):

for an array of size 0 every index is OOB

RalfJ (Aug 03 2019 at 10:48, on Zulip):

but you have OOB problems for all sizes and I dont see how 0 would be special

RalfJ (Aug 03 2019 at 10:49, on Zulip):

oh and you cannot use MaybeUninit::as_ptr for OOB indices either as they take a reference

RalfJ (Aug 03 2019 at 10:49, on Zulip):

and references must not dangle

RalfJ (Aug 03 2019 at 10:49, on Zulip):

I dont get why you dont just do a bounds check, TBH^^

DutchGhost (Aug 03 2019 at 10:51, on Zulip):

Well the question really is, if I apply the changes that would make nth_ptr safe,
Then what should first_ptr do for N = 0,
Either returned an aligned pointer, or a pointer to some non-existing value in the array?

DutchGhost (Aug 03 2019 at 10:54, on Zulip):

Especially with bounds checking, first_ptr would panic for N = 0.
But this struct is used in an ArrayVec implementation (not the one from crates.io), which uses first_ptr in its implementation for Deref<Target = [T]>, so a panic isnt something I'd like

RalfJ (Aug 03 2019 at 10:55, on Zulip):

first_ptr(0) should return the address that's 0 away from &self, at a different type

RalfJ (Aug 03 2019 at 10:55, on Zulip):

I dont understand why you think there is a problem here

RalfJ (Aug 03 2019 at 10:56, on Zulip):

it's just like first_ptr(5) returning the address 5*size_of::<T>() away from the base, except with 5 replaced by 0...

DutchGhost (Aug 03 2019 at 10:58, on Zulip):

Okey, thats cool. I will change all my UB'ness...I really should learn how to avoid all that, thanks for pointing them out! :)

RalfJ (Aug 03 2019 at 10:58, on Zulip):

for N = 0, Self is a ZST. but if you are getting your pr arithmetic right, moving away 5 elements from that pointer, while out-of-bounds, is okay

RalfJ (Aug 03 2019 at 10:58, on Zulip):

@DutchGhost as another aid in learning (besides reading the https://doc.rust-lang.org/nightly/nomicon/ ), I can recommend Miri (https://doc.rust-lang.org/nightly/nomicon/)

RalfJ (Aug 03 2019 at 10:59, on Zulip):

if you run your test suite in it, and if that does an OOB access, it would have caught this

RalfJ (Aug 03 2019 at 10:59, on Zulip):

so a panic isnt something I'd like

you are panicking in debug mode though

RalfJ (Aug 03 2019 at 10:59, on Zulip):

so it clearly is incorrect to use that function OOB, and code that does is already broken in debug mode

RalfJ (Aug 03 2019 at 11:00, on Zulip):

either you want OOB accesses, then allow them and document that and be extra-super-careful not to have any (implicit) references anywhere. or you dont want OOB accesses and then I'd recommend checked accesses unless you benchmarked that this is hot code.

DutchGhost (Aug 03 2019 at 11:21, on Zulip):

So just to get things straight;
self.array.as_ptr().wrapping_add(index) as *const T is valid, even if index is OOB, so the responsability of the validness of the ptr is up to the caller, and not me

RalfJ (Aug 03 2019 at 11:42, on Zulip):

that code does not even need an unsafe block, so yes, there's no UB there. there cannot be.

DutchGhost (Aug 04 2019 at 10:10, on Zulip):

ohh you updated the docs for slice's get_unchecked and get_unchecked_mut! hihi, thats great :)

RalfJ (Aug 04 2019 at 10:13, on Zulip):

well it's not landed yet, but yes :)

RalfJ (Aug 04 2019 at 10:14, on Zulip):

when questions like this come up, usually to answer them I try to quite the docs, but if the "obvious" docs dont have the quote I need... I just add it ;)

Last update: Nov 19 2019 at 17:35UTC