← Back to context

Comment by SuperV1234

2 days ago

> The main problem, however, was code quality.

> The sleight of hand misdirects the reader away from the main way bugs are eliminated: by dedicating engineering resources to it.

Perhaps the amount of bugs comes from using a C-like language that requires meticulous manual care to avoid writing runtime bugs.

Even C++ would be a safer choice because of RAII.

When you have to dedicate significant resources to avoid/fix runtime issues that are made impossible at compile time by other languages, the programmer isn't entirely at fault.

Memory safety problems are still possible in the new Rust Bun:

     At the time of writing, about 4% of Bun's Rust code sits inside an unsafe block (~13,000 unsafe keywords across ~27,000 lines / ~780,000 lines), and 78% of those blocks are a single line — a pointer that came from C++, or one call into a C library.

  • People bring this up a lot. What I see here is that thousands of potentially (not actually, just potentially) safety risks have been neatly tagged in the code.

    If you took a program written in Zig, Go, C++, or C, you would have no idea which parts of the code were potentially unsafe. In those languages, the entire program is one big unsafe{} block.

    Rust isolates unsafe code. Having them explicitly tagged means they're isolated and can be eradicated over time, if need be. Though in many cases, unsafe blocks are quite safe.

  • Yes - I think the proof of the pudding will be whether they put in the effort to eliminate these unsafe blocks. The conversion to Rust is the starting point that makes this possible, but it's definitely not "done" at this point.

    • If the majority of those are at an FFI boundary to a language without lifetime analysis, I don't really see how they could be fixed without rewriting all that downstream software?

  • Yes but through iterative ratcheting, some portion of that unsafe can likely be migrated to idiomatic code without unsafe. And the other 96% of the code now has more mechanical guarantees than it did before.

    Static linting in Rust via clippy also makes it pretty straightforward to begin enforcing things like "unsafe blocks need to have safety doc comments" as a CI warning or failure, and there are community tools that focus on this topic too.

    I can't stand the practice of "LLM porting" personally but if you're going to do a mechanical rewrite from something else into Rust, this (permit unsafe and unidiomatic but 1:1 translation at first) is a fairly reasonable strategy imo.

  • > 78% of those blocks are a single line — a pointer that came from C++, or one call into a C library

    Don't those blocks need some additional lines for error checking to prevent the unsafety from spreading to the safe code?

    • It depends

      Suppose there's a C library libape which implements monkeys you need in your software. There's a C API where we pass a pointer to a valid monkey and a 32-bit unsigned integer which controls how delicious bananas are. Any 32-bit unsigned integer is valid here, except zero because monkeys always think bananas are at least somewhat delicious, and there's no return value.

      Our Rust wrapper probably has Monkey as a type, wrapping one of those valid monkey pointers we mentioned, and so our wrapper for that API call is some unsafe code which just calls the C with this monkey pointer and a non-zero unsigned 32-bit integer which in Rust is just the type NonZeroU32 and we're done. That's a single line, the unsafety checking was all done in Rust's type system, every Monkey has a valid monkey pointer, every NonZeroU32 is (as its name suggests) a non-zero unsigned 32-bit integer.

      Now on the other hand, maybe we're wrapping code which takes a char * pointer intended to point at some zero terminated ISO-8859-1 encoded text. That Rust wrapper would be responsible for this translation and maybe you do that work in the wrapper function. But, if you had sixty calls like that, probably you make a Rust type for this problem named like Iso8859dash1Text and then those unsafe calls don't have a lot of boilerplate because all that boilerplate (which is probably even safe Rust depending on how exactly you do it) lives in this Iso8859dash1Text type you made. And that's also a useful model if later you discover the C library lied and it's not ISO-8859-1 it's really Windows Codepage 1252 ...

  • Possible, yes. But it's not like it's terribly difficult to verify correct usage of "unsafe" that amounts to a basic function call to a C library. Trivial uses of unsafe are pretty innocuous.

  • dude was writing slop before A.I. Andrew called him out.

    I don't write Rust - but I sure know that I'm not supposed to use 'unsafe'.

You have to put similar amount of resources when writing in Rust as well. With the difference that it’s more front loaded. Personally I’m a fan of Rust’s approach but the price for having bug free code has to be paid, regardless, one way or the other.

I’ve not seen any languages that does not require meticulous care to avoid runtime bugs. Type checking and lifetime ownership eliminate some, but not all of them.

  • > Type checking and lifetime ownership eliminate some, but not all of them.

    They actually remove certain classes completely. E.g. lifetime ownership in Rust removes all bugs related to the reason why it is in the code syntax (a.k.a. lifetime markers remove use-after-free completely in Rust.)

  • So less meticulous care then?

    • Not really, as you always need to check back on your assertions, especially at the boundary points where information about types and ownership are more axiomatic than the result of logical inference.