Along with the broader industry trend of transitioning security-sensitive code to memory-safe languages like Rust, there has been an effort to write a Rust-based replacement to GNU Coreutils. For nearly a year that Rust Coreutils has been able to run a basic Debian system while more recently they have been increasing their level of GNU Coreutils compatibility and in some cases now even outperforming the upstream project.
For someone like me, who isn’t a programmer, it’s difficult to really say anything meaningful when it comes to the pros and cons of individual programming languages, but on the face of it, with my limited understanding, modern languages like Rust do seem like a safer, more modern, more robust choice.
As a programmer, I can say that there are pros and cons to rewriting in languages like Rust as far as safety and robustness go:
The pros are related to how a modern language with a much stronger type system than C or what C++ inherited from C allows you to teach the compiler to catch more mistakes.
The cons come from how, whenever you rewrite anything, you’re likely to reintroduce bugs in the areas the system can’t catch for you.
This played out when someone experimented with rewriting
sudo
in Rust. The result turned out to reintroduce some holes that relate, not to the programming language or memory safety, but to corner cases in the POSIX APIs.That said, if they’re enjoying putting in the effort, I’m all for it. We have to switch to something that takes less effort to maintain and develop sooner or later.
ssokolow,
You are right, but at the same time our tech industries have been suffering from the same coding bugs for decade after decade. If we are unwilling/unable to move on from those languages, it’s going to keep happening. There’s still money and jobs in maintaining ridiculously old code bases because companies/people/governments can’t stomach throwing decades of work even if they have to spend millions a year maintaining it.
I wish POSIX could be updated, there’s a lot of legacy baggage. For better or worse though it’s what we have.
Well, I’m for it. I think it makes sense to clean house every few decades to modernize infrastructure. A lot of these systems would benefit from modern databases and languages, not to mention some are even still green screens. But if enough people fight new languages, they won’t replace the old ones.
The unintended bugs are more likely due to poor or non-existent TDD practices. Side effects do happen even when updating the legacy codebase although mature code like the tried-and-true coreutils is much less likely to undergo major changes. Here is the challenge. Hidden knowledge is buried deep in the legacy code for which there is no corresponding test coverage that would be eventually lost during translation into a new language.
Lots of recently discovered vulnerabilities in Linux and various Open Source projects have not been about the usual issues with unsafe programming (failure to malloc(), free(), using what’s been free()’d, off by one errors, accessing arrays beyond their limits) but issues in basic logic and those issues Rust or any other “safe” language just cannot solve.
That probably means we need to start to formally verify algorithms in critical applications/libraries/kernels but that’s extremely difficult, time consuming and expensive.
Can you elaborate? As someone who came to Rust from Python, I can attest that Rust’s type system is a lot more than just memory safety.
For example, it’s powerful enough to enforce the typestate pattern so you can teach the compiler to enforce correct traversal of any API that takes the form of a finite state machine.
(eg. the Hyper HTTP library uses the typestate pattern to catch “can’t set HTTP request/response header after the body has begun streaming” at compile time. When you start streaming the body, any references to the previous state are invalidated, and the request/response object in the “streaming body” state has no method to set headers.)
https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034
https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html
https://www.openwall.com/lists/oss-security/2022/01/24/2
All of the above vulnerabilities are about formal logic, not about the C language or unsafe programming.
PwnKit is a classic example of exactly the kind of memory-unsafe operation Rust API design is meant to avoid.
Assuming you replicated the
for at line 534 rather than writing your Rust idiomatically, the out-of-bounds read at line 610 would panic, resulting in a controlled, memory-safe exit from the program and, if it somehow didn't, the out-of-bounds write at line 639 would panic.
(Yes, Rust does have a
get_unchecked
, but then you’re visibly going out of your way to bypass a bounds check for no apparent reason… like reinventing a built-in language construct using overly convoluted and verbose typecasting in C.)Aside from that, Rust’s approach for retrieving
argv
is an iterator API that you’d have to tie in knots to get in that situation in the first place. If they hadn’t ellipsized so much, I’d write a sample of what the Rust equivalent would probably look like.As for CVE-2022-21658, sure. That’s a vulnerability in the Rust standard library. Here’s a historical breakdown of CVEs in glibc.
Your argument for that one can be trivially translated to an argument against C in favour of something which provides even less compile-time safety, like assembly language, since assembly language doesn’t have glibc, so I don’t find it very convincing.
I’ll admit that CVE-2021-3996 is something Rust probably wouldn’t have helped with, being misuse of a platform API, though I wouldn’t rule it out. I’ve noticed that the ecosystem culture in Rust puts more peer pressure toward ensuring your code is sound and correct than that of C.
As for CVE-2021-3995, that looks like something Rust’s API design would have prevented. It happened because someone accidentally misused one of C’s many slightly different string-comparison functions, turning a guard against walking off the end of the string into an accidental prefix-only comparison.
In Rust, you just use a normal
==
and trust the string types to enforce memory safety… even if you’re comparingString
toCString
orCString
toCString
.Artem S. Tashinkinov,
You can have both kinds of errors. However that doesn’t reduce the benefits of safer languages…
1) verifying code won’t corrupt it’s own memory is useful in and of itself
2) solving #1 means that humans can now focus their limited resources and attention span on the logic of the problem
Indeed. We need to break down problems into more manageable chunks. This means discouraging monolithic solutions and breaking problems down into simpler components where all possible states can be verified. Then these components can be combined to build up ever increasingly sophisticated units of functionality..
I find it weird that this is one of the fundamental ideas behind object oriented programming that has been around forever, and yet so many projects today don’t use those principals effectively. Spaghetti code is widespread. I think part of it has to do with project management. There’s so much rushing and cost cutting that we don’t always start with strong upfront designs, or we go strait from proof of concept to coding a product without a design phase. By the time it comes to implementing user’s requests it may be faster & easier to hack the interface than redesign it, thereby creating new strands of spaghetti.
It makes me wonder if next generation languages (beyond rust) may be able to provide help in this area too. It could take existing code and make recommendations for refactoring it into simpler components with looser coupling. To date code refactoring is something that project managers learn to despise because it is labor intensive and can introduce new bugs, even though refactoring can be necessary to bad designs and convoluted flow. I’m not aware of tools to do this today, but it ought to be possible to automate refactoring without introducing any more bugs by letting the computer transform the code.
Thats a very good idea/point! I was just writing a comment about how changing the language does solve some problems, but its the design thats the issue. Especially when writing a like for like replacement component, the design is very restrained.
What you are suggesting comes to the heart of it, and its something that is very difficult in the open source world (coordination of design across a disparate, part time team is far harder than a full-time focused one).
Adurbe,
Automated refactoring opens up a lot of possibilities. Obviously it could help with the periodic refactoring that projects need, but if it worked well I think it could go further than that. In the future, re-factorization could be as fluid as automatically applying new style guidelines to source code is today. Some kind of parametric refactoring IDE could enable different views of the same code in real time, all while guarantying that the transformation correctly depicts what the program is actually doing. Different teams could use their own refactored views, similar to database views, optimized for their purposes to help with debugging and editing the pieces they are interested in, all while remaining logically synchronized with the canonical version.
This could be really cool!
Anything that relieves a programmer from having to micromanage buffers, pointers and memory allocation is a good thing IMO, because it allows the limited mental capacity and limited time of the programmer to be devoted towards writing better logic. So, it doesn’t matter even if all the bugs were logic errors, by overloading the programmer with micromanagement tasks, you are increasing the potential of logic errors. It’s the reason why even the earliest typewriters will automatically advance to the next character for you (despite the fact doing so manually is “a trivial task”). Trivial tasks still consume time and mental capacity even if always done correctly (which itself is unlikely).
BTW I agree on the need to start formally verifying algorithms in critical applications/libraries/kernels. I hate the fact our industry is basically the equivalent of the builder that “eyeballs” the thickness, position and shape of the structural elements that they are about to build. Unfortunately, formal verification is something that’s opposed both by proprietary software companies (for obvious reasons) and by the FOSS community (because having to formally verify software would make it harder to contribute).
I won’t argue with that, that’s actually a great point.
I just hope that using safe languages doesn’t make everything slower while consuming tons of RAM.
Artem S. Tashkinov,
That was true of garbage collected languages like Java that needed more memory, but with rust there’s no need to defer frees and all the verification happens at compile time so it can be used in systems where runtime overhead is undesirable.
Java is a bit infamous on that front.
When Etherpad (Java) was rewritten to Etherpad Lite (Node.js), it went from needing over a gig of RAM to around 150 megs, as I remember… and I’ve seen multiple examples of people being amazed at how much less RAM their service required when they rewrote it from Node.js to Rust.
Here, for example.
Another person said they saw a drop from over 100MiB in Node.js to a stable 7MiB in Rust.
It’s not just that Rust doesn’t need to leave space for floating garbage (apparently the official jargon for things that haven’t yet been noticed as unreachable by the GC), but that:
1. Its APIs encourage stack allocation
2. The friction from its ownership-and-borrowing model pays off in far fewer cases of having a GC silently extend the lifetime of something you didn’t expect to live that long in order to make your code Just WorkTM.
(Think of Rust’s borrow-checker errors as the compiler asking for clarification on whether you wanted a memory copy, a reference count increment, etc. or whether it was just a mistake on your part, rather than just guessing.)
Real-world results seem to show that, most of the time, it’s a mistake on your part that wastes memory.
I”ve looked a bit at Rust and this is a complex language, unlike plain C.
The security offered by Rust comes with extra complexity to understand how it works, and complexity in the compiler (then, is there a formal proof of the compiler?).
In my experience, C is not as simple as it looks… it just abdicates responsibility to “It’s your fault if you don’t understand all the vagaries of the underlying platform and abstract machine that we washed our hands of”.
I suggest reading John Regehr’s Undefined Behavior in 2017 and the LLVM Blog’s What Every C Programmer Should Know About Undefined Behavior.
Also, Rust is very much a language designed around not needing to understand everything to use it safely and effectively. With C or C++, what you don’t understand can and will hurt you. With Rust, it’ll cause a compile-time error.
In Rust, the complex, hard-to-understand stuff is more to allow you to expose simpler APIs. For example, if you’re using it as a more correctness-conscious Python, to write applications depending on pre-built components, you might find it being as simple as “Python, but with a stack/heap distinction”.
On the topic of proving things, efforts are in progress, though C isn’t exactly practical to prove for non-embedded use-cases either.
From my time hanging out in /r/rust/, the RFC tracker, etc., I can tell you that a lot of the unsoundness that’s discovered lies in the LLVM code shared between rustc and Clang, which was never surfaced before because C wasn’t expecting as much soundness. (eg. Stuff like C code being made unsound because the optimizer was incorrectly applying C++ assumptions, the
noalias
LLVM IR annotation breaking things because C programmers don’t use therestrict
keyword very much, etc.)That’s not to say stuff residing in the rustc frontend is perfect (Feel free to poke through the I-unsound tag on the tracker for non-LLVM examples)
I’m not an expert on Bugzilla and not familiar with the LLVM and GCC bug tagging systems or I’d offer up links for comparison.
Treza,
It’s a bit different, while I wish they made the syntax more familiar, it is what it is.
As far as expressiveness, it was very carefully designed to require exactly that which is required to make the code safe. It’s not really more complicated than what a C programmer should already be reasoning about in their head. But by declaring it in the language now the compiler is able to verify that reasoning even after the programmer forgets, making the code safer.
I don’t actually know the answer to that. Do any mainstream C compilers have a formal proof? If not yet, maybe some day.
As far as I know, CompCert is the only formally verified one of note and it’s not mainstream… and, as Ralf Jung’s Do we really need Undefined Behavior? points out, that doesn’t prevent it from using undefined behaviour in ways that can be surprising to programmers, but which are allowed by the C spec.
(Compared to Rust where, if you don’t use the
unsafe
keyword, you only have to worry about your dependencies invoking undefined behaviour, not your own code.)Since it’s been over 24 hours, I’ll just mention that I did reply to you but it’s been stuck in moderation because I used too many links.
I am surprised that there is not more interest in Relibc:
https://gitlab.redox-os.org/redox-os/relibc
I get that the Coreutils are, you know, core but the C library effects everything. If you really think that things need a rewrite, it seems like the place you would get the biggest bang for buck.
As it is, these Rust Coreutils are still going to rely on a C library written in C, with all the issues that the Rust enthusiasts are hoping to eliminate.
Although, to partially answer my own question, it seems that one of the primary motivations for uutils ( Rust Coreutils ) is to be able to use the same code to build the same utilities on multiple platforms. Rust does seem to excel at working cross-platform more or less out-of-the-box. When it comes to C libraries, the same cross-platform benefits are not really going to apply as the C library is the place where the uniqueness of the operating system and its system call specifics are abstracted away into a more uniform interface to applications–it is called the “standard” library after-all.
tanishaj,
Rust exists in a world of C and so transitions are piecemeal, replacing a bit at a time, but I think the hope behind many of these projects is for rust to eventually tackle more and more of the C bits until the codebase is all rust and we’re no longer limited by C interfaces.
C/C++ has needed some simplifying and tidying and a dose of the sensibles for years but it never happened. Lots of known knowns versus can’t change won’t change. So yet another language needed to work forwards out of the problem.
I’m glad I no longer code. Still, it’s nice to see someone doing something about problems even if it is like pulling a wellington boot out of a peat bog.
I’m scratching my head wondering what use men are. Servicing the gas boiler and emptying bins are easy ones. I’m not sure about this pile of nonsense but men seem to be finally catching on that safety matters as well as classic design principles. Yes, women have only been screaming about this on the front pages of newspapers for the past thirty years! As for design? Yves Saint-Laurent? Yuck. Christian Dior? Fine.
Anyway, I don’t care about any of this stuff now if my stuff works. Yes I still want to know that the underpinnings and implementations are good. I’m not stupid and know what you lot get up to. Other than this as long as stuff is spiffy and doesn’t give me a headache I’m fine.
A little less stereotyping, please? Speaking as a man, those of us who are paranoid about safety and hate the cowboy attitude of so many programmers do exist.
There’s no need to swing the stereotyping axe back in the other direction.
Men are a big target and there will be some collateral damage! lol I actually do have a nuanced view of the public policy issues but ye gods. I do run into them!
I do encourage people to read material on these subject areas and haven’t yet met a man online or offline who has bothered once. It’s omg women’s issues omg the women’s pages of the newspaper omg a bit too “woke”. This material is actually another form of system with inputs and outputs. It’s no different from health and safety regulations or coding practice guidelines.
I was in Boots yesterday to buy some lash glue and baby oil. Of course the lash glue section was empty apart from a gimmicky one I wasn’t convinced about. So I was at the till and asked the man on the till if he could do organise a stock check. His answer was if it wasn’t on the shelf it wasn’t in stock. Ooh, Mr Lazy. I stood my ground so he rang for some assistance. Anyway, the poor young man tasked with this had to wander all the way down a flight of stairs and all the way backup and all the way back down again. He did produce the lash glue in both variants. Now he did say he didn’t know if this is what I wanted while standing there like he was going to shit a brick. It’s okay, lovely. I don’t bite. Yes it was. So anyway. Business done. Thank you’s all round. But men? Lazy and clueless! If I wasn’t there with a whip to get the men in gear nothing would have got done and I would have gone home miserable and would have had to make another shopping trip! No I don’t mind shopping and need the exercise but I was running out!
To be fair retail is a hard and exhausting job and not paid the best. I’m always as nice as I can be but if madam needs her stuff madam needs her stuff.
I was out to an official meeting this past week and fairly soberly dressed. I had two men in the street shouting “Hey, lady” at me twice in the space of a single hour. On the way back from Boots a man also decided to cross the road in what happened to be the darkest place in a direct bee-line for me and said “Alright!” as he walked past. In workplace situations this week I also had to put up with a gung-ho white night and a 1970’s comedy show reject. (I’m meeting with their regional manager who happens to be a woman. Oh, dear. Somebody is in trouble. That’s before I bring up complete lack of communication and the go around in circles dead end clown act organisational responses.) Not every man I meet is a complete and utter berk but they are a minority so you will have to excuse me if I have a dim view of men at the moment.
Anyway, I’m refusing to work with men at the moment. I’m also having decent conversations. Like this week? Divorce, menopause, and weight gain plus a lot of business information men never talk about. I’ve got more done and learned more in a week and my mental health has improved working with women than a whole year with men who I have previously been stuck with. I am not joking!
Ugh. I hate those kinds of people.
I’ll admit that I’m a bit guilty of “and haven’t yet met a man online or offline who has bothered once”, but that’s less a matter of not wanting to and more a matter of “Dammit, I’ve bought (not borrowed) these books (in dead tree form) and I need to get my time management issues under control so I can actually stick to my plans when I block out time for leisure reading”.
(eg. It took me years to find a good price on a copy of Sexual Politics by Kate Millett after barely starting the copy that was lent to me as a teenager and it’s still sitting on my TODO shelf with the “didn’t know it was signed when I bought it” copy of The Visual Display of Quantitative Information that I’ve been holding off on reading for years because the dust jacket is “soak up any skin oil it can” matte and I keep procrastinating finding a good source for museum gloves that fit me.)
Fair enough. I think there’s still a fair bit of idealist in me that I haven’t managed to root out and eliminate, though #metoo and COVID have certainly helped there.
Is there a word that means “misanthrope” without the negative connotations or is it one of those situations where, no matter how insane they are, the majority are in the right by definition? Realist?
HollyB,
The problem with that is you constantly berate men (and americans) without cause. Here on osnews you’re often the only one being difficult. Mature people can and should disagree without resorting to stereotypes that don’t fit what’s happening. You’re a broken record and always go strait to suggesting that something is wrong with the other person rather than accepting that reasonable people can disagree.
That’s just as sexist as “I’m refusing to work with women at the moment. I’m also having decent conversations.”
HollyB,
Thanks for sharing a day in the life of a paranoid manhater. It is plain to read from your batshit crazy comments that you are a delusional, androphobic, misandric and insufferable human being. My heartfelt sympathies goes out to those who have to endure your abusive presence on a daily basis. You can skip your usual handwaving social commentary on reading peer reviewed papers, because “getting the clue” doesn’t seem to be your thing. Narcissism and victimisation, on the other hand… Decent conversations about divorce, menopause and weight gain? You gotta be kidding me. Given your proclivity towards neuroticism, it is unlikely that you do have a nuanced view of public policy issues…or any issue for that matter.
This troll just craves attention. Don’t bite.
“I’m scratching my head wondering what use men are. Servicing the gas boiler and emptying bins are easy ones.”
Sexism and hatred should not be tolerated at a time where we have been fighting for our right to be included along side men as equals.
Shame on you. Your toxicity, hatred and insecurities have no place here.
I think I am thinking like an old person, however being a “replacement” will be a high bar.
As the common 80/20 wisdom goes, the final stretch to reach feature parity will be the most time consuming. Especially when they need to replicate all behavior, including any expected bugs, so that these can be drop in replacements. There are huge amounts of shell scripts that depend on these utilities, and randomly and silently breaking them would not be nice.
(Let us be honest, error checking is rarely done well in bash scripts).
That being said, Busybox is out there, and works well for many systems. So at least for that use case it could be a valid alternative.
No-one comments on the license?
I guess not. Why is using the MIT license an issue?
I was about to comment on that! Writing a GNU coreutils replacement and distributing it under a “permissive” license, feels like subversion of the GNU’s original intent.
It’s probably more that the overwhelmingly common choice in the Rust ecosystem is to dual-license under MIT/Apache2 so you require a patent grant from contributors (Apache2) without that “additional restriction” locking out GPL2 compatibility.
I’ve seen a lot of people in environments like that choose pure MIT because they didn’t understand the purpose of the Apache2 side.
I have no big issues with Rust language but there is one thing that is troublesome for me. And that is some feel they are entitled to force the usage of Rust language to get picked up by some prominent projects. Instead do your own projects and write them in Rust language. Nobody is forcing you to use C language. As for rewriting GNU Coreutils. In its core this is basically a NIH. Choosing a different licensee is basically a political statement. But OK, at least they are not saying GNU Coreutils must adopt Rust. Long story short the main problem i have is hype. I have often seen in the past that hype leads to sometimes some good things but often there are negative aspects involved too. I invented this new programing language everybody should now use. Well, no. Compete like the rest. After a few decades some prominent projects might use it.
Geck,
I can see why you say that it’s a type of NIH, but I’m not sure what the alternative would be. Rewriting things including coreutils is necessary to do if your goal is to replace unsafe languages with safe ones.
Most developers including myself keep using C because it’s a defacto standard for system programming and not because it’s uniquely qualified. Going against the current is very inefficient but I think many people are so fed up with C being top dog over so many decades despite many other languages having more merit. So I welcome the new challengers but i don’t think it’s going to be easy to replace C due to habit and resistance to change.
Personally i don’t believe Rust will make any significant dent in regards to long lived projects with large C or C++ code bases. At least not anytime soon. Rewriting projects such as GNU Coreutils in Rust. OK lets see the benefits in the next couple of years and lets judge then. As for new projects. Here i feel that it makes sense to choose as you say a programing language with the most merit for that project. And one of the options is Rust. If Rust will always get selected. Over languages such as C or C++. On the merit of better memory safety. I sincerely doubt that. What will likely happen instead is a couple of prominent (future) projects could on the long run use Rust. With all the pros and cons included. Just like with other competing languages. And i am sure that Rust language is not the last language intended to replace C, C++ or Rust in the future. Likely one per decade or two is reasonable to expect. Said that now i am going to write some Fortran.
Geck,
You may be right, C still has all the momentum.
I think C’s track record for trivial vulnerabilities has been proven so many times that I don’t think it’s much of a debate at all. The proportion of memory corruption errors in new code will drop significantly while leaving the human logic errors, but even so that’s still a big improvement over C. Personally I’m fed up with C holding back our industry’s robustness and reliability, not to mention language annoyances like header files, which they didn’t even fix with C++…ugh!
I think it’s an interesting question is to ask whether rust is the best language to replace C? That’s a tough question…I really like the syntax of Dlang, they did a good job addressing the problems with C/C++ and I wish something like it had taken over for C decades ago, but of course it didn’t. Also today Dlang is less safe than rust. Hypothetically if Dlang could embrace rust’s full compile time safety checks and do away with the garbage collector, which I think was a strategic mistake for a low level language, I would prefer it over rust.
C’s coming up on 50 years now and I’d say we’ve been due something better since the 80s and 90s. Realistically it’s very hard to change momentum and replace such dominant incumbents!
Lets say that you would decide to crate a new operating system kernel in 2022. For some niche purpose but of a more general purpose nature. Would you go with C or Rust?
Geck,
Probably C++?
Most of the current modern operating systems are at least partially written in C++. Windows, Mac OS, Android (core, not kernel), Fuchsia, Haiku, FreeBSD.
I think Linux is the only holdout without any C++ code in the kernel.
To be fair, all also contain C in various amounts. Historically, C has been a very good high level “assembly” language, which also happens to be very portable.
However as soon as you need better data structures, it falls apart. Hence people look into alternatives. C++ has issues, but works. D has never gotten off ground, Go is terribly slow. That left Rust as a good alternative. Yet, if you look at personal opinion I don’t like its syntax.
So, once again C++ is the most likely choice.
Geck,
Wow I applaud you for such a concise yet meaningful question
Assuming that reusing existing code were a non-issue, then I’d want to go rust as more forward looking. However I know that any new operating systems’s chances of achieving critical mass are incredibly slim. If we use market share as the project’s metric for success then it will not likely be reached. For this reason there’s little choice but to take small oppertunistic steps. That’s my gut feeling anyways.
sukru,
Many people seem to think the same thing. I wonder just how much rust’s syntax is impeding its adoption. If rust had been built on C syntax instead, like Dlang, I think people might be more open to it as a successor.
I find that when nearly everything is built in C or C++, using something else can become an upstream challenge even if it’s better. I think a lot of people find themselves in the same boat.
C’s popularity may be its biggest strength right now.
Alfman,
C++ is getting there
With things like
become common in regular code, it really make sense to look at alternatives. That example is made up, however only template library code used to look that convoluted, now it is not too rare to see type descriptions that take entire lines.
Rust has lost a great opportunity by not adopting the C syntax.
@sukru
As this news was about GNU Coreutils and a rewrite in Rust and my question implied some analogy to Linux kernel. As some want to introduce Rust to Linux kernel too. I wanted the question to be more in the lines of C vs. Rust. If you had to choose one. Now obviously in such debates C++ will quickly get mentioned too. That is if you would start some project from scratch. @Alfman OK fair point. You would make a bet on Rust. Nothing wrong with that as in the end that is how it should be done. If Rust is the future then for sure some prominent Rust projects will emerge over time. Expecting it would be a good thing, to start mixing some existing projects, mainly written in C, with Rust. I am not all that sure about that. And here i feel that the Rust camp wants to force things. They expect the world will change today. When in reality such changes take decades. Just like it was with C vs. C++. Where C and C++ have much more in common then comparing C/C++ with Rust.
sukru,
What do you define as “the C syntax”? I’m not sure how you’d be qualitatively different when you still need to support generic types and composable signatures.
Sure, some people would have preferred square brackets instead of triangle brackets for generics and no shorthand for
my_vec.get(0)
, but that only goes beyond the level of bikeshedding in that it would have avoided the need for the turbofish operator in contexts where it would otherwise be ambiguous whether you meant generics or less/greater than.…and, of course, you can always use something like this to shorten the signatures.
use std::sync::{Arc, Mutex};
type Handle<T> = Arc<Mutex<T>>;
Heck, that’s what
std::io::Result
is:std::io::Result<T> = std::result::Result<T, std::io::Error>;
ssokolow,
By C syntax I mean, literal C syntax.
Except minor divergences that happened in C99, almost all C programs are also valid C++ programs. Not only that, the family includes Java and C# as well, which are very similar on things like generics, lambda expressions, classes, and so on. Of course they are not the exact same, but learning one will make people familiar at others.
Rust seems to be “foreign”. There are Pascal like artifacts like “fn” for “function”, whereas a simple return type will convey the same meaning. Or “print-ln” like “write-ln”.
Of course these are all superficial differences, but as @Geck mentioned, there is a “forceful” promotion of the camp Rust, and it leaves a bad taste. Especially when working on million+ line C++ codebases (and Java, …), but the entire world’s output of Rust is still tiny in comparison.
ssokolow,
I agree with sukru that the differences are quite superficial in nature, but regardless it feels farther away than other languages in C’s orbit like java/dlang/c#. It has a slight basic/pascal/ada feel to it, not derivatively so, but it moves a bit in that direction.
I don’t think there’s anything necessarily wrong with this, but consider how many people consider C++ to be C with more features. If you are a C developer and would like classes/namespaces/encapsulation/strong typing/etc, it is true that there are lots of languages that get you there, but none quite so trivially as C++ making it a very easy sell for C developers and projects.
You don’t have to sell me on the merit and power of rust. I’m all for migrating to safer languages, something which is long overdue. Tons of projects would be better off using rust over C. But…there are bits of syntax that go against my preferences as a C coder, like the “let” statements that I’m not a fan of. It’s little things that like which don’t effect the power of rust, but increase subjective resistance to the syntax. I just have to tell my brain to like it, haha
Alfman,
Ahh. That’s probably the ML influence. A lot of things that seem strange trace their ancestry back to Ocaml, which the Rust compiler was originally written in. For example, that
'a
syntax for lifetimes is Ocaml’s syntax for generics, because, abstractly, lifetimes are a special kind of generic parameter. (i.e.'a
is Ocaml’s<T>
, right down to using “a” rather than “T” as the default name in the example code I’ve seen.)Calling it “let” as opposed to something like “var” is straight out of Ocaml, but having something like that was a conscious decision to avoid the need for something like the lexer hack.
@Geck
“Lets say that you would decide to crate a new operating system kernel in 2022. For some niche purpose but of a more general purpose nature. Would you go with C or Rust?”
What does Rust provide that we wouldn’t get from Checked C?
https://www.microsoft.com/en-us/research/project/checked-c/
Though in answer to your question, I’d personally use idiomatic Modern C++.
@Zayn
Whenever someone mentions Modern C++, I’m reminded of Alex Gaynor’s Modern C++ Won’t Save Us and What science can tell us about C and C++’s security.
@ssokolow
What does Rust protect you from other than yourself? It’s just the low hanging fruit.
It wouldn’t be so bad if it wasn’t so fugly.
The concept is fine, it’s the implementation that I personally have a problem with. Well, that and the rabid evangelical “convertitis” that seems to be the dominant personality trait in many of its proponents.
It’s not the Messiah of software engineering nor will it ever be. It’s just another tool. Use it or don’t use it. Choose the right tool for the job.
In this hypothetical new operating system that I chose Modern C++ to implement it in in reply to Geck, I could compile it for pretty much every single architecture I fancied.
How many does Rust support?
Personally here is what would work for me. Linux kernel is monolithic and written in C. Some people claim that is a rather bad thing from security point of view and we need to change that. On how to do that. Some argue microkernel design is the way to go. And some claim there are better languages for writing a kernel. Mainly C++ and recently Rust, due to improved memory safety support. Now what we have is Linux powering billion of devices, hence what we further need is Fuchsia/Zircon, that is written in C++, being of a microkernel design. And i guess Redox OS. Being written in Rust and of a microkernel design. We need all three on some mission critical devices. That allow installing software, have a web browser, banking application … And lets compare after on how they compare in regard to security.
Zayn,
Well, protecting from human mistakes that are easy for computers to catch is kind of the point though regardless of how low hanging the fruit is.
I think there’s a growing opinion among those of us in the software industry that C is almost always the wrong tool for the job for any project requiring security because of how easy it is even for experienced C developers to accidentally write faulty code that other languages would have prevented.
So the main question to those of us who acknowledge the notoriously insecure nature of C programing isn’t whether a replacement is justified, but what that replacement should look like. One extremely compelling aspect of rust is that its safe abstractions are zero cost, verified at compile time instead of at runtime! This is extremely desirable because runtime overhead has been used as the reason that java and .net cannot replace C for example.
All the ones that the majority of mainstream developers will care about, even some unusual platforms are supported as tier 2 and 3.
https://doc.rust-lang.org/nightly/rustc/platform-support.html
To the extent that you have such a niche platform that isn’t supported in any of the tiers then you obviously can’t use rust at the moment, but do you have an example that actually affects you for real or is this being used as a purely rhetorical argument against rust?
There is a nice thread on HN on C++ memory safety, specifically those blog posts @ssokolow has mentioned.
Over the years, my observation of “bad” C++ code is that it tries to emulate other languages. Usually “Java” OOP style, or here object life cycles.
However there are other, and better ways to write C++. Actually there is always a new way to write C++.
And that is the core point. Since C++99, it kept on evolving against “recent threats”. From the engineering standpoint, it allowed upgrading existing code bases with modern features.
(It looks like I missed the ML/SML/OcaML heritage in Rust. Thanks for pointing out).
So we come back to practicality: There are existing code bases, and talent. Do you try to improve it incrementally, or replace it with a “revolution”? Revolutions happened in the past (Assembly -> C, C -> C++, C++ -> Java/C#, everything -> JavaScript).
Okay this has become one of the favorite pastime of hackers: debating which language is “the best”.
That thread btw:
https://news.ycombinator.com/item?id=26938367
Geck,
The thing is both C and C++ already have a proven track record for being dangerous and there are many safer choices. There’s decades of history here and I don’t think C’s going to get better if we give it more time. We already have enough data and I don’t think we need to keep repeating this experiment ad infinitum, New operating systems are not change the relative insecurity of C and C++ compared to other languages designed for safety, rather the crux of this disagreement seems to be over whether the language safety problem is worth solving at all.
O/T: Argh..wordpress is terrible for these longer discussions!
@Alfman
You’ve made some good points, but what does any of it have to do with Idiomatic Modern C++?
Zayn,
Sorry, it’s getting hard to keep track of everyone’s individual threads because of wordpress. I think ssokolow’s link already covers what I would say, C++ type system isn’t as thorough as rust’s safety system and rust is particularly good about making the language enforce safe code by default. Rust even helps correct faults in multithreaded code, which is notoriously difficult for humans in large projects.
I also have an issue with the industry’s reliance on C APIs (even in C++ code), which is a problem for safety as it means safety cannot be enforced across these unit boundaries. At least in rust you’d know to look at the “unsafe” code, but C++ code doesn’t advertise itself as being unsafe.
@Alfman
You’re not providing any evidence other than your opinions which appear to be incorrect.
Your initial criticism of idiomatic Modern C++ was a criticism of C, which by design lets you shoot yourself in the foot. They are not the same language, there is no “C/C++”.
I’ll address that with a question though; There are realtime control systems written in vanilla C with uptimes of decades, that carry certifications for use in applications where loss of life is a probable outcome for any defects. Would you have us rip out and replace all these systems with code written in Rust? If so, why? If not, also why?
But going back to the original topic…
Why should I choose to use Rust instead of Idiomatic Modern C++ to develop a hypothetical new Operating System from scratch?
What specifically would I gain from throwing out over three and a half decades of accumulated knowledge by using Rust for this? What exists in Rust but is missing from Modern C++ that couldn’t be added to C++2x or another future standard for instance?
You mention threading being historically troublesome. C++ only formally introduced threads into the language specification in C++11, prior to that it handled them as well as any other single threaded language; i.e. at the mercy of the OS implementation.
Yes, Rust is obviously safer in the hands of less experienced developers than C will ever be, does that mean Idiomatic Modern C++ is less safe than Rust in the hands of a seasoned engineer that has kept their skills sharp?
Engineering is hard, programming is easy. You have to keep up and keep educating yourself, best practice evolves.
Do you have experience using Idiomatic Modern C++ btw or are you making the mistake of confusing it with C with Classes? It does sound to me like that, but please correct me if that is not the case.
@Alfman
You’re not providing any evidence other than your opinions which appear to be incorrect.
Your initial criticism of idiomatic Modern C++ was a criticism of C, which by design lets you shoot yourself in the foot. They are not the same language, there is no “C/C++”.
I’ll address that with a question though; There are realtime control systems written in vanilla C with uptimes if decades, that carry certifications for use in applications where loss of life is a probable outcome for any defects. Would you have us rip out replace these systems with code written in Rust? If so, why? If not, also why?
Back to the original topic…
Why should I choose to use Rust instead Idiomatic Modern C++ to develop a hypothetical new Operating System from scratch?
What specifically would I gain from throwing out over three and a half decades of accumulated knowledge by using Rust for this? What exists in Rust but is missing from Modern C++ that couldn’t be added to C++2x or another future standard for instance?
You mention threading being historically troublesome. C++ only formally introduced threads into the language specification in C++11, prior to that it handled them as well as any other single threaded language; i.e. at the mercy of the OS implementation.
Yes, Rust is safer in the hands of less experienced developers than C will ever be, does that mean idiomatic Modern C++ is less safe than Rust in the hands of a seasoned engineer that has kept their skills sharp?
Engineering is hard, programming is easy. You have to keep up and keep educating yourself, best practice evolves.
Do you have experience using idiomatic Modern C++ btw or are you making the mistake of confusing it with C with Classes? It sounds like that to me, but please correct me if that is not the case.
—
Posted again because my first post vanished. Something to do with OSAlert not liking my VPN I think.
Zayn,
I think we are all going in cycles, and the WP thread format is not helping either
Yes, C++ is the best engineering language out there. “Best” being subjective, of course, but as pointed out many times, most of the popular software we use everyday runs on C++.
It also has issues, even with “modern” dialects, since you not only need to have code discipline, and make use of tools like static analyzers, “-Wall -Werror” and latest IDEs to be proactive, you also need to comb your codebase every now and then to prune “dangerous” stuff (things as simple as strcpy).
But as mentioned many times, Rust is probably not the language to replace it. It feels “off” for non-technical reasons. And there are technical reasons, too. As you mentioned legacy codebases are valuable. Not only that C++ is much more expressive than Rust.
Both the template meta-programming and C-style MACROS are turing complete* in C++. Nothing on earth compares in imperative languages.
* with some limits
@sukru
You don’t have -Wall -Werror on by default?
I’m genuinely interested in getting answers to my questions though. I’m not being obstinate for the sake of it.
Zayn,
The point is that both C and C++ are languages that allow the programmer to shoot themselves in the foot whereas with rust unsafe code cannot even be compiled unless it’s been explicitly declared as unsafe. Also you haven’t responded the the link that many of us referenced above covering C++ specifically:
https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/
You can choose whatever you want. But it’s not unreasonable for experienced professionals to opt for a language specifically designed for safety by default. I think many projects have fallen into the trap of “it doesn’t matter if the language is potentially dangerous because we’re going to do it right.” However after many contributions and several thousands of lines of code human errors will always begin slipping in! Errors that safer languages may have prevented. A significant number of Chrome errors would have been caught.
I know about metaprogramming with templates. Smart pointers are nice, especially in scenarios where ownership is simple in scope. But when things get more complex, say when resources need to be protected by semaphores/mutexes/etc, C++ falls apart next to rust.
Also keep in mind some of us have other gripes with C++. Header files are one of the worst carryovers from C, and C++ templates are often a pain. G++ handling of template errors can be very obtuse. Rustc’s output is much more friendly by comparison.
Can I ask you why you dislike rust? Is it only that rust does not share C++ syntax? Or is there something specific that you would point to and say “this makes rust a bad language”?
C’s broad support is partially illusory.
To quote matthieum on /r/rust:
—
I can easily pull up articles on why revolution is rarely the right answer. One of the reasons Rust is getting this level of interest is that it’s rare to see a language that’s comparably well-suited to incrementally rewriting a codebase from C to Rust, and there are also projects working on extending that to C++. (librsvg was rewritten from C to Rust more or less function-by-function while keeping it working along the way.)
Thanks. I didn’t see how it relates “specifically” to those Alex Gaynor blog posts, but it was interesting to skim through.
His argument is more along the lines of “If all the major rich vendors like Microsoft and Apple and Google can’t get the ‘percentage of CVEs due to memory-unsafety’ down from ~70% with all the tooling and training they’re throwing at it, then maybe the problem is that C and C++ only individuals can write C and C++ ‘properly’ in real-world conditions”.
In the case of Modern C++, the problem is more that “Humans aren’t good at reasoning about a program globally and, no matter how hard you try make the codebase only require local reasoning, unless the compiler mandates it, unintended dependencies are likely to slip in sooner or later.”
That’s what Alex Gaynor was pointing out. Fundamentally, Idiomatic Modern C++ still doesn’t protect you from mistakes like that slipping in.
Compiler-enforcement that can’t be added without breaking backwards-compatibility with the rest of the ecosystem and, if you’re writing in isolation, it would wind up being “Rust, but with uglier, more verbose syntax than Rust bolted onto the C++ you love”.
I don’t want to risk getting moderated again for having too many URLs, but google up “The Day The Standard Library Died” by cor3ntin for an example of how C++ is unlikely to even aim for what it *can* fix because it’s so dedicated to ABI compatibility.
…and you can
#[forbid(unsafe_code)]
on the modules you allow your less experienced developers to touch while your more experienced ones write small, well-audited wrappers that enforce safe use of yourunsafe
code.ssokolow,
Also, opinions aside, I just wanted to say I’m glad you’re here making the case for rust and safer languages in general. I respect your experience on this subject and would like to hear about what you’ve been doing with rust if you care to discuss it.
To be honest, mostly lurking in /r/rust/ and helping people.
That whole “I didn’t know ‘executive dysfunction’ was a textbook symptom of being on the autism spectrum… I didn’t even know it existed” thing has left me with a massive sleep debt so I spent most of my time since Rust hit v1.0 too tired to be motivated to do much coding.
That said, I’ve done a little bit of stuff here and there for my own use.
I have a mostly complete effort to rewrite my “use mlocate-style behaviour to index things in the less replicated tiers of my backups which might need to be retrieved from DVD+R or re-downloaded” script in Rust, where I wrote a quick hack to work around a faulty assumption in how Serde serializes pre-epoch modification times and an escaping scheme (GitHub Gist of Rust code) for storing the full range of POSIX paths in UTF-8.
(TL;DR: Because JSON is specified as successfully round-tripping nulls in strings and everything I tested except PHP and C handles that just fine, I use
\0
as an escape character for indicating that the codepoint that follows should be typecast to a raw byte, because NULL is the one character that’s valid in a JSON string but not in a POSIX path… thus ensuring that anything that would be allowed without the transformation will pass through unaltered.)I’m also working on a tool to verify several terabytes of years-old files before I move them to DVD+Rs augmented with dvdisaster ECC, with the intent to check everything that can be checked using their internal checksums. What makes it special compared to existing options I’ve seen is that I want to write a test tool (placeholder name:
corruptic8
) that looks for holes in the checksum coverage by exhaustively walking certain types of corruption (single-bit flip, two-bit flip to defeat simple parity checks, binary null, truncation, etc.) through tiny but representative test files (eg. Does this unzipping tool catch mismatches in un-CRCed fields that are duplicated between the central directory and the local file header? Let’s see.) and then generates a PNG file. (Because PNG will compress a “one bit per bit in the file” bitmask very efficiently and can also be designed so humans can get use out of viewing it directly.) Here’s a sample of the config file for the verifier.Back before I dove so deep into the sleep debt pit, I started an experiment into what can be done for game management that neither Steam nor Lutris do… mainly heuristically auto-filling entry titles from file/directory names when you just give it a folder full of games to recurse through and not all of them have GOG
gameinfo
files. Here’s a screenshot from 2017 when I was just starting to migrate the prototype heuristic code from all-Python to a PyQt frontend bound to a Rust backend using rust-cpython and here’s a parser written in Rust (GitHub Gist of Rust code) for the specific flavour of CamelCase that shows up in the test corpus. While I was writing that, I wound up writing this blog post on the semantic distinction betweenfor
andwhile
that becomes significant under Rust’s ownership paradigm, and, a little earlier, this blog post on a better as-you-type filter.(The end goal for that once I’m ready to get back to it is to produce insights and reusable code I can offer to projects like Lutris. The GUI in the screenshot is more an experimental platform.)
I’m a little behind on bringing it up to spec, but I have published a boilerplate I like to use for my Rust CLI tools. I’m most of the way through breaking out, polishing up, and preparing my local copy of
template/src/validators.rs
to become a crate of its own, providing carefully considered and documented CLI argument validators named after what you use them for, rather than what they check.At the moment, the project I’m trying to get to an initial release is a wrapper for Firejail with the placeholder name nodo (i.e. the opposite of “sudo”, not “s[uper]u[ser] do”, but “you no do”) which looks up a profile based on the command and subcommand you’ve asked it to wrap and then generates an appropriate sandboxing profile on the fly. (eg. If you
nodo cargo build
, then it’ll walk up the filesystem to findCargo.toml
and generate a sandbox to lock it into that folder and deny access to.git
to make track-covering difficult… mainly because I’ve been spooked by the supply chain attacks in the NPM world but still want to use things like the Prettier code formatter and the typescript compiler for in-browser stuff.)In case it waits in the moderation queue too long, I did write a reply for you.
ssokolow,
When you say internal checksums, are you referring the the checksums inside of zip files?
Sorry if I’m misunderstanding you… it sounds like you’re doing diffs between archives and redundant copies to identify bit errors? Where are you getting the redundant copy from?
It looks pretty cool!
This sounds similar to something I built several years ago to create adhoc sandboxes using cgroups, but then systemd broke it. But anyways it was similar to an LXC environment created dynamically without having to write and then delete configuration profiles in the file system. The environment was intended to be completely transient, persisting until the target exited and then disappearing.
I designed it to eliminate the need to declare a new user accounts and/or VMs to run software in insolation from the current user account. Also, it enabled unprivileged users to create these isolated environments without root.
BTW I also have trouble sleeping. It gets worse the less control I have over my sleep schedule, which isn’t very much these days with kids.
Alfman,
The CRCs inside Zip files, the MD5 checksum the FLAC encoder writes in to allow
flac --test
to verify bit-exact reproduction of the raw audio data which went into the encoder, etc. More generally, once I’ve got the basics set up, I want to look into submitting PRs to get test/verify/validate options checking anything where the writing process is supposed to set up a data dependency between two bytes which could be reliably used to detect if one of them has become corrupted. (Like verifying that all parens/braces/etc. are paired up, but for binary file formats.)The Zip format itself. The format calls for the vast majority of the metadata to be stored twice. Once in the “local file header” that appears before each block of compressed file data and once in the “central directory” written at the end of the archive.
Judging by Zip – How not to design a file format., it’s an ill-considered attempt to support some mix of “you can decompress a Zip file in a purely sequential/streaming fashion without needing to seek to the end and then back to the middle” and “you can add/update/delete in a purely append-only fashion by appending to the end and rewriting the central directory”.
I haven’t confirmed that archival tools consistently comply with that yet (I remember hearing somewhere that macOS doesn’t bother to keep the two copies of the HFS filesystem metadata in sync) and I anticipate I may discover at least one Zip file that has ISO9660 multisession-style deleted files (present in the file but absent from the central directory), but, in theory, it’s a good way to work around the CRC only covering the file data, not the metadata.
Huh. Yeah. In my case, I think the big difference is that Firejail is explicitly intended to be a high-level way to add sandboxing to an application installed in a non-containerized fashion whereas, from what I remember, LXC was more envisioned as being for building things like Docker or as a competitor to the OpenVZ setup I used to get my VPS through.
ssokolow,
Interesting background! The update functionality could be broken and I would never notice it. I have lots of zip files archived, but I’d be surprised if any had used zip’s update feature on them because I found it easiest just to recreate the entire zip file from a source directory every time. In any case I didn’t know the file metadata got stored twice.
Edit: Although now that I think about it, somebody using winzip could have used drag and drop to edit the zip files instead of recreating them.
Also not a programmer so my take on this is limited in scope. With that said, this is the second big Linux-related project to use Rust to improve upon an established part of the ecosystem, and I’m looking forward to seeing how it turns out. I wonder if this will end up in System76’s new (and hopefully improved) Pop!_OS release that replaces GNOME with their own Rust-based desktop.
On a somewhat related note, there has been a great drop-in replacement for glibc for many years now, called musl. It’s available with official support in Void Linux, and Alpine Linux defaults to it (and uses busybox instead of GNU coreutils as well).
I don’t think it’s fair to call MUSL a drop-in replacement for GLIBC. Void (and Alpine) have to carry quite a few patches to get things building with MUSL. Some things (virt-manager) have undefined behavior under MUSL because they rely on unofficial behavior from GLIBC that isn’t replicated in MUSL.
Plenty of interesting comments on Rust! Now here is my take:
Scala was supposed to be the replacement for Java. Many hailed how it is concise, has a better concurrency paradigm and is compatible with existing Java APIs. There were even adoption by big projects (Apache Spark) and companies (Twitter). It even had usable tooling support. But eventually, the hype died down and the many features of the language that was hailed as “modern” Java, in itself became the bane of using it. Scala felt more like an ecosystem by itself that just rode on the JVM. It made simple tasks into complete brain teasers. Eventually organizations that went all into Scala, found out that it was not as productive as their previous investments were and tooling options left a lot to be desired. Now, it could be argued that it is after all a new language and time would be required to reach the maturity of Java, the undeniable fact was that it wasn’t an easy language to pick up and use. Where Scala failed, Kotlin succeeded in far shorter time. It had a gradual and smooth learning curve and great tooling. No surprise that it has been picked by Google as the primary language to be used for Android app development.
I see a repeat of this with Rust. You shouldn’t need to be an uber Emacs leet haxor to get simple things like code hints, autocomplete, contextual documentation, etc. Rust has very poor tooling support, in my honest opinion. You can’t easily get any of the modern editing features that you could get in even something as obscure as F#, for example. Needless to say, same situation with modern tooling for debugging your Rust code.
One of the reasons .Net and Java rose to prominence, is the standard framework and tooling. It was easy to pick up, learn and use it. There were clear coding guidelines and solutions to get you started on the right path to using it. Need an API to hash a string? It is right there in the standard framework with examples on how to use it correctly. Over the years, plenty of 3rd party tools have emerged, even for things like code quality/maintainability and secure code analysis. While you may argue that Rust is a safe language and by default forces you to write secure code, how do you ensure that an IV is generated and used correctly with an encryption cipher? In these modern times, code quality and security is a must in any major organization, which also incudes the proper and safe use of APIs, not just memory safety. Which then takes me to my next question, are there any opensource/commercially available frameworks from a large community/vendor with extended support? While there are plenty of crates to go around, to cover specific niches and use cases, I am doubtful of the reliability and quality of the code. While similar could be argued about commercial solutions, there isn’t even an option here to pick a good one. The recent Log4J issues are a legitimate cause for concern, what about solutions that aren’t sufficiently backed with developer support? Rust, unlike languages that are built on top of ecosystems like .Net or Java, does not have a mature platform it could rely on.
I took a look and found out there do seem to be some underlying issues involved. In regards to mixing C and Rust. Like different (object) lifecycle management can cause issues and in general the mentality involved is not something to take lightly. That is an average Rust developer sees C as unsafe and often finds it difficult to use C. Like for example embedding a C library. As in their eyes C defeats the main purpose on why Rust was selected for them in the first place. Not sure if this can scale good.
Geck,
You can mix rust and C as well as any two languages that share a calling convention just like you can with any other languages, but you obviously loose the safety benefits of rust in doing so.
Well, even C developers like myself have long considered C to be unsafe long before Rust came along. I don’t think C is particularly difficult to use. The motivation behind developing rust and other types of memory managed languages comes from the goal of eliminating instances of human error when it’s provably wrong.
To be fair, such problems aren’t limited to C, we focus on C mainly because it is the most prevalent language for software development and so any solutions have to recognize the need to be compatible with it in some way. This isn’t unique to Rust, just about every low level programming language has to be compatible with C in order to be usable. Even in C++ projects there tends to be a very heavy reliance on C APIs since that’s the defacto standard. This has consequences, like the lack of name spaces strategies and the lack of reflection, etc. that modern languages can bring.
Indeed if you choose Rust you likely do that because of some features it provides. Such as memory safety. And if you then go and create some application. Nothing wrong with that. If your mission is to make it a second programing language for Linux. Then in my opinion and based on my research you are likely overreaching. If you want Rust in this area you will likely need to start from scratch and do it in Rust altogether. One real life example: https://timidger.github.io/way-cooler/2019-04-29-rewriting-way-cooler-in-c/