13 ms·
What I also think is weird is that people think seg faults and crashes are "unsafe". In the terms of Cardelli, a stack overflow is a trapped runtime error -- a
by chubot 3y ago
What I also think is weird is that people think seg faults and crashes are "unsafe".
In the terms of Cardelli, a stack overflow is a trapped runtime error -- and thus a SAFE behavior of a language runtime.
What's not safe is when your program keeps running in an unknown state:
- buffer overflows - who knows what it does after memory corruption?
- integer overflows, especially in C where the behavior isn't defined. But in Rust's release mode, these runtime checks are omitted, so that's unsafe too.
---
On the other hand, the behavior of null pointer exceptions and a stack overflows is SAFE. It protects you from undefined behavior at runtime.
Crashing is a DEFINED behavior -- it's also what happens on divide-by-zero by default, and apparently when Rust's allocators run out of heap memory.
This isn't a theoretical distinction, because diagnosing and fixing NPEs and stack overflows is easy compared to the other two.
And crashes can lead to denial of service, but not remote code execution, which is WAY worse.
- Someone 3y ago> On the other hand, the behavior of null pointer exceptions and a stack overflows is SAFE. For many languages only if the OS (sometimes with a bit of help from the runtime/ compiler) protects you against them. Not all language specs require programs to abort when they occur, if only because checking for them on systems without a MMU is expensive.
- btilly 3y agoI think that you're the weird one here. The most common reason to GET a segmentation fault is memory corruption. Frequently from a buffer overflow. Which makes them the canary in the coal mine for bugs that often turn out to be exploitable security vulnerabilities. So if a program segfaults on me and I don't know exactly why, I should dial my paranoia up and expect that it is insecure. That an attacker who looked at it could use it to take over my computer instead of simply leaving me with a core dump.
- astrange 3y ago> So if a program segfaults on me and I don't know exactly why, I should dial my paranoia up and expect that it is insecure. This is true in that the program contains at least one bug, but some memory errors are safer than others. A SIGBUS is safer than SIGSEGV (usually means you mmapped a file and got an I/O error reading it) and a read is safer than a write. This comes up if you're prioritizing crashes from fuzzing.
- chubot 3y agoInstead of stack overflow causing a crash, it could silently overflow into heap memory. Do you want that? What I'm saying is that crashes are the thing that PROTECT you from undefined behavior at runtime. --- If a C program crashes, then you might suspect memory corruption. But here's the thing: if it DOESN'T crash, you actually have NO less reason to suspect memory corruption! (This isn't theoretical, I'm certain that there are thousands or millions of C programs that have memory unsafety 100% of the time at runtime, especially in embedded systems.) If a Rust program crashes, would you suspect memory corruption? It could be, but it's still BETTER if it crashes 100% of the time than if it nondeterministically crashes. --- Do you think there are any other options besides crashing or silent undefined behavior?
- btilly 3y agoI agree that segmentation faults are the right thing to do in a bad situation. But the fact that we are in that bad situation says that there is a problem that we should worry about. As for memory corruption, you're right that nothing can ever prove that code has no memory corruption. But that doesn't stop crashing from being a pretty good signal that THIS program is experiencing corruption NOW. Which should raise our alert level. I don't have enough experience with Rust directly as opposed to C to have a great sense of how valuable this signal is for those programs. But then again the programs I see segfaulting all of the time tend to be C programs. So the problem is kind of moot.
- bombcar 3y ago> And crashes can lead to denial of service, but not remote code execution, which is WAY worse. Some crashes in the past have lead to remote code execution, because a program that was supposed to be guarding/filtering something was caused to die, and the system failed open.
- chubot 3y agoYeah that's an interesting consideration, but it's more of a systems design issue, outside the scope of what the C or Rust compilers and runtime can do anything about. (Or Python, JavaScript, etc.)
- EE84M3i 3y agoRust has a particular definition of unsafe that they've documented here: https://doc.rust-lang.org/nomicon/what-unsafe-does.html https://doc.rust-lang.org/nomicon/what-unsafe-does.html They have also documented some frequently discussed behavior that is not considered unsafe here: https://doc.rust-lang.org/reference/behavior-not-considered-unsafe.html https://doc.rust-lang.org/reference/behavior-not-considered-... For each of the items on the second list, I believe there are languages that would consider those behaviors "unsafe", but rust doesn't - ultimately it's an arbitrary choice. So, it's important to be clear about what model of "unsafety" we're talking about.
- chubot 3y agoYes definitely, which is why I mentioned Cardelli. Previous comment on the same subject: https://news.ycombinator.com/item?id=21832009 https://news.ycombinator.com/item?id=21832009 A program fragment is safe if it does not cause untrapped errors to occur. Languages where all program fragments are safe are called safe languages. Therefore, safe languages rule out the most insidious form of execution errors: the ones that may go unnoticed. -- Luca Cardelli It's certainly fine for Rust to have a keyword called "unsafe". But as you note, users should remember that this isn't equivalent to semantic safety. --- As a trivial example, integer overflow IS unsafe in Rust, but it's allowed WITHOUT using the unsafe keyword. Any language that traps integer overflow, regardless of debug/release mode is safer than Rust in that respect. Python is also safer than Rust in that respect, because it allows arbitrary sized integers. Rust made a tradeoff for efficiency, which is appropriate for its use cases, just like C did at the time. --- Programmers often use/abuse terms from computer science, which is perhaps OK when the difference doesn't have engineering consequences. Here it absolutely has consequences -- a crash is SAFE because it protects you from undefined behavior at runtime. Crashes are also easy to debug. I think the fallacy is that there's any other option. Many errors can't be caught at compile time, because they're simply incomputable problems. The mathematically BEST behavior is to crash. Related thread: https://old.reddit.com/r/ProgrammingLanguages/comments/tqtxfx/abstraction_not_what_you_think_it_is/i2kw2vc/ https://old.reddit.com/r/ProgrammingLanguages/comments/tqtxf... e.g. "Regular expression" was abused by programmers, and that one also has significant engineering consequences. O(n) time and O(1) space are desirable engineering properties. So if people let one definition of "unsafe" take over, then they've lost the ability to think clearly about the problem. There are languages that are safer than Rust now (e.g. Python), and there will likely be languages in the future that are both safer and more efficient. (Maybe Mojo if they do something different WRT bounds checking).
- MindSpunk 3y agoDereferencing a null pointer is safe only on systems with an MMU to mark the 0 page as inaccessible so the processor can trap when it's accessed. On embedded systems with no MMU then 0 is a valid address just like any other. By making null pointer dereference unsafe the compiler doesn't have to insert null checks for every single pointer access to maintain the same behavior as a CPU with an MMU.
- kobebrookskC3 3y agohow is integer overflow unsafe? integer overflow in rust is not ub, unless you opt into the *_unchecked methods