Is tokio + hyper safer than GoLang / stdlib-http?

No flame war intended. Genuine question. I'm fairly pro-Rust given the time I have spent studying Rust, but this line of logic is starting to bother me.

Concrete question: is tokio + hyper safer than GoLang + stdlib-http ?

Pro Rust argument:

  1. GoLang has all types of data races that Rust's borrow checker catches. Thus, Rust is safer.

Pro GoLang argument:

  1. tokio / hyper has hundreds of unsafe blocks; and even more calls to them. A single mis-use leads to undefined behaviour, and out goes Rust's safety model.

Argument against GoLang's argument:

  1. All the tokio/hyper unsafe blocks have been checked and are safe. There is no undefined behaviour.

  2. There may be some undefined behaviour, but because Rust is awesome, they are 'contained.'

Argument against "Argument against GoLang's argument'

  1. #3 is unreasonable. Short of formal verification, this seems very unlikely.

  2. #4 is BS. Once there is UB anywhere, the entire program is UB.

So now, at this point, for a highly concurrent webserver, I can no longer convince myself that Rust + hyper + tokio is 'safer' than GoLang + stdlib-http.

Advice ?

Go's stdlib has hundreds of unsafe code; and even more calls to them. Our base systems are fundamentally unsafe. You need to have some amount of unsafe code to build safe abstractions over it. What matter actually is that those abstractions should be written/reviewed/tested properly.

Common way to build trust on project is to outsource it on some big companies. Yes, google uses Go and tokio.

https://android.googlesource.com/platform/external/rust/crates/tokio/

4 Likes

This is true, UB anywhere is UB everywhere, but at least you know where to look if there are problems.


Formal verification isn't necessary to prove something logically sound. AFAIK there also isn't any formal verification for the implementation of Vec1, but no one has problems with using it. (well, not for its soundness, anyway) Don't get me wrong, formal verification is certainly awesome! But something can still be valid without it.

Maybe so, but all uses are known and can be checked and verified. Any way safe code can cause UB is a problem with the unsafe code the UB occured in, not the safe code.

Not all unsafe code is necessarily valid, but it is much easier to check a few blocks than all of your code.


@jonhoo 's talk "Demystifying unsafe code" I believe does a great job of explaining this, and why it's okay that everything is built on the shoulders of unsafe.

1If anyone is aware of one, do share! I just haven't seen one yet

1 Like

This is largely what Hyeonu said, but remember that any program that interacts with the OS is using "unsafe code" somewhere. Some languages don't emphasize it as clearly as Rust does, but every language that's widely used can call out to SOs/DLLs written in C, and doing so is fundamentally unsafe. Perhaps it's hidden in the language runtime or JiT or something, but it's always there.

Thus it's a judgement call of how much there is, and how reasonable the use is. Not a binary "is there any" call.

1 Like

I don't know anything about Go, but when it comes to real-world vulnerabilities, a bug that doesn't involve unsafe in hyper is more likely to result in a vulnerability than unsoundness in Tokio is.

4 Likes

I disagree. UB only causes the optimizer to assume your program won't ever pick the codepath containing it, or be fed input that lead to it. The nice thing about Rust is that usually even if there's UB hidden in some rust library you (the programmer, not even the user of your program!) need to really try to trigger the situation that leads to the UB codepath.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.