loom
loom copied to clipboard
Add a mock MaybeUninit
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
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.
It would be very difficult to detect the okay assume_init call such as MaybeUninit<[T;N]> -> [MaybeUninit<T>;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 |
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.
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.