Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I’m not picturing how it works.

In rust you don’t have a garbage collector and you don’t manually deallocate - if the compiler is not certain of who drops memory and when, what happens with those ambiguous drops ?

In other words, are the silenced errors guaranteed to be memory leaks/use after frees?



The borrow checker doesn't decide when things are dropped. It only checks reference uses and doesn't generate any code. This will work exactly the same as long as your program doesn't violate any borrowing rules.


No, I get that from an architectural perspective they are separate processes. The point is, unlike in other languages, the compiler is developed assuming the input has been borrow checked, right? So it is surprising to me that it doesn’t blow up somewhere when that invariant doesn’t hold.


In a correct program, the borrow checker has no effect.

Languages like C compile code with the understanding that if the compiler can't prove the code is incorrect, it'll assume it's correct. Rust compiles with the expectation that unless the compiler can prove the code correct (according to the language rules), it won't compile it. In C, all programs that only perform defined behaviour are valid, but many programs which exhibit undefined behaviour are also valid. In safe Rust, all programs which exhibit undefined behaviour are invalid. But as a trade-off, many programs which would actually execute perfectly well are also considered invalid.

In both cases, once you get past the layers that check stuff, you may normally assume that whatever you have has already been shown to be OK and you probably don't have enough information to re-check while compiling. It might blow up at runtime, it might not.


> So it is surprising to me that it doesn’t blow up somewhere when that invariant doesn’t hold.

The final program may be broken in various manners because you don't respect the language's prescribed semantics, in about the same way they do in C and C++. From the compiler's perspective the borrow checker validates that rules it assumes are upheld are actually upheld.

mrustc already compiles rust code without having a borrow checker (well IIRC recent-ish versions of mrustc have some borrow checking bits, but for the most part it still assumes that somebody else has done all the borrow checking).


The compiler has deep assumptions about exclusive ownership and moves, which affects destructors and deallocation of objects.

It doesn't actually depend on the borrow checker. All lifetime labels are discarded after being checked. Code generation has no idea about borrow checking. Once the code is checked, it is compiled just like C or C++ would, just assuming the code is valid and doesn't use dangling pointers.

Borrow checker doesn't affect program behavior. It either stops compilation or does nothing at all. It's like an external static analysis tool.


> In other words, are the silenced errors guaranteed to be memory leaks/use after frees?

No, not at all. The examples at the beginning of the article show this - they'll execute correctly. The borrow checker is quite conservative, and rules out all sorts of code that won't (normally!) cause runtime errors.

It's fairly easy to see this if you think about the core of Rust's ownership model: every value in Rust has a single owner. The compiler enforces that for any value, there's either one mutable reference or any number of immutable references to it at a time.

This model has the advantage of being simple, easy to reason about, and ruling out large classes of errors. But like most static checks, including e.g. traditional type checks, it also rules out a great deal of otherwise valid code.

It's easy to think of examples in which you have multiple mutable references to a value that won't cause errors. Aside from trivial examples like in the article, in C-like languages you can have many concurrent mutable references to the same mutable value. You can safely (with some caveats) manage access to it via locks, protocols, documentation, or just being careful. Rust with the borrow checker simply doesn't allow multiple concurrent mutable references to the same value to exist. Rust without the borrow checker, as in the article, would allow this.


The silenced errors aren't guaranteed to be memory leaks or use after frees. There are some situations where memory is being handled properly, but the borrow checker isn't able to prove it.

One example might be a tree-like struct where a parent and child have references to each other. Even if everything is cleaned up properly, the borrow checker has no way to know that when the struct is created. Solving it requires unsafe at some point, usually through something like RefCell.


I'm pretty sure that every example except example-3 in the readme intentionally invokes undefined behavior - if that helps you picture how it works ;)


I don't think so, I don't think Rust's borrow checker is free of false negatives.


Rust's concept of lifetime and scopes exists independently of the borrow checker




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: