8 ms·
C2Rust Transpiler
- als0 4y agoYou can try it out on the main website https://c2rust.com https://c2rust.com where they have a web version. Unfortunately it isn't working (HTTP 503 error)
- gwbas1c 4y agoReally cool concept! (Rust is my favorite language for tinkering; I haven't touched C since I was in school.) What would really help is success stories: Who's used it? What have they used it for? What challenges did they encounter? Then again, maybe this is so new that there aren't a lot of success stories yet. :)
- mastax 4y agoFrom what I remember it was primarily funded by a DoD project of some sort. There probably isn't a lot of info about that. There have been a few conference talks or blogposts about it (I'm trying to remember) that talked about the process of using it.
- mshockwave 4y agoIt’s actually funded by DARPA so basically everything in this project is public available.
- dtolnay 4y agoI used it with great success for transpiring libyaml from C to Rust. I even set up Miri to run the upstream library's entire transpiled test suite, and the fact it passes is validation of absence of UB in the original C code. The transpiled library now serves as the YAML backend for the widely used serde_yaml crate. Having serde_yaml be pure-Rust code instead of linking C is advantageous for painless cross-compilation as well as making downstream projects runnable in Miri. https://github.com/dtolnay/unsafe-libyaml https://github.com/dtolnay/unsafe-libyaml
- pitaj 4y agoVery cool. Miri is seriously awesome.
- tialaramex 4y agoA few questions, if I may: Is the intent that this continues to evolve by newer libyaml code getting transpiled, or that it's effectively a fork and might gradually become more idiomatic Rust which does the same job as the C but won't track any changes? Or is this basically "done" and only small changes (to both this code and the C libyaml) are anticipated anyway? The c2rust documentation cautions that any platform independence isn't preserved, so if libyaml has types which are different on platform A versus platform B, the c2rust transpilation on platform A just gives you Rust types for platform A, losing that independence, was this an issue for libyaml ?
- SaddledBounding 4y agoI think a demo of the transpiler output for a short function would make a great addition to the readme.
- deleted 4y ago[deleted]
- dahfizz 4y agoI would be interested to see performance numbers of the C version and the transpired rust version of some program.
- pornel 4y agoIt's like compiling C with clang.
- mastax 4y agoTheir blogpost about translating Quake 3 was interesting: https://immunant.com/blog/2020/01/quake3/ https://immunant.com/blog/2020/01/quake3/
- cylinder714 4y agoFWIW, the V folks demonstrate translating DOOM source to V and compiling it: https://youtu.be/6oXrz3oRoEg https://youtu.be/6oXrz3oRoEg https://github.com/vlang/doom https://github.com/vlang/doom
- pwdisswordfish9 4y agoHow much memory does it leak at startup?
- deleted 4y ago[deleted]
- wizardman 4y ago
- deleted 4y ago[deleted]
- Tozen 4y agoIt looks better to actually use the language in which one is speaking about. Vlang went into beta (0.3), so does not leak memory. It uses a GC, by default. The plan was always for Vlang to have optional memory management, which is: GC, autofree, and manual. And, since it is a language going through its developmental phases, it could be argued to give it some leeway.
- fbdab103 4y agoA potential use case I see is for security auditing. Even if you cannot port an existing C codebase to Rust, you could run this tool to examine the unsafe hotspots. Any place where the translation has to rely upon unsafe is a region of the code more likely to contain any of the mistakes Rust is designed to prevent. Of course, this pre-supposes that 90% of the translation does not have to lean on unsafe annotation.
- kazinator 4y agoI suspect that this relies on unsafe pretty much everywhere. Even handling argc and argv in your C main function, in idiomatic ways, is unsafe. There is no 80/20 rule for C unsafety, other than maybe an inverted one: 80% of the unsafety of a large C program might be spread into 80% or more of the code. :)
- counttheforks 4y ago> Even handling argc and argv in your C main function, in idiomatic ways, is unsafe. Not knowing C very well, could you clarify what makes it unsafe? Thanks!
- initplus 4y agoC arrays are just sugar for pointer arithmetic. [] just calculates the sum and deferences the result. arr[n] == *(arr + n) == n[arr] All these forms are valid C and gcc will happily compile them all without complaining.
- tinco 4y agoThe word unsafe has a specific meaning in Rust. It doesn't mean every C program that uses argc and argv is unsafe. In this specific case however I don't think it would actually require much unsafe. The only unsafe thing I'd introduce is a way of casting the *argv[] to a type that safely deals with null terminated strings. Maybe such a type is already in Rust's standard library and I wouldn't even need that. edit: eh sorry I wasn't thinking straight, you of course need unsafe to cast the argv itself to a type that has a seperate argc as well. Assuming such a type is available, if it's not its implementation would also have unsafe all over the place. Maybe to answer the underlying question. What makes it unsafe is that in C it is assumed the programmer knows to keep all indexes into argv under argc. In Rust such an assumption must be made explicit by specifying "unsafe". It is idiomatic Rust to have all instances of "unsafe" in libraries whose implementation is vetted by the community, so ideally there are little to no instances of "unsafe" in the application logic itself. Rust's compiler and type system have various tricks that reduce the amount of "unsafe" you would think you'd need for even quite complex problems.
- kazinator 4y agoSampling some directories and files in the test suite of this project, I see a problem: testing is done by translating C to rust and compiling it, and then testing the run-time behavior of the result. I don't see test cases which cover the behavior of the translator directly: like that a certain C language input maps to a certain Rust output.
- samus 4y agoThis tool is there to automate the boring parts of converting codebases. The real work is verifying the parts that rely on undefined behavior. High fidelity and reliability would be a concern if the transpiler is used to regularly sync between C and Rust versions of a same codebase. It's less of a problem for one-off efforts. Those will usually be heavily tested and inspected before the result is trusted. Edit: it would of course be nice to see proper quality control applied, but prototypes have to proof quickly that they are worth the time spent refining them.
- kazinator 4y agoA source-to-source translator is a textbook example of something that is slam-dunk unit testable. There is almost no valid argument against doing it. Note: maybe this project has it in there; I haven't exhaustively looked into every subdirectory. > if the transpiler is used to regularly sync between C and Rust versions of a same codebase How do you know it won't be used that way? Because the maintainers of every C codebase will stop what they are doing in C, and follow the Rust conversion as soon as they hear about it? Even if you use this tool to permanently cut some code base over to Rust, it would be nice there to be some assurance about what it's doing beyond just "the converted code seems to do the same thing". A conversion could be done two or more times even if the C code isn't changing. Say you do the conversion. Then hack on the converted code. A new version of the converter comes out claiming to fix bugs. You might want to re-run it on the original code again, see if anything changed, and merge those changes to the current code stream that already contains modifications. > The real work is verifying the parts that rely on undefined behavior. That is neither here nor there. A construct that is confirmed undefined in C can be translated to the call to a Rust function that makes damons fly out of your nose. And there can be a couple of unit tests confirming this translation strategy. Or else, something else can be done. E.g. let's say the C code relies on wraparound two's complement arithmetic. The translator can oblige and generate code which makes that work (making that translator more helpful than some modern C compilers).
- Animats 4y agoHow does this compare to Corrode? The trouble with these things is that the Rust that comes out is usually too awful to maintain. Corrode, too, said that someday they'd generate more reasonable Rust. But that never happened. Converting C into Rust with unsafe raw pointers is not all that useful. What's needed is some way to provide key information C doesn't have. Mostly about array sizes. Some way to annotate int read(int fd, void* buf, size_t len) to tell the system that buf has size len. A file of translation hints with such info could guide the translator into producing decent Rust. Most of the things done with pointer arithmetic can be expressed with slices. (Things being done with pointer arithmetic which can't be expressed as slices should be viewed with deep suspicion.) But you need size info to do that.
- WalterBright 4y agoI proposed an extension to C which adds slices: https://www.digitalmars.com/articles/C-biggest-mistake.html https://www.digitalmars.com/articles/C-biggest-mistake.html
- Animats 4y agoMe too.[1] But it would have meant years of work on language politics. It might be worth looking at this sort of thing again, because machine learning is far enough along that recognizing and converting the usual array idioms is feasible. If the output code with array bounds is run time checked, then errors in translation will result in detected array bounds errors. [1] http://animats.com/papers/languages/safearraysforc43.pdf http://animats.com/papers/languages/safearraysforc43.pdf
- deleted 4y ago[deleted]
- Arnavion 4y agoYes, Windows has been doing that with SAL annotations for years.
- masklinn 4y ago
- WalterBright 4y agoC translates quite readily to D. I've been able to translate thousands of lines at a time in less than an hour, usually with some global search & replace and then making adjustments after running it through the D compiler. We relied on being able to do this in the D community for quite a while. There also have been three three translators built, with more or less effectiveness. It is nice to get the code into D, and then take advantage of D's safety features. The fundamental problem with translation, followed by some hand tweaking, is that it only works if the C version is to be abandoned. If the C code is maintained by anyone else, as soon as they make changes, the translation gets out of date. Updating the translation turns out to be impractical because of the hand tweaking necessary. Then there are some frustrating structural limits. The largest is that C doesn't have modules. The preprocessor puts everything into one file, and every C compilation is for one file. Declarations get duplicated across every translation unit. Somehow, these need to get teased apart into modules. This structural redo gets done by hand, and requires pretty good familiarity with the C code's design. The preprocessor poses another major problem. The preprocessor language and the core C compiler have no knowledge of each other. They are completely separate languages, with their own syntax, keywords, semantics, etc. The preprocessor, aside from trivial use of it, simply does not translate into other languages. I also have yet to find a C programmer who could resist using the preprocessor as a metaprogramming language, which does a great job at obstructing all efforts at converting to another language. All this stuff raises a lot of friction for D interacting with C code. Programmers don't like friction, they don't want to deal with C code they are unfamiliar with, they don't want to fold in maintenance changes in C code to the translation, etc. They want it to "just work". The eventual solution I came up with is obvious, but I'd always dismissed it as impractical. Just fix the D compiler to be able to compile C code directly, and internally make the C declarations and constructs available to D code. This turned out to be fairly easy to do, and is ridiculously effective. It sometimes works even better than C++'s ability to #include C code (C++ doesn't support things like _Generic, old style C declarations, etc.). All you have to do is import .c code just like importing any D module, and the D compiler takes care of all the dirty work for you. It isn't perfect, for example, C compilers have lots of extensions, and dealing with all of them is hopeless. But we just do the common ones, as it turns out most of them are rarely used.
- 4y ago