This one does feature <untagged>
in the message though. More on that in the README.md
of miri:
-Zmiri-track-raw-pointers
makes Stacked Borrows track a pointer tag even for raw pointers. This can make valid code fail to pass the checks, but also can help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by <untagged>
occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that works with -Zmiri-track-raw-pointers
also works without -Zmiri-track-raw-pointers
, but for the vast majority of code, this will be the case.
The main pronlem with miri-track-raw-pointers
is â as far as I understand â that it implements some form of stacked borrows which isnât the official formal modal of Rust in any way (yet?) and also still in development, I guess. Thatâs because actual Rust has not formal model and thus you canât always know if some code is considered UB or not because it may not have been decided yet. However, casting some &T
reference into a &Cell<T>
or similar things, is most definitely UB, according to Rust documentation, especially if you do use the cell for mutation afterwards. (Iâm not 100% sure I know what the documentation currently has to say about the case where you donât use the cell for mutation.)
Well â and, judging by the documentation cited above, it looks like miri-track-raw-pointers
does not support pointer-to-integer-to-pointer roundtrips either.
I mean, the situation is even worse in case of your BitField<u8, (), âŚ>
because a &self
reference is a reference to a zero-sized type. The reference doesnât give you legal access to any memory whatsoever.
But focusing on a hypothetical &T
-> &Cell<T>
conversion, Cell
is just a kind of safe wrapper for UnsafeCell
and Cell.set()
(using Cell::replace
internally) creates a mutable reference to the target of the underlying UnsafeCell
, so at last, if you go &T
-> &Cell<T>
-> call .set()
, youâve done the &T
->&mut T
conversion thatâs always UB. In other words: BitField
does not contain any interior mutability (due to lack of anything like UnsafeCell
or wrappers like Cell
/RefCell
/Mutex
/etc. so you just cannot soundly get a mutabel reference to any memory out of a shared reference to BitField<u8, (), âŚ>
Some quotes:
If you have a reference &T
, then normally in Rust the compiler performs optimizations based on the knowledge that &T
points to immutable data. Mutating that data, for example through an alias or by transmuting an &T
into an &mut T
, is considered undefined behavior. UnsafeCell<T>
opts-out of the immutability guarantee for &T
: a shared reference &UnsafeCell<T>
may point to data that is being mutated. This is called âinterior mutabilityâ.
All other types that allow internal mutability, such as Cell<T>
and RefCell<T>
, internally use UnsafeCell
to wrap their data.
this alone (implicitly) pretty much says that transmuting &T
into &UnsafeCell<T>
is UB.
mem::transmute<T, U>
takes a value of type T
and reinterprets it to have type U
. The only restriction is that the T
and U
are verified to have the same size. The ways to cause Undefined Behavior with this are mind boggling.
- [âŚ]
- Transmuting an
&
to &mut
is UB.
- Transmuting an
&
to &mut
is always UB.
- No you can't do it.
- No you're not special.