Make UserData
pointer-packing actually sound
#223
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This rewrites a lot of handling of user data both in the sys and high level wrapper crate. First of all, it puts all (well, as much as possible) handling of
void* userData
pointers through aUserData
type on the Rust side. That type is this union:The reason this is necessary is that if we want to be able to pack arbitrary
T
inside the space occupied by the user data, we need to make Rust aware that all or part of that data might be uninitialized since there can be arbitrary padding bytes inT
's layout.In addition, we fix #210 actually for-real this time, including in other places that did their packing adhoc other than the
UserData
trait. The reason for that issue is that in order to write someT
into a*mut c_void
, we interpreted theT
as a*mut c_void
and wrote that reinterpretation into the*mut c_void
location. This is backwards though --T
's size and alignment are subsets of*mut c_void
, so we should instead cast a pointer to theUserData
's memory (*mut UserData
) as a*mut T
and then write theT
into that. Which is what we do now. Finally we make sure to not create even a temporary reference to theUserData
when viewed as some otherT
when theUserData
is not yet actually initialized to a valid value of thatT
(usingaddr_of_mut!
).Another notable advantage of this is that it's much more readable what's going on at higher level uses of user data, and to justify that what is happening is actually sound or not.
Next, I also went through some more of the high level wrapper's handling of user data. The
UserData
trait is renamed toHasUserData
and is modified somewhat, implemented on top of the newUserData
. Importantly, theController
trait's handling of user data was unsound (it returned a reference to a temporary inget_user_data
when the storedT
was packed into the pointer). Because of the reference-to-temporary problem, I decided to follow suit of thePxFoundation
user data pieces by forcing them onto the heap rather than trying to pack them.