There’s a lot of exaltation of Rust around the web. Let me summarise my reasons why this programming language should be avoided. (One could add “for now” but I don’t believe the state will ever change.)
The thing is: the Rust compiler is written in Rust. So, to compile a Rust compiler, you need a Rust compiler. Don’t have a Rust compiler? Good luck.
The only alternative compiler is mrustc that is written in C++ and can compile the official Rust compiler. But!
But Rust is far from being a stable mature language. Every minor version, Rust introduces some changes to the language. There is no specification of the language, no target state.
If you think that one reference implementation is a sufficient “specification,” then, please, take into account more than 3 thousand unfixed compiler bugs (flagged
C-bug) that there are in the official compiler today.
That makes it very hard to write alternative compilers. The mentioned mrustc only aims to provide a way to compile the official compiler. It may work for other code too but there’s no guarantee and it’s not its goal. Also, it doesn’t support borrow checking (the memory-safety superfeature of Rust).
Nonetheless, when you try to compile the current version of the official Rust compiler with mrustc, you still can’t.
Because the official Rust compiler depends on the newest language features. You have to compile one minor version of the official compiler after another, until you reach the current version. It took me several days and lots of compilations that shouldn’t be needed.
There are some efforts to get support for Rust compilation into gcc and folks pushing Rust into Linux (the kernel) try justifying their takeover attempts with it. It’s worth noting that they promise support for Rust 1.40 by the end of this year (2022) while “Rust in Linux” already depends 1.62.0 (i.e., the latest version). (And that is without any support for the borrow checker, without which it doesn’t really make any sense. So we’re rather talking about 2024.)
All that is of course possible only on supported architectures and platforms. The bugtracker of mrustc currently lists problems on macos and windows systems. Support for hardware architectures is very, very limited. Basically anything else than amd64 (or hopefully arm64 in the case of macos) is beyond support.
The official Rust attitude that no one should compile the compiler but use their binaries is completely flawed.
In 1974, Paul A. Karger and Roger R. Schell elaborated (around page 52) on compiler trap doors (nowadays commonly called backdoors). TL;DR: a backdoored compiler can infect all programs it compiles AND also itself. So the backdoor propagates into new versions. So the Rust compiler developers’ advice to download their binary to compile their source code is laughable.
As a proof, someone actually wrote a backdoor into the official Rust compiler. (This one is public and not part of the official Rust compiler repository.)
Bootstrappability is important but the Rust developers actively work against it. Therefore, nearly no one really bootstraps the official Rust compiler.
It’s quite alarming that this fundamental problem is often ignored or even downplayed. Especially when discussing something as significant as introducing dependency on (the latest(!) versions of) Rust into Linux (the kernel).
The Rust compiler version 1.63.0 is unable to compile Firefox browser version 91.13.0 or 102.2.0 (or older). Rust compiler version 1.62.0 can. That’s just sad.
But even sadder are the many warnings I noticed when examining the build logs after the build failed:
warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! Put simply, you can’t just write Rust code and let it live/let it be. Unless you don’t care that no one can compile it, you are forced to update it, even though you don’t add anything new regarding functionality nor you change any existing functionality. In contrast, I’m still writing my code in C89 to this day and have no problems compiling any C89 code.
Update 2022-10-16: @chrysn pointed out to me that the warning above (now crossed out) only materialises when the developer chooses to depend on the newer edition of Rust. That sounds reasonable. I was mistaken to assume that just a compiler upgrade would turn that code uncompilable.
This argument has already been written.
Security is almost always mentioned when talking about Rust. Especially that Rust is safer than C. It easily makes an impression that the official Rust compiler or its standard library (which are both written in Rust) or generally any software written in Rust are free of security bugs. Well, no. Some language memory-safety features don’t imply that code in that language doesn’t contain security bugs.
It is a mystery to me how one can hype Rust’s security benefits and ignore its security risks (mentioned above and below) at the same time.
The attitude of the Rust compiler developers to defects is to first require a compelling use case for fixing the defects before working on a fix, as evidenced, e.g., in this bug report. The lack of any language specification leads to situations where objective defects can be relativised or even rejected.
According to the folks over at stackoverflow, software written in Rust requires special, non-standard runtime libraries. So by default, everything is compiled with static linking. That means that every program written in Rust has its own copy of everything it needs. Which is a problem for users when a security vulnerability (or an unpleasant bug) is found in some of those bundled libraries. Normally, one would simply upgrade to a fixed version of the library. Not here – with Rust, you depend on each program’s developers to release a fixed build of their program (or, if you use a Linux distribution, on those programs’ packagers to bump the dependency and create an updated build). This mode of operation also takes much more disk space and consumes much more memory.
The current way of doing “Rust things” in Linux distributions (I checked Gentoo Linux) is to not package the dependencies but instead download them ad-hoc for each installed package. Even simple programs download tens or hundreds of crates (a “crate” is a package). All compiled exclusively for the one single package. And then again for some other package that depends on the same things. It quite reminds us of npm, doesn’t it?
It doesn’t end there. Keep in mind the number of dependencies. For each package. And now imagine either a developer that adds those dependencies to his project or even a package maintainer in a Linux distribution. Can you imagine either of them checking the dependencies and changes between versions? Security, anyone?
Note: the fact that Rust uses static linking by default is not the reason for this – it’s quite common to have static libraries in the system, so that you can statically link binaries depending on those and yet you don’t have to download & build the dependencies again and again.
The more complicated you make it for software or package maintainers to check each and every package/dependency, the worse environment you create for the overall security of the ecosystem. In this light, I cannot but say that Rust’s “security guarantees” are just empty marketing. If you want some real-life examples of how bad this is for security, check the same situation in Flatpak.
Update 2022-10-22: a Debian maintainer of packages of software written in Rust @dcz pointed out practical problems with attempts to package software written in Rust and its dependencies normally:
Kostya wrote about more Rust problems and also provided some examples. Hirrolot wrote about the problems of Rust “magic.”
As pointed out by Hyperbola, Linux distributions must not patch the official Rust compiler as that would be a breach of the Rust trademark. Bone-Baboon summarised an analysis of the problem. If you look around the free software ecosystem, patches are omnipresent. It’s just not healthy to prevent patching bugs or compilation errors (i.e., bugs).
I would like to thank my friends for their feedback on this article.
Tagged with: Rust