Hacker News new | ask | show | jobs
by TheMagicHorsey 3662 days ago
Is there any reason why embedded software for autonomous vehicles is still being written in C/C++? This last week I was talking to a friend at a company that makes a small autonomous vehicle. During testing their prototype suddenly went off in a straight line. They had to pull a safety to halt the vehicle or it would have gone straight forever into the Pacific Ocean. Turns out there was an unsafe access to a variable in memory, which had not been caught with their software and hardware test platform, even with thousands of virtual sorties.

If their code was written in Rust, that sort of bug could not have occurred.

10 comments

> any reason why embedded software for autonomous vehicles is still being written in C/C++

Nearing a half-century of momentum in the community which includes developers, mature tools, etc. Until rust arrived it was nearly the only game in town for predictable low-latency systems programming.

Yes, now that Rust's here there's a bit of an alternative. But if you've got a team of 30+ software devs who know C/C++ and an existing well-tested codebase of millions of lines, even if you had multiple Rust champions it would take a very long time to evolve towards Rust.

A more productive line of questioning, rather than prodding them to convert their probably-quite-substantial codebase into a language that, with all due respect to the Rust team, is probably still a wee bit cutting edge to be putting in self-driving cars, is to ask them what static analysis tools they've been using and why their static-analysis tool missed this one.

If the answer is "no static analysis tool", there's your problem.

But as my first paragraph implied, they can't catch everything, so "we installed many layers of protection and it still got through even so" is definitely a possibility. Rust may have a different set of such issues but they will of course always exist.

No, there's no reason, as it could have been written in Ada and gotten many of the same safety guarantees as Rust provides.
Given Ada's history in safety critical systems (avionics), it's actually somewhat surprising more didn't use Ada. They could have just adopted the military standard (which is fairly stringent, as I understand it). The military is pretty adverse to losing billion dollar pieces of equipment, so they probably take quite a few precautions.
Didn't most of the military-industrial complex drop Ada in favor of C or C++ as soon as the DoD dropped the requirement that critical software must be done in Ada?

AFAIU the JSF software is done in C++, there is (or at least used to be) some JSF coding guidelines document on Bjarne Stroustrups web page. Of course, blaming C++ for the JSF boondoggle is unfair, but still, one wonders whether it was wise of the DoD to allow C/C++...

You got me as to why this is. Dude, I tried back in the day - Ada, MODULA, all those.

Maybe the "badass 'C' hax0r" meme was stronger than I realized. But I think a lot of it was just switching cost.

To be fair, Ada has a lot of library cruft for dynamically sized structures that you don't have to deal with in C. It can be pretty annoying.
There's two reasons Rust might not be ready here yet. First, while LLVM supports a wide number of platforms, some embedded devices literally only support the exact version of the C compiler they ship to you, sometimes, it's even got its own custom patches. Second, we sort of assume 32 bits at the lowest, though we have a patch in the queue that starts some work on 8/16 bit support. This means some tiny micros are out of reach at the moment.
> we have a patch in the queue

If you mean this one[1], it's merged. Still lots of work to do, and even more corners where things will shake out[2], but there's definitely progress.

[1]: https://github.com/rust-lang/rust/pull/33460 [2]: https://github.com/rust-lang/rust/pull/34174

Ah nice! I was unsure if the first had gotten through bors yet or not, and I was pretty sure the second one hadn't.
A rust -> C compiler would be really nice for those custom/slow updating environments, but I can understand if that just too much of a distraction.
Since I got two replies with basically the same thing at the same time, I'll pick one at random and it'll serve as a reply to both. You won the coin flip :)

This is feasible in a sense, but C is a fairly tricky target to compile to: you have to make sure that you don't accidentally include UB in the code you generate. I know pcwalton has lots of feels here...

The easiest way to do it would be if LLVM had a C backend; I know that it did, but it was removed a few years back, and I haven't heard anything about it coming back into tree yet. MIR might also in theory enable new backends, but then you'd have to re-implement all of the optimizations that we currently rely on LLVM supplying.

> I know that it did, but it was removed a few years back, and I haven't heard anything about it coming back into tree yet.

(out-of-tree) fork(s) have been kept alive by several groups. The most current one I'm aware of is: https://github.com/JuliaComputing/llvm-cbe

I'll just say - I've generated A Great Deal of 'C' code. It's not hard to avoid UB at all. You only use a very concise subset of the language. YMMV.

This sounds more like generating 'C' is a distraction rather than a goal.

It is certainly not impossible. I think it's just presented as a bit more trivial than it is. You can generate C, but is it easy to generate good C? That's what I was trying to get at with the LLVM comments. Rust relies a lot on a good optimizer; a straightforward transformation might be significantly slower.
Agreed. I did not mean to minimize the effort involved.
Is there any possibility of compiling Rust into C and then use that particular C compiler that works for the processor in question?
Industry standards, certified compilers and cargo cult are usually the main reasons.
This is the main reason. Also legacy. I work on a lot of embedded code for $AUTO_MANUFACTOR some of our code bases go back to the 90's.

The code base is so modified by macros/typedefs its hardly even C anymore.

Not to mention the LLVM has to support the embedded device you are targeting. And Rust's support of legacy CPU's (8008, 8080, 80386, 68000) are lacking.

Oh, god the macros! I also work in the auto industry and the macros are frigging everywhere and makes navigating the source a nightmare.
I would sum it up in a similar fashion. Another point that should be taken into consideration is that the industry is not really interested in software, and therefore most stuff will be done as it was always done. And now that everything should be based on Autosar (a standardized C-based OS and Giga-framework specification) chances are even lower that anybody looks at saner alternatives.

Rust won't change anything about this, if there would have been interest in changing the situation other alternatives like Ada would have been available for years.

But presumably some sort of bug would have. Broken is broken. If Rust correctly deduces the intent leading to the bad dereference, then it's REALLY GOOD! :)

( no snark; I hope you get my point )

Ironically, reliability is actually a value of merit with 'C'/C++ - in cases. It's just that the ways of doing that seem rather inaccessible these days, or the flow of people past seeing them is not working out.

I don't think there will ever be a way around developing proper test vectors. It's quite interesting work but it tends to go unrewarded.

As a C++ developer for 13 years I got to say that language just makes screwing up so much easier. The last year I've been coding Swift and man it is so much easier to avoid so many pitfalls in C++. I could write page upon page about all the problems with C++ and how those problems don't exist in modern languages like Swift and Rust.

Programming languages isn't just fashion, we invent them because we thing we can solve old problems in better ways.

Most of my co-workes doing C++ never even wanted to look at the alternatives. Being the only thing they have ever done, they don't even realize how bad it is. They have just internalized it.

You'll get no argument from me. That RAII exists at all is the best evidence ever ( even though I've used a variation on RAII in assembly in the past ).

The interesting question is - are there actually fewer defects, objectively, or are they simply rendered .. something like latent?

One I fixed in... April - if the file system on an SD card was scrogged, writing to the file system crashes the box. So I moved the write of a configuration file from the event of a switch change ( because if the switch was never put in that position, then there was no reason to ever do that ) to the top of the program so it'd crash when you powered up.

It helps me personally to think that defects are just something I've chosen to do despite my best effort. Keeps me on my toes. I certainly understand people being fatigued by that.

I would guess maturity of the wider ecosystem around the language. Not necessarily the language itself or the immediate tooling & toolchain, but the whole stack of sensor support, hardware support, mature algorithm implementations, etc. Rust is maturing quickly but it would take a long time (years/decades!) to expand out to all the niches which have been built around C/C++ even if it were an absolutely perfect replacement.
There are standards (MISRA C) which are supposed to stop things like that happening. Perhaps they weren't being followed?

There are other safe languages they could have used which have a longer track record than Rust, e.g. Ada. It's used in avionics. Why shouldn't it being used here?

While a decent guideline, MISRA does not guarantee correctitude. There are many ways you can twist code that MISRA will not complain but the code will be wholly broken.

I do not know what kind of unsafe memory access happened in their systems, but you can do all sorts of memory opperations and as long as the explicit typecasts are a-ok misra won't flinch.

Totally agree, you can write software thats perfectly MISRA compliant and still contains lots of different bugs.
Truth be told, the question here is: "Is the class of errors that is prevented by Rust natively also prevented by MISRA?"

My take is that while there is some overlap, MISRA is unable to guarantee anything, while Rust is able to guarantee certain things that C can't. (that's from my limited understanding of Rust, I haven't futzed with it yet)

I don't think C (or C++) should be used for autonomous vehicles at all, as it is known to be unsafe, but if it is, the MISRA C guidelines or something similar should be used to help prevent certain kinds of bugs.

Almost any other statically typed language, along with similarly strict guidelines, would be preferable to C, but there is no ideal language. Rust still allows dynamic heap memory allocation and recursive functions. It is also new. Ada has been used for decades.

MISRA is already used extensively in the auto industry. But i guess what I was trying to say is that while it helps, it can easily be tricked while a compiler designed with the safety measures MISRA promotes already baked into it will not let you do certain things.
MISRA is okay. It's not a panacea.
Wiki says it is proprietary..
Yeah, although the principles/rules are in quite public places. It's rather like the ITU standards in that regard - you pay for the documents.

Applying them feels like buying indulgences. :)

A bunch, including:

1. Most of those platforms don't have compilers for any languages other than C(++). If the platform has a lot of history behind it, maybe you could write it in Ada, but that's pretty much it.

2. Development tools (debuggers, static analyzers, standards compliance verification tools and so on) for C and C++ are very hard to match, both in strength and in sheer availability. In the meantime, Rust still relatively recently got decent GDB support.

3. A lot of Rust's features simply aren't needed when writing this kind of software (e.g. the breadth of features related to memory management is largely unneeded because everything is statically allocated).

4. For better or for worse, C is well-understood (C++ is... well, not that I haven't seen good safety-critical code written in C++, but in my experience, C++ code is a lot easier to get wrong, both by humans and compilers). Rust isn't, not yet in any case. There's no Rust equivalent for e.g. MISRA, and not because Rust doesn't need one.

5. To, uh, put it bluntly -- C and C++ are very well known in the far corners of the world where a lot of this software is outsourced. Rust -- not so much, because outsourcing companies don't really encourage their employees to learn this kind of stuff.

6. There's a lot of commercial risk involved. I'm not sure about autonomous vehicles, this is probably a more volatile field, but many safety-critical systems have to be maintained for a very long time (10 years is fairly common, and 15-20 isn't unheard of). Rust may well be dead and burried ten years from now, whereas language enthusiasts have been singing requiems to C (on roughly the same tune as Rust, no less) for almost thirty years now.

Rust is a great development in this field and I can't wait for the day when we'll finally put C (and especially frickin C++, Jesus, who writes that!) to sleep, but it's at least five years away from the point where I'd even half-heartedly consider it for a project with critical safety requirements.

> If their code was written in Rust, that sort of bug could not have occurred.

I don't know the specifics of the bugs you mentioned, so I can't really comment on this, but in my experience, most of the similar claims that float around the Interwebs are somewhat exaggerated when put in their proper context. E.g. Heartbleed, which wasn't because C something something PDP-11, but because someone decided to be smart about it and implement their own (buggy) memory management system so as to make the damn thing run decently on twenty year-old operating systems.

I've seen people write that kind of code, for similar reasons, in Java and Go -- and, at least once, with Heartbleed-like results. The ways in which a language can be misused rarely reveal themselves before that language breaks out of its devoted community.

To be clear on it though -- I think Rust is a step in the right direction, and one that we should have taken a long, long time ago. If it can make it through its infancy, and if it can get enough commercial support, it will be a great alternative to C and C++.

> A lot of Rust's features simply aren't needed when writing this kind of software (e.g. the breadth of features related to memory management is largely unneeded because everything is statically allocated).

True, but I don't think that Rust's other features wouldn't be useful here. References which know about mutability/immutability, sum/enum types, "fat" pointers/slices w/ bounds checking, the ability to construct library APIs which enforce non-memory safety through session/affine/linear types, sane integer typing, etc, could all still be useful to a fully-statically-allocated program.

> static analyzers

Rust doesn't exactly need these, no? Most static analysis in C/++ is safety/UB focused. Rust doesn't need this, unless you're going to spend a lot of time with `unsafe` code.

Rust does have clippy, a lint library with >150 lints which catch things ranging from correctness to style to safety issues. I'm one of the maintainers, so I'm biased, but I've personally found it to be much better than its equivalents in C++land. Perhaps not Javaland.

Static analyzers are good for a lot more than just finding potentially unsafe memory access. In fact, memory access bugs are typically just the low-hanging fruits that static analyzers find (and which, most of the time, you can find by code review, assuming your team consists of more than two developers and that they actually get some sleep every once in a while).

It's issues related to timing constraints, incomplete branches, common but subtle mistakes (e.g. in C, suspicious memory allocations, like malloc-ing strlen(x) instead of strlen(x) + 1 bytes) and so on. E.g. http://www.viva64.com/en/examples/ . Many of these are, indeed, because unsafe memory access allowed without restriction, but they're fewer than one might expect. Most of them are either language warts which no language is devoid of, no matter what its fans would say) or programming blunders that occur because our brains work the way they do.

I know they are, I'm saying that the main attraction is memory access stuff (at least, for me it was when I used to use them).

For the rest, Rust does have static analysis tooling of the kind you describe in the form of clippy. There's still a lot that can be done, but it's already quite helpful and catches all kinds of things.

> I know they are, I'm saying that the main attraction is memory access stuff (at least, for me it was when I used to use them).

It depends on what you're working on. In the context of the original question of the thread (i.e. autonomous vehicles), I'd consider memory access to be the least difficult thing that static analysis can help me with. With code review, careful structuring of your data and, if it's available, hardware support for memory access models (e.g. ring buffers), memory access bugs can be reasonably avoided even without code analysis tools (not that it should!). Things like timing analysis are a lot harder to do without proper tools.

> For the rest, Rust does have static analysis tooling of the kind you describe in the form of clippy. There's still a lot that can be done, but it's already quite helpful and catches all kinds of things.

I would, uh, rather not be put in a situation where I have to send documentation to an approval body, and have the documentation mention -- as the only static analysis tool that was used -- a community project that's at version 0.0.75.

For comparison, there was a thread around here a while ago, where I think Gerald Holzmann from JPL mentioned how they used several (something like the top 5) code analysis tools to check their code. A top of all available static analysis tools for Rust would be a lot shorter than that.

This kind of stuff is important for mission-critical applications. I like Rust and I think it's a step in the right direction (and would certainly love to see it go all the way in that direction!) but I'm not about to write code that could kill people in a language whose only viable compiler barely reached 1.0, barely has a working debugger and only lint-level static analysis. It's the right track, but we're not there yet.

Edit: oh -- and I would like to point out one thing that seems to be often lost in the HN bandwagon. If you look at the numbers, it turns out that programmers have been able to get C and C++ to perform reliably for quite some time now. Failures are high-profile, but by and large, the medical, space and automotive industries have been doing a pretty good job at delivering safe tools, considering how many cardiac pumps, cars, airplanes and spaces probes are around and how few of them fail. It goes without saying that we should aspire for better, but the status quo is really hard to beat.

> I would, uh, rather not be put in a situation where I have to send documentation to an approval body, and have the documentation mention -- as the only static analysis tool that was used -- a community project that's at version 0.0.75.

Heh. Yeah, clippy has a lot more to do, and it's not a product with official support, but so far it's been pretty useful :) The version number is just because I want to have an rfc about it before I release a 1.0.

But yeah, it's nowhere near the level of lint tooling C++ has. For most people, I believe it might be sufficient, but for mission-critical stuff I'm not so sure -- you're probably right. Though Rust's type system also might help in creating safety guarantees (non memory safety) for mission critical things.

> only lint-level static analysis

what do you mean? Clippy calls itself a linter because it uses the lint API, but it does all kinds of static analysis. The meaning of "lint" in the Rust community is slightly overloaded.

> if you look at the numbers, it turns out that programmers have been able to get C and C++ to perform reliably for quite some time now.

Of course :)

Rust is not stable. The language is not battle tested like C/C++.
I will certainly concede the second, but we put a _lot_ of effort into ensuring that Rust is stable. Things have changed a lot since the pre-1.0 days.
> Things have changed a lot since the pre-1.0 days.

The instability of the pre-1.0 days left a very bad impression on many people who tried Rust then. They came to know Rust as a compile-today-but-not-tomorrow kind of language. What, if anything, is being done to try to inform these people that the situation has changed, to encourage them to try Rust again? What's being done to restore Rust's reputation?

> What, if anything, is being done to try to inform these people that the situation has changed, to encourage them to try Rust again? What's being done to restore Rust's reputation?

A lot? For example, "Stability as a Deliverable", which was here on HN: http://blog.rust-lang.org/2014/10/30/Stability.html

I'm not sorry for opening up the language during its early development. The alternatives would have been to produce a deeply flawed language or to keep the language secret. Both of these are far worse than a few ignorant comments.

There are still plenty of crates that say "you need to be using nightly!".

That put me off starting to develop something in Rust right now, unfortunately, because I'm a huge fan of the way Rust was developed and its core ideals.

We can't force people to use the stable version of Rust. But it does exist. And we're working on bringing the most popular nightly features to stable as soon as possible.

In any case, even if you're using nightly your code won't break nearly as much as it did pre-1.0. We use nightly in Servo and we've been through dozens of Rust upgrades that sailed through without a hitch--and we have 150+ dependencies.

That's more about encouraging crate developers to make their package work on stable. There are crates that are made to take advantage of nightly features, but I believe many of those label them as "beta", "unstable", "only works in nightly".
If somebody uses a piece of software or language that is pre-1.0 with "Beta" and "unstable" written all over it and then they get mad when it changes, that is purely their fault.

The programming community of people who actually write real things and create production software, I highly doubt any of those people are the people you are referring to and thus Rust should be doing nothing to restore its reputation with those people, as they are ignorant and/or highly incompetent, and I hope they never write a piece of code that makes it into production.

Well before 1.0 itself, we were already trying to telegraph our intentions here. October 2014! http://blog.rust-lang.org/2014/10/30/Stability.html

We try to be fairly vocal about the things we're doing here, but of course, it can be tough to get the word out. While some people may not know things have changed, a lot of people also do.

Some examples of things we do to ensure stability:

* The RFC process requires lots of discussion before major change happens, to ensure we can do things in a compatible way.

* We run a tool, "crater", both on PRs that we are worried might cause issues, and just in general. This tool compiles all of the open source Rust code on crates.io with the new revision, and reports problems. It's not perfect, but it helps a lot.

* For that matter, we don't merge any code ourselves; bors manages a fleet of 30ish machines that test every commit with our full test suite.

* We recently added three significant crates (and their dependencies, which last I checked was around 80ish crates in total?) to be part of our test suite, so we know that they build properly on every commit.

> What, if anything, is being done to try to inform these people that the situation has changed, to encourage them to try Rust again?

Releasing something called 1.0.

The Rust project has been vocal about its stability guarantees; all that's left is to correct people when they claim the language isn't stable.

http://blog.rust-lang.org/2014/10/30/Stability.html

EDIT: As you can see from the number of responses you got, this matters a lot to the Rust community :-)

If anything we have better stability guarantees, we actually run the beta against the entire ecosystem before releasing.

Rust has been _extremely_ vocal about its stability guarantees. Not sure what else can be done here.

Yes, Rust is younger. There is less code out there running to root out undefined behavior.

Except Rust allows for less undefined behavior. I wouldn't be surprised if it improved at a faster rate then C. Or C++ ()

() Please don't say C/C++. They are different beasts.

Addendum to your nitpick: Also don't even leave it at just "C++" unless you really are a master of everything in C++98 plus all the new stuff in C++14.
Even the name tells you that C++ was originally designed to be C with extra features. It can still be used that way and frequently is. These days, there are contexts in which the differences are very significant, and there are many others where any statement about either applies to both, and in those latter contexts "C/C++" is completely valid.
And C++ was originally just a C pre-processor. It's not anymore. So what it was originally is not that relevant nowadays. And that's the whole point. They have diverged too much.

These contexts you speak of are rare enough that the "no-C/C++" heuristic is useful.

Can you give specific examples of this alleged lack of stability?