Hacker News new | past | comments | ask | show | jobs | submit login
Translating Quake 3 into Rust (2020) (immunant.com)
121 points by lukastyrychtr 45 days ago | hide | past | favorite | 27 comments



Need some benchmark numbers after that.

Rust compiled binary FPS vs C code FPS.


It should be the same as the C code compiled with clang. Apart from edge cases, it's a straightforward 1:1 translation. It all ends up in the LLVM optimizer either way.

c2rust doesn't change semantics of the C code, so there's no added safety, no extra abstraction, no checks. The converted code can be the first step in refactoring towards safe Rust, but that's a manual job.



> Pointers to Arrays

>In a few places, the original source code contains expressions that point one past the last element of an array. Here is a simplified example of the C code:

    int array[1024];
    int *p;



    if (p >= &array[1024]) {
   
    }
>The C standard (see e.g. C11, Section 6.5.6) allows pointers to an element one past the end of the array.

Wait? Why?

I get that char strings in C are null terminated and that might seem like an off by 1 issue if you aren’t paying attention, you still size your string one larger than your string.

What is this all about?


    #define COUNT(array) (sizeof(array) / sizeof((array)[0]))

    int array[1024];

    for (int *p = array; p < array + COUNT(array); ++p) {
        // ...
    }
For the loop to be well-behaved, such pointer formation must be well-defined.


It's so you can do exactly what's being done here - see if you have reached the end of the array by comparing the current position pointer.

Lots of iterator designs have a special "end" iterator you can compare against but not deference or access - this is just the same for C arrays.

The C standard here allows pointers to elements one past the array, but it's still busted if you try to dereference it.


Makes sense. I got what they were doing but in my head combined the C statement of addressing and accessing/dereferencing.


You can point to the element one pass, but you cannot dereference the pointer.


Ah, I get it now.

And it’s interesting to me that Rust doesn’t allow that considering it’s not accessing memory (yet, and that’s the whole point I’m sure.


Pointers in Rust behave the same way. The problem is that the "array index" operator in Rust returns a reference to the indexed element, not a pointer, and references must be safely dereferenceable.


C arrays are nothing more than convenient pointer math. array[1024] = &array + sizeof(element) * index (in that case 1024). And while there is some weird post-facto "one past the end" bit in the standard (added long after Quake 3 was made), in any modern compiler you can happily get pointers for illegal indexes. If you have a literally sized array and a literal offset it could warn (e.g. Warray-bounds), but for the vast majority of cases it won't flag at all. Nor would this cause any runtime issues. Because it's just math.

And the truth is that without runtime memory protection you can dereference those illegal positions.


It is very confusing to me that you've been downvoted in this thread. Anyone who did so want to explain why?


I didn’t downvote (I can’t, and I wouldn’t have anyways) but I’ve often see the “Wait? Why?” (Or “wait, what?”) construct carries a connotation of “Why are you doing this insane bad thing?” which people sometimes react negatively to.


Ah, that would make sense. I wouldn’t have thought of it that way. Thanks.


Yea, maybe it’s that, but every other post I’ve made is also offended someone deeply or so it would seem :)


I second that. Why punish someone for asking a pretty understandable question?


Reading at the transpiled code, theres something that make me a little worried if this becomes a trend. The lost information in the process. I guess if there's an AI in the middle, capturing the logical context and later helping into the translation process.

In that way the power of the source code to teach us will still be there.

I understand if some tool that is in C and need a boost in security might use this, but giving the output code is intractable, they would still have to code in C, so this kind of defeat the some of the goals of writing code in a more secure environment.

Its important to understand that security is just one of the axis of a whole that have much more things to consider.

Having said that, maybe there will be a good use for source code in C that needs a safety boost right away in critical places, or use something like this to spot dark corners and fix the code back in C.

Also, great hacking points to whoever did this, as this is fun just because is hacking at its best.


You don't get much of a safety boost right away with the auto-translation, because a lot (all?) of it will start out wrapped in unsafe blocks. The idea is to use it as a jumping-off point from which you can gradually migrate more and more code into safety


It produces functions which are pub unsafe extern "C" -- which among other effects currently results in effectively wrapping the code in an unsafe block yes.

It seems as though the very long term plan is to divide more thoroughly the unsafe function declaration (purpose: To flag to people calling it that they need to be careful) from the unsafe block (purpose: To flag to the compiler that you checked this is OK and so it's fine that the compiler can't tell if it's OK). Today I believe the linter will optionally complain that you didn't clarify, and perhaps in the Rust 2021 edition the compiler will default to rejecting this, then perhaps Rust 2024 will just outlaw it.

I expect c2rust will eventually either just shove everything inside unsafe {} blocks as well as inside unsafe functions, or it will mark code as Rust 2018 edition and let you change that when you've written as idiomatic Rust.


That makes sense. But i wonder if two teams creating a port, one straight from the C code and the other with the translation output..

Which one would end first and with the best version..

(Not sure if doing this from the transpiled code is the best option, giving you will miss a lot of otherwise informative context in the original source)


So, is quake3 more performant with the rust version? not that it really matters in modern hardware, but I'm curious if Quake3 rust would run faster on my 486.


Quake 1 wouldn't even run on a 486, and Q3 needed a GPU, one of the first games to have that requirement.


Quake 1 relied on fast floating point maths. So it would run on a 486DX (the variants with floating point) but very slowly. Intel's Pentium at similar or even slower core speeds has much faster FP maths, resulting in Quake on a mid-range Pentium PC running rings around Quake on the top-spec 486, whereas most other games from that era would be faster on the 486.


Quake1 ran on my 486 for sure, I think I also tried Q3. I think I was running either slackware or mandriva. All games required a GPU, so you probably mean DirectX or OpenGL acceleration.

Yes, so given the existence of OpenGL acceleration on chip would this rust version be significantly more performant than the c++ version?


Quake 1 ran on a 486 but wasn't very playable, you needed the fast FPU of the Pentium for that. Quake 1 and 2 also didn't require a GPU, they had a software rasterizer. Quake 3 did require one.


Yeah it ran, at low res and low FPS, I remember I had one too. It was barely playable. You really wanted a Pentium


With c2rust it wouldn't. It would likely be slower in some cases due to added checks for, say, buffer overruns.

But that's not the point. C2rust code is not "idiomatic". You get weird, unsafe Rust code full of potential side effects. The idea is to provide a means for you to start rewriting things in ways that make sense in Rust.

Would the final code be faster? Harder to tell. Maybe, maybe not. It depends on how well it's implemented, what kind of clever constructs are applied, what the game's bottlenecks are, etc.

And yet, I don't think that matters much either. Games shouldn't be bound by CPU as much nowadays unless they're doing massive simulations that are likely not language constrained. So it would be the wrong comparison to make IMO.




Applications are open for YC Winter 2022

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: