In practice rust also tries to guide you towards patterns that reduces the risk of other bugs. For example, using Result, Option (and enums in general) reduces the risk that you forget to handle error paths. It is also quite hard to get memory leaks unintentionally in Rust, since by default you work with various smart pointers.
In my experience typical multi-threaded C++ has a lot of threading bugs that tend to cause hard to reproduce bugs (I work in safety critical hard realtime robotics / machine control, where we have a lot of communicating threads). When I code Rust I can trust the language to prevent those classes of bugs, letting me focus on the actual hard domain specific problems, rather than language minutiae. Yes, TSAN helps in C++, but that is dynamic analysis so it has to actually catch the potential problem happening while running.
So I think that the multithreading approach in Rust is really good and what we want, not a hindrance. It is absolutely the right thing to do.
Now, the async story is another matter and I have conflicting opinions on how that is done in rust. I can't think of a significantly better design that would work on microcontrollers / no-std though. I'm not interested in anything that requires allocations or a runtime.
Yes, that is true, but 1. that's not the same justification as for memory safety, and 2. that's a decision made by Rust, but it's not the only valid one (e.g. Zig has the "unordered" ordering, using LLVM's Java memory model support).
> In practice rust also tries to guide you towards patterns that reduces the risk of other bugs.
I understand that perspective, but let's say it's not hard to debate, and there's a clear difference between something that prevents a cause of a majority of vulnerabilities and something that prevents a small minority (while not preventing bigger causes).
> So I think that the multithreading approach in Rust is really good and what we want, not a hindrance. It is absolutely the right thing to do.
Well, it is absolutely what some people think is the right thing to do and also absolutely what others don't think is the right thing to do. It's an approach with both supporters and critics.
As soon as you have something larger than the hardware atomic size (or unaligned in memory) you risk torn reads/writes. So a pointer + a size for example on some architectures (some hardware like x86 has a double word atomic support, but on embedded you usually only get up to word size atomics).
All this means that you can't (in a systems level language) feasibly make everything atomic and ensure no UB.
All that said, do I wish Rust did more for other concurrency bugs? Yes, sure. Though there is some hope: I have seen Rust crates to enforce lock ordering at compile time (I think that originally came out of the Fuchsia OS kernel development). There is also scoped threads, rayon, actor frameworks etc. All different approaches to strucured concurrency, with the goal of reducing bugs. Different frameworks seem to suit different problems though. For what I do I rarely need mutexes, instead either rayon or message passing work well.
Java doesn't have this problem.
> As soon as you have something larger than the hardware atomic size (or unaligned in memory) you risk torn reads/writes. So a pointer + a size for example on some architectures (some hardware like x86 has a double word atomic support, but on embedded you usually only get up to word size atomics).
Well, the reading of a stale pointer alone could lead to UAF even without tearing.
> All this means that you can't (in a systems level language) feasibly make everything atomic and ensure no UB.
I didn't say no UB. I get that Rust decided to do something (no UB in the safe subset) and this is a consequence of that, but my point is that it's not obvious it's the best goal in the first place. Certain patterns are known to be the cause of a majority of vulnerabilities in C and C++, so it makes sense to sacrifice something to address them, but once you get to bugs that are no more common as vulnerabilities as many other bugs that Rust doesn't stop, saying we must stop these bugs and not others, even at the cost of requiring more programs to use the unsafe subset is one possible tradeoff but not a universally superior one.