Reputation: 3706
I want to reinterpret an immutable reference to a mutable reference (in an unsafe block) and be responsible for the safety checks on my own, yet it appears I cannot use mem::transmute()
to do so.
let map_of_vecs: HashMap<usize, Vec<_>> = ...;
let vec = map_of_vecs[2];
/// obtain a mutable reference to vec here
Vec
s into Cell
s because that would affect all other areas of code that use map_of_vecs
and I only need mutability in one line.map_of_vecs
Upvotes: 1
Views: 2318
Reputation: 601529
The Rust compiler annotates &T
function parameters with the LLVM noalias
and readonly
attributes (provided that T
does not contain any UnsafeCell
parts). The noalias
attribute tells LLVM that the memory behind this pointer may only be written to through this pointer (and not through any other pointers), and the readonly
attribute tells LLVM that it can't be written to through this pointer (but possibly other pointers). In combination, the two attributes allow the LLVM optimiser to assume the memory is not changed at all during the execution of this function, and the code can be optimised based on this assumption. The optimiser may reorder instructions or remove code in a way that is only safe to do if you actually stick to this contract.
Another way the conversion can lead to undefined behaviour is for statics: immutable statics without UnsafeCell
s will be placed into read-only memory, so if you actually write to them, your code will segfault.
For parameters with UnsafeCell
s the compiler does not emit the readonly
attribute, and statics containing an UnsafeCell
are placed into writable memory.
Upvotes: 6
Reputation: 58725
The Rust optimiser makes the assumption that &mut T
references are unique. For example, it might deduce that a particular piece of memory can be reused because a mutable reference to that memory exists but is never accessed again.
However, if you transmute a &T
to a &mut T
then you are able to create multiple mutable references to the same data. If the compiler makes this assumption, you could end up dereferencing a value that has been overwritten with something else.
This is just one example of how the compiler might make use of the assumption that mutable references are unique. In fact, the compiler is free to use this information in any way it sees fit — which could (and likely will) change from version to version.
Even if you think you have guaranteed that the reference isn't aliased, you can't always guarantee that users of your code won't create more references. Even if you think you can be sure of that, the existence of references is extremely subtle and it's very easy to miss one. For example when you call a method that takes &self
, that's a reference.
Upvotes: 7