4 ms·
&mut vs. & isn't fundamentally about mutability: having unique access (as in &mut) does imply that mutation will be "safe" (as in, act of mutating won't cause p
by dbaupp 11y ago
&mut vs. & isn't fundamentally about mutability: having unique access (as in &mut) does imply that mutation will be "safe" (as in, act of mutating won't cause problems, although it may violate invariants in whatever is being mutated), but types with internal mutability allow safe mutation even when shared (as in &), examples are Cell, RefCell, Mutex and the atomics.
Fields wrapped in these types can have invariants that can be violated, e.g.
struct Foo {
must_be_even: Cell<i32>
}
impl Foo {
fn evil(&self) {
self.must_be_even.set(1); // whoops
}
// ... unsafe code that relies on evenness assumption ...
}
> So it seems to fix it by hand, one could wrap all the calls which touch instances of this Vec with safe validation code -- basically guard code that runs at runtime to prevent corruptions from spreading
Yes, but unfortunately one can't always detect the corruption easily/cheaply, e.g. there's no guarantee of a detectable runtime difference between push_good and push_bad without having to introduce overhead as there's no way to look at an arbitrary memory location and tell if it has been initialised or not:
/// Push the value x onto the end of the vector
fn push_good(&mut self, x: T) {
// need space for one more element
self.reserve(1);
unsafe {
// move x into the space we just reserved
ptr::write(self.ptr.offset(self.len), x);
}
// register that there's a new element
self.len += 1;
}
// just like `evil`
fn push_bad(&mut self, x: T) {
self.reserve(1);
// don't bother writing `x`, too slow!
self.len += 1;
}
Also, there are various opt-in modes that will try to detect problems in this vein automatically (opt-in because they have non-trivial overhead). For example, debug_assertions mode built into rustc (enables integer overflow checking, and any `debug_assert!`s in libraries), and sanitisers/checkers designed for C/C++ such as valgrind (works with Rust), TSan and ASan (don't yet work).