I'm not saying developers who are careful about UB aren't doing the right thing. They are absolutely doing the right thing.
What I am saying is that a compiler that sees
int8_t x;
float x;
and does anything other than "terminating a translation or execution (with the issuance of a diagnostic measure)" is doing the wrong thing.
I am also saying that a compiler that offers -fwrapv and formats your hard drive on int x = INT_MAX; x++; rather than "behaving during translation or program execution in a documented manner characteristic of the environment" is pathological, violates the spirit of the ANSI and ISO standards, and violates the letter of the ANSI standard.
You may not like it, and it’s within your rights not to like it, but the reality is that compilers do treat UB this way, and it’s not “grossly dishonest FUD” to point out that this is the reality. Here’s a test case demonstrating that UB can actually format your hard drive: https://bugs.llvm.org/show_bug.cgi?id=49599.
Note that one of the differences between C and Rust is that integer overflow is not UB in Rust (it panics in debug mode and wraps in release mode: https://doc.rust-lang.org/book/ch03-02-data-types.html#integ...). But there are other sources of UB in unsafe Rust, such reads through a pointer not allowed by the memory model.
Clang will not blow your computer up just because you use #pragma STDC FENV_ROUND <direction> in accordance with its documentation.
I don't know why it became popular to make UB into a bogeyman and act like it's an intractable problem, but it isn't. Compilers handle most UB just fine.* It's better for everyone if we can focus on the actual problems rather than blowing it out of proportion with sweeping generalizations.
* All undefined behavior is undefined, but some undefined behavior is more undefined than others.
It seems like you think I’m saying that all compilers are required to recognize all forms of UB and format your hard drive. Of course not; some UB in one specification may be defined in another more restrictive spec, some UB may be defined by compiler flags like -fwrapv, some UB might be detected and converted to a compile-time or runtime error, and some UB might happen to behave like you expect because your compiler didn’t implement certain optimizations yet or you just got lucky.
It sounds like you agree that programmers should avoid relying on luck for UB safety. If you have a way to prove that this UB is actually safe and not just lucky, feel free to present it. Until then, I stand by everything I’ve said.
No. I am saying that the tropes about the danger of undefined behavior apply only to a subset of undefined behavior.
It isn't true to say that "any undefined behavior" can result in a parade of horribles. That is a sweeping generalization. Huge amounts of undefined behavior are in fact well-defined by the implementation and/or environment.
Indeed, the formal definition of "implementation-defined" is so narrow that most of what you'd think should be "implementation-defined" is actually "undefined." The example I gave of realloc(ptr, 0) is one such case. "Classifying a call to realloc with a size of 0 as undefined behavior would allow POSIX to define the otherwise undefined behavior however they please." WG14 n2464, available at https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf
If a program’s behavior is undefined in one specification and defined in a second, then insofar as both specifications apply to it, that is defined behavior, not undefined behavior. That’s not an obscure property of terms of art and specific formal definitions about which I need to be educated, it’s just basic logic about which we obviously agree. The conclusion would be the same if one specification explicitly said “this may return an empty allocation or NULL or format your hard drive” and a second specification said “this will return an empty allocation or NULL”; the conjunction of those two specifications entails that it will not format your hard drive.
There’s nothing wrong or misleading in what I wrote. If, hypothetically, there were a second specification that constrained the Rust compiler’s translation of programs that over-read memory, then it would have been wrong to write that over-reading memory in Rust is undefined behavior, and misleading to suggest that a statement about “any undefined behavior” is applicable to it. But there is no such second specification (as confirmed by comments on the issue I linked from RalfJung, whose formal specification hat is much pointier than either of ours), and you aren’t even disputing that. Instead, you have deliberately misapplied a statement about “any undefined behavior” to other unrelated behavior that is in fact defined, in order to construct a pretense for calling someone else dishonest. Find better hobbies.
No. Undefined behavior means one thing and only one thing, at least when it comes to C: "behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements"
There's no such thing as "insofar as both specifications apply to it, that is defined behavior, not undefined behavior." Undefined behavior in C that is standardized by POSIX is still undefined behavior. Indeed, that is why "Possible undefined behavior [includes] behaving during translation or program execution in a documented manner characteristic of the environment." Behaving according to the POSIX specification on a POSIX system (or according to the specification of any system on that system) is explicitly accounted for in the definition of "undefined behavior."
These things are objectively, inarguably true, and recorded in black and white. I do not understand why you are so relentless in trying to gaslight HN about them. Just stop.
When the term “undefined behavior” appears within the C standard, yes, that’s what it means. There is no way for another document to alter the meaning of “undefined behavior” as it appears within the C standard.
When the term “undefined behavior” appears in different context, we use our writing and reading comprehension skills to agree on what it means. If we’re programming in standard C, it refers to one class of behavior. If we’re programming in POSIX C, it refers to a smaller class of behavior (even according to the C standards committee: see the usage of “otherwise undefined behavior” in N2464). If we’re programming in Rust, it refers to a completely different class of behavior.
From my very first message, I did my part by providing the context explicitly: “undefined behavior in the Rust and LLVM memory model”. You complained that it’s nonsense to talk about “undefined behavior” in any context other than the C standard, but I provided references showing that it’s not. Yet you persist in intentionally misinterpreting what I wrote in order to accuse me of gaslighting. Does that make you feel superior?
What I am saying is that a compiler that sees
and does anything other than "terminating a translation or execution (with the issuance of a diagnostic measure)" is doing the wrong thing.I am also saying that a compiler that offers -fwrapv and formats your hard drive on int x = INT_MAX; x++; rather than "behaving during translation or program execution in a documented manner characteristic of the environment" is pathological, violates the spirit of the ANSI and ISO standards, and violates the letter of the ANSI standard.