Hacker News new | ask | show | jobs
by tom_mellior 3276 days ago
> Note that all of these are inside of unsafe blocks. Besides unsafe blocks, Rust has no undefined behavior, and the compiler will prevent you from doing any of these things.

It's true that unsafe is needed to get these problems, but they can also occur outside of unsafe blocks. See an example here: https://gankro.github.io/blah/only-in-rust/#unbound-lifetime...

Your own code need not use "unsafe" at all, but the program may still crash in your code if you called some function that internally does unsafe things to mess up your memory.

EDIT: I should say that the linked code does not crash, it only reads uninitialized memory. It seems to me like the same hole could be used to make things crash, but I don't have a ready-made example.

2 comments

The important quote from the article you linked is: "But what happens when we throw some unsafe code at the issue?", so the claim that safe Rust doesn't have UB (that isn't considered a bug in the compiler) still stands. If you mix in unsafe code, bad things may happen, regardless of whether you wrote the unsafe yourself or rely on a library.
> the claim that safe Rust doesn't have UB (that isn't considered a bug in the compiler) still stands

Yes!

> If you mix in unsafe code, bad things may happen

Yes!

My point was only that those bad things may also happen after the unsafe block that is their root cause. This is in reply to parent's "all of these [UBs] are inside of unsafe blocks". They aren't. They are caused by something inside unsafe blocks, but they may also materialize after.

See also https://doc.rust-lang.org/nomicon/working-with-unsafe.html

> unsafe does more than pollute a whole function: it pollutes a whole module. Generally, the only bullet-proof way to limit the scope of unsafe code is at the module boundary with privacy.

Not to belabor the point, but...

> the only bullet-proof way to limit the scope of unsafe code is at the module boundary with privacy

I understand how this is meant in the context of that page, and it is true that modules protect against users messing with modules' internal invariants.

But does that also work the other way around? In the example in https://gankro.github.io/blah/only-in-rust/#unbound-lifetime... it's not the caller messing with the callee's state, it's the callee messing up the caller's state. Do modules help at all here? That is, would the function

    fn foo<'a>(input: *const u32) -> &'a u32 {
        unsafe {
            return &*input
        }
    }
become less dangerous, or maybe impossible to call, when put into a module?
I would argue that this is not the caller making the mistake; it's this function. That is, since this function is safe, any safe code should be able to call it and not generate UB. It's not the caller's fault here, it's the incorrect implementation.
> It's not the caller's fault here, it's the incorrect implementation.

I agree. But then this shows that it's possible to write "safe" Rust code that only calls "safe" external code and still (to a first approximation) have the possibility of undefined behavior showing up at any point. In other words, Rust's famous static, compiler-enforced guarantees are not guarantees at all, more like firm promises.

Nothing wrong with that; it's easy to write memory-corrupting code in other safe-by-default languages like Haskell or OCaml as well. But it seems like Rust's marketing materials do try to suggest otherwise, and many people get wrong impressions (look at the first post in this thread, and the other comments on this article saying that Rust's "safe" code is 100% free from undefined behavior).

I mean, safe code is. Again, it's the unsafe that's at fault here.

Your point about other languages is exactly what I was going to say; unsafe is like an FFI layer. Nobody says that Ruby isn't memory safe because it can call into C code, and if someone messes up the C, well, it's at fault. "It's memory safe except for FFI" is a mouthful, and so people generally let the exceptions slide. Same with Rust.