Live data from Hacker News

Translating All C to Rust (TRACTOR)

darpa.mil

301–310 of 403 posts

Re: Translating All C to Rust (TRACTOR)

#301

Earlier quoted context omitted.

It doesn't make sense to convert a C array to a Vec, the Vec type is a growable array but the C array isn't growable. It makes sense to convert to Rust's array type, which has a fixed size, and we realise there's a problem at API boundaries because C's arrays decay to pointers, so the moment we touch an API boundary all safety is destroyed.

Depends on how the array is created. If it comes from "malloc" or C++ "new", it may need to be created as a "Vec".

Firstly, that's not an array. C has actual arrays, even though they decay to pointers at API edges and what you've made with malloc is not an array. I'll disregard C++ new and new[]

But also, it's definitely not a growable array. Box::new_uninit_slice makes the thing you've got here, a heap allocation of some specific size, which doesn't magically grow (or shrink) and isn't initialized yet.

Re: Translating All C to Rust (TRACTOR)

#302

That sounds ... hard. Especially as idiomatic Rust as written by skilled programmers looks nothing like C, and most interesting code is written in C++ anyway. Isn't it equivalent to statically determining the lifetimes of all allocations in the C program, including those that are implemented using custom allocators or which cross into proprietary libraries? There's been a lot of research into this sort of thing over…

Man, I want to upvote this but…

> most interesting code is written in C++ anyway.

Really?! The Linux kernel is a _pretty enormous_ counterexample, as are many of the userland tools of most desktop Linux distros.

I am also a key developer of an entirely-written-in-C tool which I'd venture that [a large fraction of desktop Linux users in corporate environments use on a regular basis](https://gitlab.com/openconnect/openconnect).

Re: Translating All C to Rust (TRACTOR)

#303
It sounds to me near-impossible to convert C or C++ into as-safe-as-possible Rust code, because the original intention of the developer are missing. However, I wonder if some clever generative AI could be taught to recognize sufficient C programming patterns in relevant code bases to make the problem tractable.

Re: Translating All C to Rust (TRACTOR)

#304

Earlier quoted context omitted.

> undefined behavior gives the compiler leeway in deciding what a program does, so the more undefined behavior a C program invokes, the easier it is to translate its code to rust. That's the kind of language lawyer approach that caused a rebellion in the last decade amongst C programmers against irresponsible compiler optimizations. "Who cares if your program actually works as intended? My optimization is legal accor…

> I don't see any evidence that that's the attitude being taken by TRACTOR — I sure hope it isn't. I don’t see any way it can do otherwise. As a simple example, what would one translate this C statement to: int i; … i = abs(i); ? I would expect TRACTOR to generate (assuming 64-bit integers): let i: i64; … i = abs(i); However, that can panic in debug mode and return a negative number in release mode ( https://doc.rust…

It's possible to preserve the semantics of the original program using unsafe Rust. [1]

    unsafe {
        let mut i: std::os::raw::c_int
            = std::mem::MaybeUninit::uninit().assume_init();
        // ...
        i = libc::abs(i);
    }
That's grotesque, but it is idiomatic Rust insofar as it lays bare many of the assumptions in the C code and gives the programmer the opportunity to fix them. It is what I would personally want TRACTOR to generate if it could not prove that `i` can never take on the value `libc::INT_MIN`.

Given that generated code, I could then piecemeal migrate the unsafe bits to cleaner, idiomatic safe rust: possibly your code but more likely `i::wrapping_abs()` or similar.

What will TRACTOR choose? At least for this example, they don't have to choose inappropriate pruning of undefined behavior. They claim the following:

> The goal is to achieve the same quality and style that a skilled Rust developer would produce, thereby eliminating the entire class of memory safety security vulnerabilities present in C programs.

If they're going to uphold the same "quality", the translation you presented doesn't cut it. But you may be right and they will go down the path of claiming that a garbage translation is technically valid under undefined behavior and therefore”quality” — if so, I will shun them.

[1] https://play.rust-lang.org/?version=stable&mode=debug&editio...

Re: Translating All C to Rust (TRACTOR)

#305

Earlier quoted context omitted.

> But, this isn't just about rewriting code from one language to another. It's about reverse engineering complex information out of the code, which may not be immediately visible in it, and then finding a way to make it "safe" according to Rust's type system. Where's the training data for that? It'd be really hard even for skilled humans. That might not be too bad. A combination of a formal system and an LLM might wo…

Yes, this is similar to what IntelliJ does for Java->Kotlin. Do a first pass that's extremely non-idiomatic and mechanical, then do lots of automated refactoring to bring it closer to idiomatic. But if you're going to do it that way, the right place to start is probably to a safer form of C++ not Rust. That way code can be ported file-at-a-time or even function-at-a-time, and so you'll have a chance to run the assert…

> But if you're going to do it that way, the right place to start is probably to a safer form of C++ not Rust.

There's something to be said for that. You're going to need at least an internal representation that's a safe C/C++.

Re: Translating All C to Rust (TRACTOR)

#306

a) if every C program could be translated into an equivalent safe Rust program, that would mean that each C program is as safe as the safe Rust equivalent. b) since there are C programs that are open to memory currption in a way safe Rust isn't, this corruptability would need to be translated into partially unsafe Rust. Congrats, you now have a corruptible Rust program, what's the point again?? c) so DARPA must be tr…

Memory corruption is undefined behavior and means the compiler is free to do anything it wants.

Anything it wants... and that includes doing something entirely safe and reasonable.

If you write out of bounds, the compiler is allowed to shut the program down in a controlled manner. It's allowed to transparently resize the array for you. Etc.

Hence a rust translation can do these things.

Re: Translating All C to Rust (TRACTOR)

#307

Earlier quoted context omitted.

> No serious person claims that Rust solves every problem ever No, but there are a lot of people claiming that Rust cannot ever have any problems. Just look at this thread. I merely linked to MIRI, and am currently at, like, -10 just for that. Lots of people claiming that it just applies to 'unsafe Rust': is that true or not? Regardless of anything else: can you, as a Rust community leader, please state clearly: is U…

No, people are not claiming Rust cannot have any problems. UB is not possible in safe Rust, by design. The root cause of UB is always in unsafe code. Miri is useless if your code is 100% safe Rust. The only exception to this is bugs in the compiler, of which there are a few. They’ll be fixed.

I have no faith in this statement. Let's see how it plays out.

Re: Translating All C to Rust (TRACTOR)

#308
post #252
post #50

Earlier quoted context omitted.

speaking of hard, the DOE actually funds a project that has been around for 20+ years now (ROSE) that involves (among other things) doing static analysis on and automatically translating between C/C++/Cuda and even high level languages like Python as well as HPC variants of C/C++. They have a combined AST that supports all of those languages with the same set of node types essentially. Quite cool. I got to work on it…

I have already seen legacy projects that were designed using Rational Rose, but for some reason I thought it was only a commercial name, not an actual system. Thanks, I learned something today !

Your first instinct was more correct, that's definitely a different thing. :) https://en.wikipedia.org/wiki/IBM_Rational_Rose

Re: Translating All C to Rust (TRACTOR)

#309

Earlier quoted context omitted.

> I don't see any evidence that that's the attitude being taken by TRACTOR — I sure hope it isn't. I don’t see any way it can do otherwise. As a simple example, what would one translate this C statement to: int i; … i = abs(i); ? I would expect TRACTOR to generate (assuming 64-bit integers): let i: i64; … i = abs(i); However, that can panic in debug mode and return a negative number in release mode ( https://doc.rust…

It's possible to preserve the semantics of the original program using unsafe Rust. [1] unsafe { let mut i: std::os::raw::c_int = std::mem::MaybeUninit::uninit().assume_init(); // ... i = libc::abs(i); } That's grotesque, but it is idiomatic Rust insofar as it lays bare many of the assumptions in the C code and gives the programmer the opportunity to fix them. It is what I would personally want TRACTOR to generate if…

> It's possible to preserve the semantics of the original program using unsafe Rust

Because of the leeway the C standard gives you, you can preserve the semantics of the C program by just calling abs, and I think that’s the best you can do.

What the compiler does may be different for different compilers, different compiler versions or different compilation flags, so if all you have is the C source code, there’s no way to preserve the semantics of the machine code that the C compiler generates.

You could special-case all of them, but even then, there is the problem that a C compiler, even in a single translation unit, can inline one call and then apply some transformations while compiling another call to a call to a library function, making the semantics of overflow in one location different from that in another.

If you want to replicate that, I’d say you aren’t writing a C to rust translator, but a (C + assembly) to rust translator.

Also, if you go this route, you’d have to do similar gnarly stuff for all arithmetic on integers where you cannot prove there will not be overflow. I would not call the resulting code idiomatic rust.

Re: Translating All C to Rust (TRACTOR)

#310

Earlier quoted context omitted.

It's possible to preserve the semantics of the original program using unsafe Rust. [1] unsafe { let mut i: std::os::raw::c_int = std::mem::MaybeUninit::uninit().assume_init(); // ... i = libc::abs(i); } That's grotesque, but it is idiomatic Rust insofar as it lays bare many of the assumptions in the C code and gives the programmer the opportunity to fix them. It is what I would personally want TRACTOR to generate if…

> It's possible to preserve the semantics of the original program using unsafe Rust Because of the leeway the C standard gives you, you can preserve the semantics of the C program by just calling abs , and I think that’s the best you can do. What the compiler does may be different for different compilers, different compiler versions or different compilation flags, so if all you have is the C source code, there’s no w…

What you describe is antithetical to idiomatic Rust, written by a skilled Rust programmer.

To uphold the spirit of Rust, a C program must go through a process where assumptions are laid bare and footguns are dismantled. Applying an automatic process which arbitrarily changes the behavior from the implementation-dependent compilation of a C program just gets you a messy slop of hidden bugs collected inside an opaque, "safe" garbage can.

You don't get to Rust's reliability by applying a translation which discards it!

> Also, if you go this route, you’d have to do similar gnarly stuff for all arithmetic on integers where you cannot prove there will not be overflow.

Damn straight. That's what C is! It was always this bad, as those of us who have struggled to control it can attest. Faithful translation to unsafe Rust just makes it obvious.

Post reply on HN