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* userDatapointers through aUserDatatype 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
Tinside 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
UserDatatrait. The reason for that issue is that in order to write someTinto a*mut c_void, we interpreted theTas a*mut c_voidand wrote that reinterpretation into the*mut c_voidlocation. 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 Tand then write theTinto that. Which is what we do now. Finally we make sure to not create even a temporary reference to theUserDatawhen viewed as some otherTwhen theUserDatais 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
UserDatatrait is renamed toHasUserDataand is modified somewhat, implemented on top of the newUserData. Importantly, theControllertrait's handling of user data was unsound (it returned a reference to a temporary inget_user_datawhen the storedTwas packed into the pointer). Because of the reference-to-temporary problem, I decided to follow suit of thePxFoundationuser data pieces by forcing them onto the heap rather than trying to pack them.