← Back to context

Comment by zozbot234

5 hours ago

> The practice of encapsulation enables local reasoning about safety invariants.

> The additional scrutiny that unsafe{} blocks receive.

None of this supports an argument that "unsafe Rust is safer than C". It's just saying that with enough scrutiny on those unsafe blocks, the potential bugs will be found and addressed as part of development. That's a rather different claim.

It does, if you read the report and run a little (implied) math.

The report says that their historical data gives them an estimate of 1000 Memory Safety issues per Million Lines of Code for C/C++.

The same team currently has 5 Million lines of Rust code, of which 4% are unsafe (200 000). Assuming that unsafe Rust is on par with C/C++, this gives us an expected value of about 200 memory safety issues in the unsafe code. They have one. Either they have 199 hidden and undetected memory safety issues, or the conclusion is that even unsafe Rust is orders of magnitude better than C/C++ when it comes to memory safety.

I trust them to track these numbers diligently. This is a seasoned team building foundational low level software. We can safely assume that the Android team is better than the average C/C++ programmer (and likely also than the average Rust programmer), so the numbers should generalize fairly well.

Part of the benefits of Rust is indeed that it allows local reasoning about crucial parts of the code. This does allow for higher scrutiny which will find more bugs, but that's a result of the language design. unsafe {} was designed with that im mind - this is not a random emergent property.

  • They say "With roughly 5 million lines of Rust in the Android platform and one potential memory safety vulnerability found (and fixed pre-release), our estimated vulnerability density for Rust is 0.2 vuln per 1 million lines (MLOC).".

    Do you honestly believe that there is 1 vulnerability per 5 MLoC?

    • 1 memory safety vulnerability, that's a pretty important distinction.

      Yes, I believe that at least the order of magnitude is correct because 4 800 000 of those lines are guaranteed to not have any by virtue of the compiler enforcing memory safety.

      So it's 1 per 200 000, which is 1-2 orders of magnitude worse, but still pretty darn good. Given that not all unsafe code actually has potential for memory safety issues and that the compiler still will enforce a pretty wide set of rules, I consider this to be achievable.

      This is clearly a competent team that's writing important and challenging low-level software. They published the numbers voluntarily and are staking their reputation on these reports. From personal observation of the Rust projects we work on, the results track with the trend.

      There's no reason for me to disbelieve the numbers put forward in the report.

      3 replies →

literally from the quote:

    unsafe{} doesn't actually disable all or even most of Rust’s safety checks (a common misconception).

  • They also say

      The practice of encapsulation enables local reasoning about safety invariants.
    

    which is not fully correct. Undefined behavior in unsafe blocks can and will leak into the safe Rust code so there is nothing there about the "local reasoning" or "encapsulation" or "safety invariants".

    This whole blog always read to me as too much like a marketing material disguised with some data so that it is not so obvious. IMHO

    • > which is not fully correct. Undefined behavior in unsafe blocks can and will leak into the safe Rust code so there is nothing there about the "local reasoning" or "encapsulation" or "safety invariants".

      Strictly speaking, that encapsulation enables local reasoning about safety invariants does not necessarily imply that encapsulation guarantees local reasoning about safety invariants. It's always possible to write something unadvisable, and no language is capable of preventing that.

      That being said, I think you might be missing the point to some extent. The idea behind the sentence is not to say that the consequences of a mistake will not be felt elsewhere. The idea is that when reasoning about whether you're upholding invariants and/or investivating something that went wrong, the amount of code you need to look at is bounded such that you can ignore everything outside those bounds; i.e., you can look at some set of code in complete isolation. In the most conservative/general case that boundary would be the module boundary, but it's not uncommon to be able to shrink those boundaries to the function body, or potentially even further.

      This general concept here isn't really new. Rust just applied it in a relatively new context.

      2 replies →

It actually does support it. Human attention is a finite resource. You can spend a little bit if attention in every line to scrutinize safety or you can spend a lot of time scrutinizing the places where you can't mechanically guarantee safety.

It's safer because it spends the human attention resource more wisely.