-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Feature: unchecked access to enum interior #1863
Comments
Does this work for you? https://docs.rs/unreachable/0.1.1/unreachable/trait.UncheckedOptionExt.html Under the hood this uses a If you want to make this slightly less dangerous, https://crates.io/crates/debug_unreachable adds a check in debug mode only. |
@SimonSapin I can't use that directly since I need a pointer to the interior, and dereferencing the initial pointer at all is UB. A similar approach might work in release mode, as a way to calculate the pointer offset before-hand, but I'd need it to work in debug mode too (also, relying on compiler optimizations for correctness is not ideal!) |
Sorry, I don’t understand: why is it UB to dereference that |
The timeline looks approximately like this:
Until I know I have exclusive access to the pointer, it would be UB to try dereferencing it (data race) but I can't wait until I've got exclusive access to convert the pointer. |
Afaik, there is not necessarily any valid pointer to the interior of an Can you build up a custom trait that provides this pointer when it exists? Roughly :
|
@burdges There is always a valid pointer to the interior of an |
We need this in libstd badly. |
I found a (horrible) workaround for my specific
Obviously this will fail if rust ever adds more advanced layout manipulations, but hopefully this issue is resolved properly before then... |
@Diggsey They'd be on, but a ton of personal things came up, so the last pull request that actually enables it isn't in yet. |
@camlorn In that case, the only option left would seem to be to create a bit pattern which is likely to be within the domain of |
That sounds like a pretty horrific hack :) Have you considered replacing your use of edit: This would be a nice feature to have though. |
My take on this is that even a really cut down version of #1450 would be enough here, and that's more likely to get in (the implementation is already there in part, as MIR requires downcasts to variants) than any hack. |
Could someone explain that part in more detail? Is it UB to construct such a pointer even if it's never dereferenced? Or would it have to get dereferenced in some way? Edit: Hmm, I think I understand part of the problem. Could something like this be correct? fn option_offset<T>() -> usize {
// Avoid creating an uninitialized Some if the null pointer optimization is
// in effect, because it's not actually guaranteed to be Some.
if mem::size_of::<T>() == mem::size_of::<Option<T>>() {
return 0;
}
let dummy: Option<T> = unsafe { Some(mem::uninitialized()) };
let dummy_ptr = &dummy as *const Option<T> as usize;
let interior_ptr = dummy.as_ref().unwrap() as *const T as usize;
mem::forget(dummy);
interior_ptr - dummy_ptr
} |
I'll use
Option
as an example, but this applies to any enum:Sometimes you may have a
*mut Option<T>
, and want to get a*mut T
from that, without dereferencing the pointer, and without checking whether it is actually aSome(T)
. AFAICT, this is currently impossible to do in rust, unless you have some way to construct a validT
(which would allow calculating an offset before-hand and then using pointer arithmetic).Using
mem::uninitialized()
, ormem::zeroed()
to construct aT
before-hand to calculate the pointer offset doesn't work, because of enum layout optimization, which means it could be UB.This came up when writing some concurrency code: in this case de-referencing the pointer would be invalid because the memory may be being concurrently written to. The unsafe code is able to be correct because it checks at run-time that it has exclusive access, and that it was indeed a
Some(T)
before it ever tries to dereference the pointer.The text was updated successfully, but these errors were encountered: