logoalt Hacker News

torginustoday at 11:41 AM4 repliesview on HN

I don't even get what they gain by Rust - Bun imports Webkit, which is a C++ project, relying on it for stuff like JITing Javascript. I would say that's a major concern, and making sure the JIT doesn't emit anything broken or naughty is completely outside the scope of Rust.


Replies

saghmtoday at 1:39 PM

I don't have a strong stance on the overall issue of whether it made sense for them to port like this, but I feel like this misunderstands the value proposition of Rust. The point of Rust is not and has never been "make literally everything safe", it's "push the unsafe boundary as low as possible and keep as much as possible above it so that you can reduce the surface area for unsafety and more easily find bugs in the unsafe code". For some things, that means you can rely only on unsafe code that's in the standard library implementation, which is awesome. For others, you might need to rely on FFI to interface with external libraries, and that's obviously less ideal but still provides tangible value. In the worst case, you might need to write unsafe Rust code yourself, but you can at least take efforts to minimize the surface area of it by wrapping it in safe abstractions that enforce the invariants you need to uphold safety.

The idea that "anything other then pure safe Rust is useless" is common (even among some Rust proponents, but generally not the most experienced ones), but it's a pretty fundamental misconception of what Rust actually offers. Safety is a spectrum, not a binary, and while the extreme end of "everything is guaranteed to be safe no matter what" is nice when you can get it, Rust is literally designed to solve the problem of giving you the ability to slide along the spectrum to calibrate to the most amount of safety you an achieve rather than being all-or-nothing.

If you still think there's no value in enforcing safety outside of the lowest level stuff like JIT, I'd suggest being more explicit about why you're confident that memory safety bugs wouldn't be a concern outside of those contexts. I've yet to hear an argument for why I shouldn't be concerned about memory unsafety in even relatively mundane code in memory unsafe languages that doesn't basically boil down to "just be really really careful", which I'd argue has been empircally shown to not work even a little bit no matter how skilled the programmers writing the code are.

show 1 reply
woodruffwtoday at 11:58 AM

I think their original post lays out the benefits pretty well. I think the realization of some of these benefits is debatable (for example, they probably could have made their existing Zig code faster), but others are straightforward (like having fewer crashes because more of your code is provably “safe” in Rust terms).

(I think wrapping a large, complex C/C++ codebase is where Rust often shines, if you build the right joiner abstractions. PyO3 is a really great example of that.)

lyu07282today at 1:27 PM

They listed some of the memory bugs they had in the blog post, I just looked at three of them, the first one was this:

> heap-use-after-free crash in node:zlib when calling .reset() on a zlib, Brotli, or Zstd stream while an async .write() is still in progress on the threadpool

https://github.com/spaceraccoon/vulnerability-spoiler-alert/...

If you look at the fix you can see its all in their zig codebase:

https://github.com/oven-sh/bun/commit/621c4016218bb782e05907...

What is kind of funny is that nodejs also had a basically identical bug with an almost identical fix:

https://github.com/spaceraccoon/vulnerability-spoiler-alert/... https://github.com/nodejs/node/commit/53bcd114b10021c4a883b0...

But now the interesting question, how does the code look like in Rust?

https://github.com/oven-sh/bun/blob/8f1a9540fdff25410506de76...

It has the same guard in place as the zig and c++ versions, the rust code also just calls into the zlib bindings after the "write in progress" check.

So in this case at least the same exact use-after-free would've happened and they don't win anything from the rust port.

Another one was this:

> crash and out-of-bounds read in Buffer#copy and Buffer#fill when a valueOf callback detaches or resizes the underlying ArrayBuffer during argument coercion

I think ths is the fix:

https://github.com/oven-sh/bun/commit/79522ab6c579736dc239fa...

But the bug here is in C++ bindings, Rust wouldn't have helped here either.

Last one:

> double-free crash in the CSS parser when background-clip had vendor prefixes and multi-layer backgrounds

Fix: https://github.com/oven-sh/bun/commit/912970c98437e418a95b6b...

Code side-by-side:

Rust: https://github.com/oven-sh/bun/blob/8f1a9540fdff25410506de76...

Zig: https://github.com/oven-sh/bun/blob/912970c98437e418a95b6b5b...

I can't judge the Zig code, perhaps someone could say if this was a "beginner" mistake.

But this is at least one case where Rust would've helped, although even that is a bit complicated considering stuff like bun_ptr:

    // Lifetime-erasure helpers (RUST_PATTERNS.md §6/§18) — re-exported here so
    // crates that already depend on `bun_collections` (logger, css, js_parser,
    // crash_handler, watcher, http_types) can route the borrowck-dodge through
    // one centralised `unsafe fn` instead of open-coding the lifetime cast.
    pub use bun_ptr::{RawSlice, detach_lifetime, detach_ref};
Which is a bit concerning?
lolindertoday at 1:18 PM

> making sure the JIT doesn't emit anything broken or naughty is completely outside the scope of Rust.

It's also outside the scope of the project if they're using Webkit's engine for that part. Which means Bun itself isn't a JIT, it's all the stuff built around the Webkit JIT, so whether or not Rust is useful for the JIT is entirely immaterial to the question of if Bun would benefit from Rust.