3 ms·
> 2. there are tools to convert c to rust (I dont know if I'd trust this..) The core C specification by itself isn't all that complicated of a language; a C-to
by jcranmer 3y ago
> 2. there are tools to convert c to rust (I dont know if I'd trust this..)
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.
- jandrese 3y agoThe big problem is just the fundamental mismatch between what Rust requires and what you can do in C, especially with embedded code. 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.
- Animats 3y ago> C-to-Rust transpiler is a pretty doable project. 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?
- jcranmer 3y ago> It's been done, but what comes out is terrible Rust. Everything is unsafe types with C semantics. The idea behind the current c2rust tool is that you'd do a one-shot conversion to Rust and then gradually do refactoring passes over the barely-Rust code to convert it to correct C code. The focus is on preserving semantics of C over writing anything close to idiomatic (cue a + b being translated to a.wrapping_add(b) all the time, e.g.). Which is an approach, but I'm not sure it ends up providing any value over "set your system to compile both C and Rust into a final image and then slowly move stuff from the C to the Rust side as appropriate" in practice. > Usually, C code does have array length info; it's just not in a form that the language ties to the array itself. This is actually why C23 made VLA support semi-mandatory: it enables you to describe a function signature as int write_to_device(size_t len, char buf[len]) and C23 compilers are required to support that, even in absence of full VLA support! The intent of making this support mandatory was to be able to use that as a basis for adding better bounds-checking support to the language and compilers. (Although, as you noticed, there is an order-of-declarations issue compared to the typical idiomatic expression of such APIs in C, and the committee has yet to find a solution to that).
- Animats 3y ago> The idea behind the current c2rust tool is that you'd do a one-shot conversion to Rust and then gradually do refactoring passes over the barely-Rust code to convert it to correct C code. I've seen what comes out of the transpiler. Nobody should touch that code by hand. It's awful Rust, and uglier than the original C. Modifying that by hand is like modifying compiler-generated machine code. > This is actually why C23 made VLA support semi-mandatory. C23 doesn't actually use that info. You can't get the size of buf from buf. I proposed something like that 12 years ago.[1] But I wanted to add enough features to check it. [1] http://animats.com/papers/languages/safearraysforc43.pdf http://animats.com/papers/languages/safearraysforc43.pdf
- jcranmer 3y ago> I've seen what comes out of the transpiler. Nobody should touch that code by hand. It's awful Rust, and uglier than the original C. I can't disagree here. I think the original idea was to rely on automated refactoring tools to try to make the generated Rust somewhat more palatable, but I never was able to get that working. > C23 doesn't actually use that info. True; the intent is to require it so that it can be leveraged by future extensions. The C committee tends to move glacially.