Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use NonNull #2

Merged
merged 3 commits into from
May 11, 2022
Merged

Use NonNull #2

merged 3 commits into from
May 11, 2022

Conversation

SabrinaJewson
Copy link
Contributor

This allows Option<AnyVec> to have the same size as AnyVec. But the main reason I did this was to fix the null pointer deref that can occur when allocation fails by using the type-system to force us to handle that case with handle_alloc_error. Additionally, it fixes the UB of taking multiple unique references to ZST_SLICE by using NonNull::dangling() instead.

@tower120
Copy link
Owner

This allows Option to have the same size as AnyVec

I know that Option<NonZero/NonNull> have the same size as NonZero/NonNull, but struct AnyVec have other members...
I didn't know that making one member NonNull will make struct Option -friendly.

Additionally, it fixes the UB of taking multiple unique references to ZST_SLICE by using NonNull::dangling() instead.

You mean taking multiple as_slice ? If so, why with NonNull::dangling() this is not the case?

@SabrinaJewson
Copy link
Contributor Author

The issue was that if with_capacity was called in parallel from multiple threads, it could end up creating multiple co-existing unique references to the ZST_SLICE constant, which is UB.

@tower120
Copy link
Owner

Ok. But what about calling as_slice with mem = NonNull::dangling()? Aren't that crate reference from invalid memory pointer?

@SabrinaJewson
Copy link
Contributor Author

No, that's fine — even though it's invalid you're not reading any bytes so it's OK. Box does it for allocating Boxes around ZSTs.

As a side-effect this fixes an unsoundness by correctly handling
allocation errors. Additionally, it fixes the UB of taking multiple
unique references to `ZST_SLICE` by using `NonNull::dangling()` instead.
@tower120
Copy link
Owner

But if follow that logic, aren't multiple references to ZST_SLICE is OK too? Since we never touch it.

@SabrinaJewson
Copy link
Contributor Author

No, because a unique reference asserts that no other unique references exist to the same location, whether or not you use the reference.

fn unsound() {
    static mut X: [u8; 1] = [0];
    // It is not sound to create multiple unique references to the same
    // location if it is not a ZST.
    unsafe { &mut X };
}
fn sound() {
    // It is sound to create multiple unique references to the same
    // location if they come from different places and are ZSTs
    unsafe { <NonNull<[u8; 0]>>::dangling().as_mut() };
}

@tower120
Copy link
Owner

// It is not sound to create multiple unique references to the same
// location if it is not a ZST.

Wait a minute.
So if instead of:

static mut ZST_ARRAY: [u8;1] = [0];

It was:

struct empty{};
static mut X: [empty; 1] = [empty{}];

That would be OK?

Were I can read about multi &mut ZST references?

@SabrinaJewson
Copy link
Contributor Author

That would be OK?

I am not quite sure on that, but it should definitely be avoided since we have a better alternative that is definitely sound.

Were I can read about multi &mut ZST references?

I found this issue which might be interesting.

@tower120 tower120 merged commit 9295f28 into tower120:main May 11, 2022
@tower120
Copy link
Owner

Thank you for this PR!

@SabrinaJewson SabrinaJewson deleted the nonnull branch May 12, 2022 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants