> one can write fairly safe C code
In practice, pretty much every C/C++ codebase in existence has ended up having memory safety issues, even very widely used ones with a lot of scrutiny over the years.
> while Rust code in practice is also far from perfectly safe and also introduces new supply chain risks.
You're conflating "does not have one notoriously dangerous type of safety issue" and "does not have any safety issues", which is a disingenuous characterization of what I said. You were the one who introduced the comparison to memory safety in Rust and C++, and now you're moving the goalposts as an attempt to rebut my disagreement.
You don't have to agree, but this is how I see it.
That is explicitly not what I'm claiming. You seem to think that I think "memory safety" is equivalent to "safety", which is what I've repeatedly told you is not what I'm saying. That's conflation. It's not clear why you'd expect me to read more details you give after repeatedly ignoring what I'm saying and putting words in my mouth that I'm not saying, so I have to assume at this point you're posturing for other readers rather than actually trying to communicate with me in any reasonable way.
But maybe I am still not getting your point correctly.
Yes, there can be compiler bugs that cause unsafety in safe Rust code, and it's possible to have unsafety in dependencies that leads to issues in code that otherwise looks safe, but this can happen in C++ as well. My point is that the risk of having memory unsafety from bugs that you write in your own Rust code is effectively zero if you don't ever use the unsafe keyword, and this is how most Rust code is written in practice. Most C++ code is not written in a way that produces anywhere close to this level of confidence because the language fundamentally does not support anything like that. I don't think that contracts would fundamentally change this.
On their own, no. What contracts provide are annotations for how the programmer expects the code to behave, which can be verified by model checkers or automatic theorem provers. These can already verify memory safety properties; borrow checking only does a subset of what a model checker can do. To scale model checking up so it can work on a large codebase, compositional verification is required. Contracts enable compositional verification, which in turn allows developers to write code safer than what is possible with vanilla Rust or Java.
I do this today with C. The model checked C I write is safer than software written in Rust without a model checker. It is memory safe, and it is verified to work within the specification that I have designed. As far as the specification is correct, it is correct.
We can't rewrite the world in Rust. There are many billions of lines of code in C and C++ that aren't going away. Instead, we need to find ways of making this code safe with as little change to it as possible.
In practice, we also still see memory safety issues also in Rust code exactly because people use "unsafe" or have a dependency that does. I also see that practical impact of memory safety issues in well-maintained C/C++ code is almost zero on my personal security (rare, often mitigated or extremely difficult to exploit). And after the LLM wave of issues is processed, this will be even less a problem. I am far more scared about supply chain issues (and I bring this up as comparison for proper risk assessment, not to move away the discussion from memory safety).
Then, theoretically, one could also make sure C/C++ have no memory safety issues. (And I have done this myself in toy programs and industry also for larger projects, so this is not even purely theory.) The languages does not fully support this yet, yes, but why does this matter so much? The language / compiler / good coding standards still support reducing memory safety issues to low levels - which is relevant, because outside of theoretical scenarios, this is what Rust also achieves in practice (and not perfection in getting rid of memory safety issues).
And then now in this thread, this argument that in C/C++ it is more difficult to achieve perfect memory safety was even used as argument against a feature that would be a step towards making this easier. This I find completely misguided.
(I am not talking about compilers bugs).