In what conditions could Rust code leak memory, excluding the use of unsafe code? What are the technical reasons you can't guarantee an absence of leaks?
> What are the technical reasons you can't guarantee an absence of leaks?
Well, 'leak' is one of those things that's easy for a programmer to understand, but a hard thing for a computer to understand, because it's really about intent. How long did you intend for some resource to live? Any global value is, in some sense, a leak. We had a long discussion about this, and, at least currently, we couldn't come up with a formal enough definition of 'leak' to even start tackling the problem of "how do we solve leaks." (It is entirely possible that I am unaware about research on this topic... but given that solving leaks wasn't a goal of Rust, fixing it would just be gravy anyway. You have to choose your battles, and Rust certainly isn't perfect.)
As for how safe Rust can leak:
let x = Box::new(5);
std::mem::forget(x);
which can itself just be implemented in safe code:
use std::cell::RefCell;
use std::rc::Rc;
fn forget<T>(val: T) {
struct Foo<T>(T, RefCell<Option<Rc<Foo<T>>>>);
let x = Rc::new(Foo(val, RefCell::new(None)));
*x.1.borrow_mut() = Some(x.clone());
}
or something like "I have a thread that is holding the receiving end of a channel that infinitely loops without reading anything off," in which case anything sent down that channel leaks.
That's a very intriguing block of code there. I'd like to think that while Rust may not have been designed to guarantee that leaks are prevented, it so happens that anything that could leak memory sticks out like a sore thumb in code review, since the code to get something to leak needs to be explicit. I'd consider a global variable or a channel that has the possibility of not reading all its values to follow that pattern. Whereas it's much easier to get something "stuck" in memory without a reference in C++. But you're absolutely right that memory safety does not at all imply "leak" safety, nor is the latter well defined at all!
It is technically possible to guarantee the absence of leaks by introducing a `?Leak` trait to the language. There was a point in time when many wanted Rust to go that way, but it was ultimately decided against (it complicates other things).
Note that the trait-based scheme referenced here would only prohibit specific kinds of memory leaks. "Leaking", in its broadest usage, isn't a solvable problem in a Turing-complete language since an infinite loop can be considered a leak.