The following code creates boxes, each pointing to a block of 4096 bytes. If I run this on release, everything is optimised away :(, but on debug, this behaves as expected and leaks a bunch of memory... or does it?
fn main() {
for _ in 0..1000 {
for _ in 0..100000 {
let b = Box::new([!0u64; 1 << 10]);
std::mem::forget(b);
}
let mut buf = String::new();
let _ = std::io::stdin().read_line(&mut buf);
}
}
Why is this not considered unsafe?
The other answers have given good information on why this is considered safe today, but it's also useful to know the context of how this came to be the case.
Long ago (before 1.0), Rust did guarantee that safe code could never cause a memory leak (and as such mem::forget was marked as an unsafe fn). As a consequence of this, other unsafe code was written that relied on this assumption.
However, this turned out to be completely untrue - for example, you can trivially create a memory leak by creating cyclic Rcs! As a result, several APIs in std (most notably, the original implementation of scoped threads) had to be removed or rewritten, as they were unsound.
This is occassionally referred to within the Rust community as the 'leakpocalypse', and it led to Rust's definition of memory safety being changed to no longer cover memory leaks. Since leaking memory was no longer considered unsafe, mem::forget was changed to no longer be an unsafe fn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With