I was casting a field of a struct to a *mut pointer, so I declared that struct's reference as mutable. But then I started getting warnings that the mut modifier is not required. That seemed weird to me, I'm clearly mutating something, yet declaring it as mut is unnecessary? This leads me to this minimal example:
struct NonMut {
bytes: [u8; 5]
}
impl NonMut {
pub fn get_bytes(&self) -> &[u8] {
&self.bytes
}
}
fn potentially_mutate(ptr: *mut u8) {
unsafe { *ptr = 0 }
}
fn why(x: &NonMut) {
let ptr = x.get_bytes().as_ptr() as *mut u8;
potentially_mutate(ptr);
}
fn main() {
let x = NonMut { bytes: [1, 2, 3, 4, 5] };
println!("{}", x.get_bytes()[0]);
why(&x);
println!("{}", x.get_bytes()[0]);
}
1
0
Obviously dereferencing the pointer requires unsafe code, but from the perspective of someone just writing their own app and deciding to call why, perhaps defined in an external crate, this behaviour seems completely unexpected. You pass a clearly nonmutable reference somewhere, the borrow checker marks your code as correct, but under the hood there is a mutable reference created for that struct. This could cause multiple living mutable references being created to NonMut without the user of why ever knowing about that.
Is this behaviour as expected? Shouldn't casting to *mut require the operand to be mut in the first place? Is there a compelling reason as to why it is not required?