Some of the survey responses highlight one of the biggest hurdles to rust adoption I've experienced though:
Rust has an education problem. People dramatically overestimate the correctness of their [C/C++] code and underestimate the potential severity of failures to meet that expectation. I've found very few projects where a bit of poking can't turn up memory safety issues. Even people who are far more skilled programmers than I am routinely write silly mistakes.
Unfortunately the response I often hear to bringing these issues up after the code exists is "it's working code, why should I care about these theoretical issues?"
I expect the careless unaware culture to get worse with time as more and more aware people manage to leave it.
Or the ones writing code where security doesn't matter, like HFT and video games (the former have no users, and the latter are basically impossible to make crack-resistant even if they're written entirely in Rust).
Genuinely interested: what do people think of their tons of third-party dependencies in Rust? My experience building Rust projects is that there are orders of magnitudes more dependencies than what would make me comfortable. At least in C/C++ it's much harder to get there.
Of course, dependency-reliance falls on a spectrum for any individual programmer. On the one hand you have script kiddies with 400 npm dependencies gathered from arcane Discord channels - on the other you have old bearded wizards who don't understand why you'd need printf() when you can just mov rax 1; syscall.
I find Rust is not strongly opinionated about this. You can just as easily eschew dependencies as use them. There's usually a good array of options available, or you could always FFI to a C lib directly if you need to.
Here are three things I think, and they have in fact nothing to do with Rust:
1. The easier it is to add dependencies, the more dependencies will be added on average - unless you work purposefully against that.
2. The effect of a rising average number of dependencies in libraries is that their number of dependencies grows as well, and the number of their dependencies' dependencies... up to dependency graphs of several hundred nodes size. Like in exponential growth. An example would be the dependency graph of jquery.
3. I observe this "exponential" growth can have chain-reaction-like effects, like if you have a mass of U235 that achieves critical mass. Below that critical value, some neutrons flying around might trigger a few fissions, but these die out. Above that value, neutrons lead to fissions which lead to more neutrons and so on. The same can happen with complexity in multi-component software. At some point, complexity goes through the roof.
And the latter is especially true if backwards compatibility is not strictly observed, since backwards-incompatible changes tend to be infectuous in that they often make their client components (parents in the dependency graph) backwards-incompatible as well, in other words, there is breakage that propagates up the dependency graph. That breakage might die out and be able to be contained by local fixes, or it might propagate. And once your dependency graph becomes large enough, it is almost guaranteed, that you have breakage.
All these things together is why I believe that systems like NixOS or Guix are the future (but of course there might be other developments in that space).
Interesting take. Poor package management as a security feature.
As others have pointed out, instead of potentially poorly written third-party dependencies C/C++ will just have potentially poorly written homebrew replacements.
That’s more than can be said about hand rolled equivalents in C/C++.
Really depends on the field. I heard more than once in my life now that it's better to reboot every night than spend even an afternoon of engineering trying to fix memory leaks.
It's not great when you have problems like use after free and pointers going to where they don't belong. Those can cause security vulnerabilities that rebooting won't fix.
I'm working on a Rust project right now, and I'm probably one of those people who are overestimating the correctness of my code! I would love to know about what sorts of memory safety issues you often uncover.
There are five orders of magnitude more pwned boxes due to misquoted strings then there are due to memory safety issues.
You are searching for a problem that could potentially make Rust useful instead of solving a real existing problem that people actually have.
I'm not sure where your data comes from, but memory safety issues are roughly 50% of all exploitable security vulnerabilities.
They were also about 50% of all crashes of android apps (null pointer exceptions)
For professional embedded programmers, faith in silver bullets disappears with the growth of professionalism.
So let's say I happen to work with a MCU that is well supported in Rust, what if I want to connect it to a popular OLED display? Is there a library for that? If so, does it work? If it works, does it have the needed features? Now maybe I am incredibly lucky and all of that works, what about a popular gyro IC?
Granted, there is probably some way to interface the Rust code with C code, but is that gonna work without turning it into a day of research?
I will certainly check back on the state of Rust on embedded every now and then, but as of now C++ is my goto.
Other than Arduino, which of course has pretty good support for many devices and is likely to work out of the box.
I run an electronics workshop at an artschool, so the end result counts and how we get there is more or less arbitrary unless it happens in a finite timeframe. For my own private projects I tried Rust, but also there my goal is to get things done, not to fool around forever. I like fooling around with the interesting bits, not with rewriting a thing others have written before.
#1: You benefit from the nice tooling and language of rust #2: You are forced to learn how to use peripherals at a lower level than would otherwise be required. You will become adept at reading datasheets, and interacting with hardware, because you will write to registers directly while building your own abstractions.
The easy choice is to use C or C++.
At least for the ssd1306 and the sh1106 there is in fact a library for it that works well.
I recently started working on a rust-esp32 project because I'm far too lazy to properly deal with json in C. It was basic, some buttons, a display, an encoder, and a web api but it was a breeze. I'd really like to continue on more complex projects in the future. I've somehow avoided writing C++ in an embedded setting and now I'm afraid I might have to go back and learn that rather than continue with Rust.
The semantics as you cross the boundary are ill-defined. And you will pay dearly if the C library wants to own any of the resources (like an event loop).
And "unsafe" programming in Rust is really difficult to get right--possibly harder than C.
To be fair, these problems are not inherent to Rust--any language which tries to interface with C will have them.
I had a sense this a priority for the Rust Central Committee, so I had a quick look
https://docs.rust-embedded.org/book/interoperability/c-with-...
I have not had to use it yet, looking for a reason.
Maybe the mindset of the industry as well?
Not sure if things have changed (and if so, how) but 9-10 years ago when i was in university I had an interview with a company that did embedded systems stuff. While talking about my competencies I mentioned I was able to create cross-toolchain if they were interested and the guy (he was kinda like the CTO iirc) abruptly interrupted me and just said:
"no. just no. we always and only use the vendor's BSP (board support package). we don't care about anything else. should there be any kind of issue we want to be able to ring them and get them to fix the issue.".
How do you get people (or an industry?) with such a mindset to just use something because it's trendy?
My guess is that industry will wait another 10-15 years until some vendor big enough ships a rust toolchain as a BSP. Other vendors will follow. Then Rust on embedded systems will flourish.
You need to be in the right kind of company - the one where waiting for the external vendor to fix their shit is too slow.
What? Are there really people out there relying on libraries for every peripheral? I've never seen anyone use a third party library for peripherals like that, short of some prototyping on an Arduino or the like. It's always just drivers implemented from scratch.
1. https://arewertosyet.com/ to track rust RTOSes and their status
2. there are tools to convert c to rust (I dont know if I'd trust this..)
3. "Out of 43 different MCU families, peripheral crates are currently available for only 16 (37%). Most of these crates are generated using svd2rust utility"
4. developers considered but rejected rust because: "Lack of Support for MCUs (36%) ; Difficulty Integrating with Existing codebase (32%) ; Organization constraints and certification requirements (30%)"
5. "The second major (26%) issue is debugging, which is expected because, as explained in Section 2, embedded systems follow an asynchronous and event-driven design. This results in frequent cross-language domain interactions and makes debugging hard."
I would adopt rust if it were easy to get up and running just while(1) loop applications.
The core C specification by itself isn't all that complicated of a language; a C-to-Rust transpiler is a pretty doable project.
The main issues here are that
a) a lot of the code you'd likely want to convert is likely to be reliant on non-standard extensions
b) there's a lot of undefined behavior which you probably want to have somewhat more defined behavior on, especially in embedded contexts
c) the real goal for a lot of this automated conversion is to do the conversion once and work well enough that you don't have to audit the result of the conversion, and because of especially the previous point, it's really hard to get that level of trust for C code.
The existing c2rust converter works by creating the clang AST and then lowering that to Rust source code, which I'm not sure is a path that would lead me to high confidence in the converted code due to the potential impedance mismatch in understanding the clang AST. A custom C frontend is probably a better match here for a long term project (C, unlike C++, is feasible to build your own compiler from scratch), or maybe another project idea is to convert LLVM IR to Rust and ditch the C frontend entirely.
It's been done, but what comes out is terrible Rust. Everything is unsafe types with C semantics.
An intelligent C to Rust translator would be a big win. You'd need to annotate the input C with info about how long arrays are and such, to guide the translator. It might be possible to use an LLM to analyze the code and provide annotations. Usually, C code does have array length info; it's just not in a form that the language ties to the array itself. If you see
char* buf = malloc(len);
the programmer knows that "buf" has length "len", but the programmer does not. Something needs to annotate "buf" with that info so that the translator knows it. Then the translator can generate Rust: let mut buf = vec![0;len];
The payoff comes at calls. C code: int write_to_device(char* buf, size_t len)
is a common idiom. LLMs are good at idioms. At this point, one can guess that this
is equivalent to fn write_to_device(buf: &[u8]) -> i32
in Rust. Then the translator has to track "len" to make sure that assert_eq!(buf.len(), len);
is either provably true, or put in that assert to check it at run time.
So that's a path to translation into safe Rust.Funding could probably be obtained from Homeland Security for this, given the new White House level interest in safe languages and the headaches being caused by the cyber war. Is CVS still down?
If the library in question handles interrupts by jumping to an interrupt handler that updates some shared state you're going to have a bad time converting that into safe Rust.
There are a lot of obscure MCU families out there. Most engineers or shops specialize in a couple, become familiar with those, and stick to it. Using and learning a brand new MCU family is a lot of work.
As long as I can find Rust support for common MCUs that I use, I don’t care how broadly the rest of the market is covered.
(in fact, while I like the theory of generic embedded HALs, I have yet to see a good implementation of the concept. Most effective HALs I have seen are specialised to one area or another, usually to one particular application)
Doesn't embassy_rs make that pretty easy?
reading the readme gets me pretty excited tho
As an aside, does anyone know if there is a central directory of these Rust "areweXyet" websites? I didn't know of this one but I knew about https://areweideyet.com/ and https://areweguiyet.com/
It is: Install the toolchain (eg `rustup target add thumbv7hibf`); install probe-rs; `cargo run`. I think getting applications up and running in embedded rust is one of its strengths.
Out of Bounds Reads => 18.6%;
Out of Bounds Writes => 62.7%;
Null-Ptr Deref => 8.5%;
Use-After-Free => 5.1%;
Type Confusion, Uninitialized Pointer Access, Memory Leak => EACH 1.5%;
I have to wonder about the applicability of these percentages to non-RTOS programming. I find it very interesting that 81% of CVE's are allocated to Out-of-Bound Read/Writes, with writes being the larges percent of those obviously.
Has there been any CVE cause analysis performed and publicly available? If so and the percentages bear out similarly to RTOS's across a spectrum of application/system types then there may be some clear cost/benefit analysis needed at the programming language design stage. Rust is a complex language with a complex type and lifetime system to achieve memory safety, and it is not an uncommon refrain that a simpler 'safe' language would be appreciated by many developers. If 80% of CVE's come from Read/Write errors on array access, then a language that enforces strict memory access semantics, but forgoes the rest of Rust's complexity regarding lifetimes and type system complexity would achieve a very large portion of exploit prevention at a minimal cost.
Additionally, if you prevent Null types in the type system the language would then prevent 90% of CVE causes, again with a minimal amount of complexity.
I'm not certain that the above is correct, if the percentages play out in the large, or that devs would actively switch to a considerably safer, while being simpler language. But it certainly is thought provoking.
C has some bad things it does by default that lead to terrible bugs. I imagine many of them can be addressed without complex move semantics added to it.
Some promising work I've seen in this area had been the adoption of language level allocators in zig and Odin. Many newer languages also have better arrays come with length information. And array languages like APL avoid out of bounds errors.
I don't think you have to go full ML style type checker (or borrow checker) to prevent bugs.
However, there's generally a strong pushback from C developers against features that have an unnecessary performance overhead.
Having reliable bounds checking without run-time cost if a much more complicated problem. Rust uses iterators for this, but that requires generics and specialization, and compared to C, these are big and complex features.
My comment was more for consideration in the design of new languages, in particular, the development of the frequently cited as not existing, simple, C-like language with memory safety features. In that case, in a green field scenario, there are a few ways to achieve statically known memory-boundary respecting iteration and general access. Further, there are several existing methods of achieving 'generics'. The real design challenge would be in finding the simplest implementation that does not overly burden potential developers.
I am confident that it could be done, but it would take some grave dissatisfaction with Rust (which is currently at the top of the adoption curve in the memory safe, but GC free space) for the proposed language to take off.
Out of Bounds Reads => 10.1%;
Out of Bounds Writes => 34%;
Null-Ptr Deref => 4.6%;
Type Confusion => 0.9%
Uninitialized Pointer Access => 0.9%
Use-After-Free => 2.8%;
Memory Leaks => 0.9%;
The most staggering statistic is the out of bounds writes. C23 added variably-modified types which helps [1], but I hope future revisions of C consider adding slices. I quite like Zig slices where a "slice" can be constructed from any pointer+length pair.
[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2778.pdf
Seems possible to me, although a bit labor intensive depending on the C/C++ lib — https://docs.rust-embedded.org/book/interoperability/c-with-...
Do the Python SDKs run fast enough? Genuine question. I've done a good amount of Python, but don't have any idea of how suitable it is for embedded stuff, other than knowing that MicroPython exists.
A lot of parts I had to work with didn’t have it, last one a couple months ago for example was a guided parachute for a drone dropper, I ended up making the driver from scratch that interfaced with the serial io.
Til then, no way to switch.
Rust is there on the embedded, the only thing missing is people realising it's there.
The paper could use a few minor corrections and improvements. For example, they go through thousands of crates in crates.io to give the impression of completeness, but it would have been better to go though a more curated source like https://github.com/rust-embedded/awesome-embedded-rust. It doesn't matter if the quality of random one off crates that someone hacked over a weekend is poor, it does matter if the crates recommended by the community are poor. But I suppose their analysis would look impressive then.
The other nit is that they think that the existence of even one instance of unsafe is a problem. This is a mistake that people unfamiliar with Rust make.
I don't think I would be able to approach it on an ESP32 or AVR xMega or some other real microcontroller.
I'm sure "sorry for getting everyone to switch to this unestablished language" will go over very well with your boss and upper management. At least in C and C++ you can blame your tools.
If you've stupidly convinced management the existing tooling is shit, then you've got a problem. And I don't mean a technical one, I mean a problem with paying rent, because you're not going to be employed much longer.
For low level, hard realtime control and interrupt handling rust gets in the way. Many embedded applications stop here. For things like parsing, protocol stacks and business logic rust has a clear advantage. Interoperability with C is therefore essential. The current situation is good for ARM and RISC (ESP32) but impossible for weirder stuff like C28x. (See my demo here: https://github.com/driftregion/bazel-c-rust-x86_linux-armv7_... )
I used it for a custom board I made and it not only consumed less power overall due to the automatic chip sleep state handling but has been drastically easier to work with than the provided C firmware.
Developer is also super responsive on Matrix and a nice guy.
And why is the std_library less performant than, let's say, C's counterpart?