Rust's standard library is incredibly thin (intentionally so). As a result, you need to use the crate ecosystem. This comes with some downsides.
1. Each crate you depend on generally comes with dozens of its own dependencies.
2. A large number of crates have few downloads. You can use blessed.rs to try an find "trusted" dependencies.
3. Cargo comes with "build.rs" for compile time code execution. Basically, your code (or your dependencies) can run arbitrary code when it first gets compiled.
4. A Github account is required to publish crates to crates.io (this sucks if you don't want to be locked in to another Microsoft system).
These are just a few of the issues I have had with Rust before switching off it.
edit:
Point #4 is personal for me. I have multiple crates published on crates.io and I cannot log in and manage them because I deleted my GitHub account a long time ago. I wonder if someone could create a GitHub account using my name and claim ownership of them...
> Rust's standard library is incredibly thin (intentionally so). As a result, you need to use the crate ecosystem. This comes with some downsides.
This is no different than C++. C++ standard library made so many compromises in the name of ABI compatibility almost none of the library is actually usable for any use case. So people start to quickly add things like boost, abseil, folly, Qt, asio, imgui, doctest etc. There are millions of small libraries everywhere too!
Their CMakeLists files or conan packages also execute random commands and in the case of supply chain compromise they are as vulnerable as Rust. Actually CMake is so complicated that one can hide an exploit a bit better than build.rs.
I don't think it is a good thing either way and both toolchains should implement ways to limit execution and isolate code generation. For the packages we also need to see stronger ownership and signing guarantees. Maybe even a domain-based validation system with TXT-keys against takeovers. Allowing random people to just register and typosquat packages is not a good idea.
That's not really true at all though, even in very complex software it's pretty rare to have more than ~10 external dependencies in a C++ project. People tend to roll their own a lot more, partly because dependency management is a lot more painful and fragmented. Boost is effectively an extended standard library, as is abseil, but the language has got much better at incorporating back features since C++ 2011, but even so, the dependencies tend to be slow moving and fairly stable.
True, you have few external dependencies... but you have random code thrown into your repository in the form of vendored 3rd party libraries, header only libraries, and bits and pieces copied from somewhere. Of course you also get huge kitchen-sink libraries that do everything, so you only need to add one library and have semi-decent functionality for everything you might need. At least those usually have people working on maintaining their usually pretty huge dependency tree -- those they know of. They have the same problems knowing their true dependency trees as everybody else in the eco system.
I have not yet looked at any C++ code base > 1 milliom lines where I did not find at least 3 copies of zlib. Often just the compression or decompression function copy and pasted into a random file. Which version? No idea. Was it patched? Likely. Is there any documentation on how to update this? Absolutely not. Was it easy to find? No, some specialists even rename the functions so that users linking to the system zlib do not get into symbol conflicts. I have heared way to often that it is so much simpler to just copy a class over from abseil, or whatever other library than to depend on it.
Sure, you do not see dependencies, the functionality those provide are still there somewhere though -- either hidden away or in the form of reimplementations. You just do not know... and what you do not know about you can not maintain.
I've never seen a C program use hundreds of dependencies. This is typical in Rust (and Node). I know a few high assurance teams that dropped Rust for this very reason.
They look no different than your usual Rust crate. And their full flattened dependency trees already exceeds hundreds of packages.
C/C++ libraries have much more complex build systems with many optional features shipped inside the library. Just think of curl and how many protocols it supports.
Rust's build system, however, is extremely simplistic and limited. So to have things like multiple backends for rendering, parsing, serializing etc. you have to split your library into multiple crates due to limitations Cargo impose on you. So the full equivalent of curl will be 20+ individual crates.
I think the hundreds of dependencies is overblown due to this effect. I maintain my argument. C and C++ projects are just as complex and vulnerable. CMake and fully binary distribution via Linux package managers just hide their complexity.
I haven't seen hundreds of dependencies in C projects either. But I _have_ seen on the scale of 1s to 10s of libraries and algorithms vendored in (sometimes just a header or 5).
It's also an indirect risk, but I've seen C projects reimplement things that would be a dependency in Rust, and introduce subtle (or not subtle) bugs.
again, I don't really see how 1 and 2 are rust specific; compared to c -- sure, but it's seems unfair: the type of rust software that needs a bunch of random dependencies usually wouldn't even exist in c in the first place; if it would, then it's more of a software quality problem than security
even 4 -- fuck microsoft of course, but other than that: you always need some sort of an account to publish stuff
> Point #4 is personal for me. I have multiple crates published on crates.io and I cannot log in and manage them because I deleted my GitHub account a long time ago. I wonder if someone could create a GitHub account using my name and claim ownership of them...
Why not just make a throwaway account with that username and test it, and if it works, just don't save the password or ever log on again? If it's something you care about personally and it's really been that long, I'm kind of confused why you haven't already tried this rather than just vaguely implying risk that seems pretty straightforward too verify. (It's fine if you just legitimately don't care, but it doesn't seem like it's really a personal issue for you in that case)
Most dependencies in the C/C++ world come with fewer dependencies of their own (at least, an order of magnitude fewer than the average rust dependency).
Perhaps a Makefile could be considered arbitrary code execution, but we've been running Makefiles for 50 years and we haven't had the supply chain issues we see in NPM, etc.
Supply chain risk was always considered in the C/C++ world... think back to Ken Thompson's 1984 paper "Reflections on Trusting Trust" where he questioned if you could even trust your compiler.
Perhaps the main difference between the Rust and C/C++ world is less about the tooling or languages, but more cultural? I don't know, just something to think about.
Experts know that copy/pasting and/or reimplementing code is not an issue in practice regardless of how often it comes up as an anti-pattern in freshman CS courses. The (amalgamated) software system can still be audited in reasonable time as long as the number of third party dependencies is kept low.
Rust has thrown the baby out with the bathwater in that regard resulting in software that is practically impossible to audit without putting in enormous effort.
In languages that don't have a culture of deep dependency trees managed with good tooling, supply chain attacks are perceived as being more difficult or rarer. That may or may not be true. But it is a concern in any case. Rust could have had namespaces to decrease namesquatting. The "no deps younger than N days" thing will help some. Those with this perception would prefer a large stdlib that is well vetted or that they can pretend is well vetted. In practice, if you don't use tokio you are likely not using anything that isn't written by a well known member of the rust community. Tokio brings in a lot... The real fix comes in two flavors, pay to write everything yourself and test it well. Or limit what a bad dependency can do. The latter is difficult in every mainstream language. Austral had a good answer for it, but seems to be dead.
In rust if you can verify a dependency is no_std with no unsafe code and that all of it's dependencies are the same, then it can't get to libc or the kernel syscalls. So any privilege it works with is something you passed it. But that amounts to writing everything yourself in practice.
It's not special in this regard in the language, or even especially so in the available tooling. Nevertheless, the culture in rust is to add many many dependencies. I occasionally use self-professed "small, modern" CLI tools that use ~400 crates (e.g., interactive podcast downloader).
1. Each crate you depend on generally comes with dozens of its own dependencies.
2. A large number of crates have few downloads. You can use blessed.rs to try an find "trusted" dependencies.
3. Cargo comes with "build.rs" for compile time code execution. Basically, your code (or your dependencies) can run arbitrary code when it first gets compiled.
4. A Github account is required to publish crates to crates.io (this sucks if you don't want to be locked in to another Microsoft system).
These are just a few of the issues I have had with Rust before switching off it.
edit:
Point #4 is personal for me. I have multiple crates published on crates.io and I cannot log in and manage them because I deleted my GitHub account a long time ago. I wonder if someone could create a GitHub account using my name and claim ownership of them...