-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Fixes the is_null
method in PtrExt for fat pointers.
#23163
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
Conversation
The previous implementation of `is_null` would attempt to cast `0` to the pointer type of `*const T` or `*mut T` for any T. This was incorrect when the pointer type was not the size of some integer, as is the case for *const [T] and *mut [T], and would lead to an ICE. This commit fixes this issue by looking at the first pointer size integer of the pointer itself which in fat pointers is a pointer to the location of the data and in regular pointers is the pointer itself.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @pcwalton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see CONTRIBUTING.md for more information. |
This may not quite be the implementation strategy we'd like to take, for example this does not handle if the pointer/vtable fields are rearranged (e.g. it doesn't transmute to |
I agree that fixing the ICE is ultimately the best course of action. and I agree that field rearrangement could cause issues. But, even if the fields were rearranged in a trait object pointer, I would expect that if either of the pointer fields were null, then the trait object pointer itself would be considered null. Thus, this strategy would still work. Also, is there a good reason why the data pointer would not be the first field of a fat pointer struct? It makes a lot of sense given optimizations; not having the data pointer be the first field would mean that most data dereferences of a fat pointer would need to first perform an arithmetic operation to locate the data pointer field. To my knowledge this patch is correct given the current implementation and near to far future plans. Progress on fixing the ICE has not been quick, and blocking this commit would mean that |
Yes I understand that the implementation today has been chosen and is probably the right choice, but we want to avoid as many
It has only recently becomes possible to call this method on a |
How does changing the current implementation of {Mut}PtrExt to be defined only for T: Sized, and in addition, adding an implementation for *const/mut [T], sound? |
The change would break the method for fn is_null(&self) -> bool where T: Sized {
*self == 0 as *const T
} |
How would that break the method? I'm suggesting adding an implementation specifically for *const/mut [T]: impl<T> PtrExt for *const [T] |
We discussed this a bit on IRC, but I don't think that we should be adding an In the long run this will likely need some form of compiler intrinsic to extract the actual pointer from |
@@ -89,6 +101,15 @@ fn test_as_ref() { | |||
let p: *const int = &u as *const _; | |||
assert_eq!(p.as_ref().unwrap(), &2); | |||
} | |||
|
|||
let sn = slice::from_raw_parts(null(), 0) as *const [u32]; | |||
assert_eq!(sn.as_ref(), None); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is "6.1.3.2.3 Behavior considered undefined" because we put a null pointer inside a &[T]
. It's just a test case, so I guess it can do no harm. I don't know what I want to say more than this is UB and rustc doesn't have to compile it into a sane test case if it doesn't want to.
☔ The latest upstream changes (presumably #23482) made this pull request unmergeable. Please resolve the merge conflicts. |
Closing due to inactivity, and in the meantime it looks like these methods have re-grown the |
The current implementation of
is_null
attempts to cast0
to thepointer type of
*const T
or*mut T
for any T. This is incorrect when thepointer type is not the size of some integer, as is the case for *const [T]
and *mut [T], and leads to an ICE.
This commit fixes this issue by looking at the first pointer size integer of
the pointer itself which in fat pointers is a pointer to the location of the data
and in regular pointers is the pointer itself.
The following program can be used to verify the ICE and the fix: