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

Add a mock MaybeUninit #299

Open
jschwe opened this issue Dec 9, 2022 · 4 comments
Open

Add a mock MaybeUninit #299

jschwe opened this issue Dec 9, 2022 · 4 comments

Comments

@jschwe
Copy link

jschwe commented Dec 9, 2022

It would be nice if loom could add a MaybeUninit type, which internally keeps track of if it is in an initialized state, and asserts that it is indeed initialized when the user calls assume_init().
Additionally it could provide a new API to mark the value as uninitalized again, which for std would simply be a no-op. This would increase the confidence of users that in all possible interleavings only initialized data is read, and with the option to mark a MaybeUninit as unitialized, we could also check that data is not read after it was "moved out" e.g. by ptr::read

@taiki-e
Copy link
Member

taiki-e commented Dec 9, 2022

I believe this is basically an area that Miri or sanitizer should handle. It would be very difficult to detect the okay assume_init call such as MaybeUninit<[T;N]> -> [MaybeUninit<T>;N] on the library side.

@jschwe
Copy link
Author

jschwe commented Dec 9, 2022

It would be very difficult to detect the okay assume_init call such as MaybeUninit<[T;N]> -> [MaybeUninit;N] on the library side.

It may be difficult if we wanted to detect every possible way of interacting with the MaybeUninit value. But I think this would already be very useful when we can detect issues if users restrict themselves to a subset of the std API (i.e. don't use pointers or transmute). The advantage of loom is that it can explore all possible interleavings, which I don't think miri or sanitizers could offer.

What I have in mind boils down to the following:

function Behavior
as_ptr / as_mut_ptr Transition the state to Unknown, which effectively disables assertions as long as we are in this state.
new Create with state initialized
assume_init and friends Assert that the value is initialized (unless we are in the Unknown state)
uninit Create with state uninit
write Set state to initialized
read Assert that the value is initialized (unless we are in the Unknown state) and transition to unknown
take assert that the value is initialized and transition the state to uninit
zeroed Create with state Unknown

@Darksonn
Copy link
Contributor

assert that the value is initialized and transition the state to uninit

This is not always correct. The type could be Copy, in which case it remains initialized (and its not possible to check whether its Copy in generic code). It's also possible that the type has only Copy fields but isn't Copy itself — in this case it can still be ok for it to remain initialized. Furthermore, the user could also mem::forget the value and conceptually have this transfer the value back into the MaybeUninit.

@jschwe
Copy link
Author

jschwe commented Dec 10, 2022

This is not always correct. The type could be Copy, in which case it remains initialized (and its not possible to check whether its Copy in generic code).

I updated the table to also include a read method which transitions to the Unknown state.
take is meant to be used when the user explicitly wants to take ownership of the value and move it out.

There are very clear limitations of what we can check, but I think it would work well for data structures like a queue or stack, where you want to insert something once, and then take the value out again exactly once and never twice.

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

No branches or pull requests

3 participants