3 ms·
> 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
by tom_mellior 9y 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-lifetimes 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.
- adrianN 9y agoThe 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.
- tom_mellior 9y ago> 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.
- steveklabnik 9y agoSee also https://doc.rust-lang.org/nomicon/working-with-unsafe.html 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.
- tom_mellior 9y agoNot 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-lifetimes 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?
- steveklabnik 9y agoI 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.
- tom_mellior 9y ago> 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).
- steveklabnik 9y ago