-
Notifications
You must be signed in to change notification settings - Fork 58
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
Is it UB to have a mutable reference that could be misused, or simply to misuse it? #524
Comments
A type changing transmute for a mutable reference is undefined behaviour in the following cases:
The following is currently an open question whether it would be UB:
It's very much legal to transmute between any kind of reference even if you could "misuse" the reference to write an invalid value. Rust memory isn't typed, and a reference to some memory doesn't know what "type" that memory might be used as until the actual use. In fact, it's not inherently UB to, say, transmute a |
Hmm, it's interesting that you say that writing I also when looking more into this noticed that |
Indeed, that's #412.
And that's #84. I think those two issues cover all questions you raise? It is definitely allowed to transmute an |
Indeed, I think that my questions are covered by those two; I'll close this. Thank you both! |
Essentially, both the reference and MIRI seem to be okay with this, but I don't think this has been explicitly specified, and it probably should be.
Clarifying the question:
x
of arbitrary typeT
U
with the same layout asT
x
is valid for bothT
andU
&mut x
to&mut U
?A few examples for
T
andU
might bechar
andu32
, or more generallyT
andMaybeUninit<T>
, the latter being the case I specifically am interested in.Essentially, we know that in all cases, if you actually assign a value to
x
via&mut U
that isn't valid forT
, that is definitely UB. For example, ifT
ischar
, then it would be invalid to cast the reference of&mut x
to&mut u32
and then assign it the value ofu32::MAX
, for example.For a bit of background: I would like to generalise code such that it can accept either
&mut T
or&mut MaybeUninit<T>
, and ideally, I would be able to cast both of these types to a third type,&mut ForwardInit<T>
, which allows writing values ofT
but does not allow writing values ofMaybeUninit<T>
. This would presumably be sound, since we can't write an uninit value back into&mut T
.However, the issue here is that we would have to define
ForwardInit<T>
like:and, indirectly, we would be casting our
&mut T
to&mut MaybeUninit<T>
. However, we can still technically keep this sound if we ensure that, via our API forForwardInit<T>
, we only allow writing initialized values, and disallow writing uninitialized values.This is kind of similar to
Exclusive<T>
in spirit, since all we're doing is changing the API for the type, without changing anything inside the type. Except in this case, we're actually changing the inside of the type, but making sure that the API on the surface can't actually take advantage of this to do an invalid write. Assuming that it's the write that is UB, and not the reference itself.Here's the code I used to test whether MIRI was okay with this kind of casting:
See the code
The text was updated successfully, but these errors were encountered: