News for hackers. Stuff that matters.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by userbinator on Sunday July 14, 2019 @04:44PM (#20435877)
When K&R invented C, and when ISO/ANSI standardised C, I don't think this is at all what they had in mind for UB. Whenever discussions like this come up, I like to quote the C standard itself on its definition:

"NOTE: Possible undefined behavior ranges from [...] to behaving during translation or program execution in a documented manner characteristic of the environment"

The whole point of C as K&R and ISO is to let you do "what the hardware does". They left parts of the standard purposefully undefined, so it could remain applicable to a wide variety of implementations. The intention was definitely NOT "screw the programmer" as a lot of the compiler writers seem to have interpreted it, but to allow them to do something that makes sense for the environment.

Now we have, mostly academics from what I've noticed, that are taking the language farther and farther away from reality; focusing only on something uselessly abstract, completely ignoring the practical consequences of what they're doing. Compilers are becoming increasingly hostile to programmers. A programming language that had humble and very practical uses, with straightforward and easily understood behaviour, has been perverted into theoretical quagmire of uselessness.

Something very very odd is going on, and I don't like it one bit. It's very WTF-inducing.

(I don't know much about Rust, hence why I didn't say anything about it. But I've been using C since the late 80s.)

Re:“What the Hardware Does” Is Not What Your Program Does: U... by nothrabannosir on Sunday July 14, 2019 @05:03PM (#20436005)
This is driven by programmers' insatiable thirst for performance. Compiler writers are constantly judged on benchmarks, and the only way to squeeze that last flop out of a piece of code is to take the specification to its extreme.

UB is always about optimisations and performance. Incidentally, this is why I don't think talking about "nasal demons" is productive. The compiler mostly just uses UB to assume: ah, this can't happen, so I can optimise it away. Often that means valid programs go faster. We wanted it: we got it.

From my limited experience (and it's been a while), -O0 (no optimisations) is really quite reliable, even if you do all kinds of UB shenanigans.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by naniwaduni on Sunday July 14, 2019 @05:11PM (#20436062)
> This is driven by programmers' insatiable thirst for performance. Compiler writers are constantly judged on benchmarks, and the only way to squeeze that last flop out of a piece of code is to take the specification to its extreme.

Really? I've seen people switch between competing compilers for licensing reasons, platform support, features---but benchmark performance? Maybe blog posts suggesting that a new compiler wasn't ready.

Compiler writers judge themselves on benchmarks.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by closeparen on Sunday July 14, 2019 @06:56PM (#20436795)
Competitive performance for your workload is basically the reason you would buy Intel's compiler, right?
Re:“What the Hardware Does” Is Not What Your Program Does: U... by mhh__ on Sunday July 14, 2019 @06:39PM (#20436704)
It might not be true now because LLVM and GCC can generally put a commercial compiler 6 feet under, but if you're paying for a compiler you'd definitely want to choose the one that delivers the best performance (Money being no object)

No idea whether ICC is still worth paying for

Re:“What the Hardware Does” Is Not What Your Program Does: U... by userbinator on Sunday July 14, 2019 @07:02PM (#20436822)
No idea whether ICC is still worth paying for

From my experience, ICC is far more reluctant to exploit UB, yet still generates very good code.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by saagarjha on Monday July 15, 2019 @02:16AM (#20438562)
ICC exploits the standard itself: it generates code that is technically incorrect.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Monday July 15, 2019 @03:20AM (#20438784)
What do you mean?
Re:“What the Hardware Does” Is Not What Your Program Does: U... by saagarjha on Monday July 15, 2019 @03:31AM (#20438830)
As Patrick mentions, ICC generates code that doesn't follow IEEE-754: https://news.ycombinator.com/item?id=20437375 (I should have mentioned I was talking about that rather than the C standard).
Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Monday July 15, 2019 @03:35AM (#20438855)
Oh I see, you're talking about floating point.

So basically ICC has -ffast-math (or -funsafe-math-optimizations) on by default, and you can turn it off with an explicit flag?

I see this as more of a philosophical difference than a material one since you can just add or remove the flag on either one...

Re:“What the Hardware Does” Is Not What Your Program Does: U... by dllthomas on Sunday July 14, 2019 @07:09PM (#20436866)
IME, benchmarks aren't enough of an impetus to move between compilers, but are often a not-insignificant piece of what's considered when moving is otherwise motivated.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by SamReidHughes on Monday July 15, 2019 @03:32AM (#20438833)
For C++, compilation time performance is the benchmark. At least it's why I started using clang.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by xeeeeeeeeeeenu on Monday July 15, 2019 @02:25AM (#20438582)
>This is driven by programmers' insatiable thirst for performance. Compiler writers are constantly judged on benchmarks, and the only way to squeeze that last flop out of a piece of code is to take the specification to its extreme.

Ironically, strict aliasing rule (which is one of the most common causes of UB) makes writing fast programs much harder, because it forbids type punning (except via memcpy or unions).

BTW, according to WG14 mailings and minutes, the C committee is considering either relaxing it or creating a standard way to suppress it in C2X. I can't wait for it.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by saagarjha on Monday July 15, 2019 @03:05AM (#20438725)
Writing fast programs while keeping the strict aliasing rule in mind isn't all that hard: compilers know the semantics of memcpy and can optimize your use to what it's "supposed to be in assembly".
Re:“What the Hardware Does” Is Not What Your Program Does: U... by dagenix on Sunday July 14, 2019 @09:28PM (#20437439)
> When K&R invented C

Brian Kernighan didn't invent C, he co-authored a book about it.

> Whenever discussions like this come up, I like to quote the C standard itself on its definition: "NOTE: Possible undefined behavior ranges from [...] to behaving during translation or program execution in a documented manner characteristic of the environment"

The actual quote is: "NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message)." - but you snipped out the part that contradicted your point.

> The whole point of C as K&R and ISO is to let you do "what the hardware does". They left parts of the standard purposefully undefined, so it could remain applicable to a wide variety of implementations. The intention was definitely NOT "screw the programmer" as a lot of the compiler writers seem to have interpreted it, but to allow them to do something that makes sense for the environment.

This seems to be contradicted by the full quote above: "ignoring the situation completely with unpredictable results" does sound like it's going to "make sense for the environment". It's also pretty inflammatory to say that the intention of a compiler author is to "screw the programmer".

> Now we have, mostly academics from what I've noticed, that are taking the language farther and farther away from reality; focusing only on something uselessly abstract, completely ignoring the practical consequences of what they're doing. Compilers are becoming increasingly hostile to programmers. A programming language that had humble and very practical uses, with straightforward and easily understood behaviour, has been perverted into theoretical quagmire of uselessness.

So, the "academics" are making compilers "hostile to programmers" and perverting the language into a "theoretical quagmire of uselessness"? That's nonsensical anti-academic garbage unsubstantiated by fact.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by lmm on Sunday July 14, 2019 @05:23PM (#20436144)
> Now we have, mostly academics from what I've noticed, that are taking the language farther and farther away from reality; focusing only on something uselessly abstract, completely ignoring the practical consequences of what they're doing. Compilers are becoming increasingly hostile to programmers.

I don't think it's the academics, it's the compiler implementers - driven by wanting to win at benchmarks. Our industry is absurdly focused on "performance" over all else (even correctness). But then again, those who care about other things moved on to non-C languages years or decades ago.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by roca on Sunday July 14, 2019 @06:03PM (#20436445)
Indeed, it's compiler implementors, not academics.

However, the performance impact of optimizations that take advantage of UB is not known, and is potentially very large. It would be a very interesting experiment to modify a C/C++ compiler so that every C/C++ program has defined semantics in terms of a simple array-of-bytes abstract machine, and see how much slower the generated code is compared to the regular compiler.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by userbinator on Sunday July 14, 2019 @06:46PM (#20436750)
It would be a very interesting experiment to modify a C/C++ compiler so that every C/C++ program has defined semantics in terms of a simple array-of-bytes abstract machine, and see how much slower the generated code is compared to the regular compiler.

Alternatively, look at compilers like Intel's ICC --- it has historically been one of the best at code generation, yet it's not known for having anywhere near the same level of UB-craziness as Clang (or GCC, to a lesser extent). The same has been my experience with MSVC, at least the earlier versions.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by pcwalton on Sunday July 14, 2019 @09:14PM (#20437375)
On the contrary, ICC doesn't even implement IEEE 754 correctly by default [1], for performance. This is way more aggressive than GCC or Clang.

[1]: https://hal.archives-ouvertes.fr/hal-00128124v5/document

Re:“What the Hardware Does” Is Not What Your Program Does: U... by BeeOnRope on Sunday July 14, 2019 @11:39PM (#20437946)
Uh, ICC does some crazy things to get some of its performance, such as making transformations not allowed by the standard (inventing writes), in order to get better vectorization.

So in some respects ICC is very aggressive.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by gameswithgo on Sunday July 14, 2019 @06:10PM (#20436515)
our industry mainly uses javascript, we aren’t focused on performance at all
Re:“What the Hardware Does” Is Not What Your Program Does: U... by wvenable on Monday July 15, 2019 @01:33AM (#20438396)
Yet the C/C++/ASM in JavaScript runtimes are heavily optimized for performance.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by saagarjha on Monday July 15, 2019 @12:53AM (#20438239)
Compiler implementers are often academics, or at least a lot likely to be higher on the ivory tower than their users are.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by ralfjung on Monday July 15, 2019 @06:58AM (#20439593)
Which major compiler is mostly implemented by academics? Neither GCC nor LLVM, for sure.

Us academics do have a lot of "fun" figuring out a way to put what the compiler developers do on solid footing [1]. But this is a game of whack-a-mole that will never end: each time we find a way to formally approach some new crazy optimization they came up with, and help them weed out all the bugs that were caused by not carefully thinking through all the implications [2], the next crazy optimization comes up [3].

[1]: https://people.mpi-sws.org/~jung/twinsem/twinsem.pdf

[2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65752, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82282, https://bugs.llvm.org/show_bug.cgi?id=35229, https://bugs.llvm.org/show_bug.cgi?id=34548

[3]: https://bugs.llvm.org/show_bug.cgi?id=21725, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57359

Re:“What the Hardware Does” Is Not What Your Program Does: U... by roblabla on Sunday July 14, 2019 @05:17PM (#20436098)
Rust is in a very different situation though. Safe Rust has no undefined behavior - if something is behaving in an unsound manner, then that's a compiler bug.

Safe Rust does have some implementation-specific behavior - for instance, panics can either unwind or abort.

In Unsafe Rust, all bets are off, and the programmer may trigger Undefined Behavior if they're not careful. The upshot is that it's easier to maintain the compiler's invariants because you only need to be careful in a single place about making sure everything is in order. By clearly marking places where the programmer is in charge of maintaining the invariants instead of the compiler, the hope is that mistakes will be minimized (thanks to careful code review and making the programmer think a lot about what they're writing).

Further helping with that, the goal is to have tools to help catch UB at runtime. For instance, miri is an interpreter for MIR (an intermediate language between rust and the LLVM IR) that checks for UB.

I agree that in C, UB has probably be stretched way beyond its intended purpose. But in Rust, this new definition of UB is taken advantage of in much less WTF-inducing ways, allowing us to enjoy those performance guarantees without losing our minds.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Sunday July 14, 2019 @05:57PM (#20436402)
The "[...]" you deliberately omitted explicitly permits "ignoring the situation completely with unpredictable results".
Re:“What the Hardware Does” Is Not What Your Program Does: U... by jschwartzi on Sunday July 14, 2019 @06:56PM (#20436797)
I would interpret that to mean that if memory is uninitialized to a specific value and you're working in a physical rather than virtual address space, then a read from some random pointer to uninitialized data might return an unpredictable value, such as the value of a GPIO register or a word from an RS-232 buffer. There's clearly a defined behavior for that specific platform.

And when they're talking about doing something hardware-specific I would take that to be about the MMU on certain platforms. Platforms with an MMU and where the processor is executing code in a virtual address space can generate an access violation if the program code reads data at a virtual address that is not mapped to a specific segment of physical memory.

Even when a program runs in a physical address space, the processor may be configured with an address space that is significantly larger than the actual block of memory and registers on the memory bus. And this matters because if you have a 32-bit processor but the upper 3 gigabytes of the address space don't map to a register file or RAM then it's hardware-dependent what happens when you read from those addresses.

Some hardware will roll the map over and read from somewhere in the available section of the address space based on the offset, and some hardware will treat that as an error which triggers an access violation. Some hardware will bug out and do something completely unexpected. It's undefined behavior what happens in this case. It has everything to do with how your specific chip, mainframe, or minicomputer is wired. And that's what they're referring to.

Undefined behavior does not mean "do whatever you want," it means "do what the hardware would probably do in this situation, or do whatever can be reasonably expected." And that's important here because that means that UB is not carte blanche to violate the programmer's expectations here.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Sunday July 14, 2019 @08:03PM (#20437098)
As far as the standard's goes, you're interpreting undefined behavior to mean unspecified behavior -- behavior that's well-defined, but whose definition "depends on the implementation" (in this case, your hardware). I mean, I can't stop you if you want to read it that way, but you're literally interpreting it to mean exactly what they did not intend it to mean... that's why they chose separate terms and explicitly told you undefined behavior is allowed to be unpredictable, rather than being required to be implementation-dependent.

But let's ignore the standard... who cares what it says...

The thing is, what you're asking for inhibits optimizations that many people would very much like to see from their compilers. Like for example if you have an uninitialized function pointer that you only assign to in 1 or 2 locations -- the compiler should be able to just replace the indirect function calls with direct function calls. You're demanding that it doesn't do that, and that it simply call whatever function or non-function that pointer happened to point to. I mean -- you're welcome to ask for that, and maybe your compiler should have a flag to make it behave that way (or maybe it does already? do you use it if so?), but to me and many other people, the compiler should obviously be permitted to see right through that.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by nkurz on Sunday July 14, 2019 @09:23PM (#20437416)
> You're demanding that it doesn't do that

Rather than telling someone what they are demanding, it's often better to ask them --- especially if you are sure that what they are demanding is stupid. Personally, I'd guess that 'jschwartzi' might be fine with a compiler that makes the optimization you refer to, and is instead objecting to a compiler that deletes essential safety checks in other parts of the program on the assumption that all bets are off once "undefined behavior" can be proven to occur. If he's like me, he'd probably also prefer that the compiler issue a warning about the undefined behavior rather than silently making changes to the program. But better to ask him than to guess.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Sunday July 14, 2019 @09:44PM (#20437514)
I don't think it's a stupid demand at all -- like I said, I have nothing against implementations behaving more nicely if they wish. I'm just saying that this is an extra demand, not an interpretation of the standard, and that it would have performance repercussions which many C users would rather avoid.

In the case of your safety check example, it'd be nice if you could mention something concrete so we know exactly what situation you're talking about. But I mean, I can't rule out that maybe you'll find a couple situations here and there where the standard shouldn't leave things undefined. But the argument I'm rebutting here is that all instances of UB must behave "like the hardware", not that this particular instance is good but another one is bad, so I'm not sure you two would agree. I agree warnings would be nice too (some of which already exist), and I think despite their current efforts compiler still have some ways to go (e.g. a macro expanding to 0 should probably not behave the same as the literal 0 when you multiply, say, by a constant), but again, that's already assuming you're fine with UB...

Re:“What the Hardware Does” Is Not What Your Program Does: U... by tsimionescu on Monday July 15, 2019 @01:13AM (#20438312)
> In the case of your safety check example, it'd be nice if you could mention something concrete so we know exactly what situation you're talking about.

There are some well-publicised cases of compilers removing NULL-checks[0] on the assumption that the NULL value can't occur as it would be UB.

As another example, the Linux kernel assumes in several places that signed integer overflow wraps, so it is compiling with -f-no-strict-overflow/-fwrapv ever since GCC started optimizing based on this piece of UB (they noticed the compiler behavior change and added the flags before releasing any faulty kernels though, apparently).

[0] https://lwn.net/Articles/342330/

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Monday July 15, 2019 @03:07AM (#20438733)
I know about that NULL check example, but the thing is, the compiler is being pretty reasonable there. The fact that the pointer is dereferenced means that the NULL check was useless: if the address is NULL, then the NULL check can never be reached because you'd have already segfaulted (your beloved hardware behavior!) on the dereference earlier. [1] So that code is dead, and needs to be removed. The fact that the dereferenced variable is unused means that the compiler needs to eliminate that too.

People want these optimizations individually. They don't want to keep dead code taking up cycles and they also don't want dead variables taking up registers. So you can't really find much support arguing that those optimizations should be removed entirely. The only real possibilities you can propose here are that the compiler should have magically re-inserted the pruned check during the second optimization, or that it should have performed them in the opposite order. But are you sure these are actually possible and if so, practical? I mean, maybe they are, but they are far from obvious to me. I can easily see the compiler thrashing and failing to reach a fixed point if it re-inserts code that a previous optimization pass pruned. Similarly, I don't see how the compiler can just magically detect an optimization order that ensures "surprising" situations like this don't occur. My guesstimation is that it would carry severe downsides people wouldn't want. Now maybe I'm just not smart enough to see a good solution to this that doesn't carry significant downsides, and there's already one out there. If there is, I'm curious to hear about it, and I hope someone implements it under some flag, but I have yet to hear of one.

For signed integer overflow -- that might be one place where I think it would make sense to just define it to either wrap with 2's complement just like unsigned integers do, or to be unspecified behavior that falls back to the implementation's representation. Though in the latter case... you already have an implementation-specific solution: your compiler flags. But again, we might agree on a couple optimizations here and there, but that's a far cry from saying UB should just fall back to hardware behavior. And honestly, I'm not even here supporting C; I hate it. If you want wrapping, I would suggest it's a sign you might want to use C++ already. Then you can define an integer type that will play Beethoven when you overflow, and people who want their UB on overflow can have that too.

[1] I'm ignoring the validity of address 0 in kernel-mode here; there's also some subtleties on what's a null pointer and what's address zero that are rather beside my point.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by simiones on Monday July 15, 2019 @07:26AM (#20439749)
I think that everyone agrees that NULL checks should be elided when the compiler can prove that they are useless. However, I think most people assume that the way for the compiler to prove that would be "when it sees that the variable has a non-NULL value" - e.g. `int v = 0; int *p = &v;`.

That's the sort of thing I would suggest - don't work back from UB (and I agree, I wouldn't expect the optimizer to backtrack optimizations as new facts come up), work forward from actually known facts.

NULL checks are probably a pretty bad example, since the NULL access would surely SEGFAULT if allowed to execute (though the particular case of address 0 vs NULL, and of code catching segfaults like on Windows, throw a wrench in this assumption eve here), but other types of UB are much worse.

If you accidentally issue a read from a point after the end of an array, but only later check that the index was within bounds (e.g. `int x = a[i]; if i < len(a) return x; else return NULL`), the compiler eliding the bounds check by the same logic will take a program that might have been safe in practice to a program that is certainly not safe. Note that I don't know if compilers perform this type of optimization, so this may be a hypothetical.

In general though, I think that the tension here comes from C being used in 2 very different use cases: 1 is C used as portable assembly, where you expect the compiler to keep a pretty 1:1 mapping with your code; and the second one is C used as the ultimate performance language, where you drop to C when you can't optimize further in anything else. I think most of the complaints about "exploiting UB" come from the first camp, whereas the second camp is pretty happy with the current status quo.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Monday July 15, 2019 @08:16AM (#20440062)
I think you're focusing so much on particular examples you're missing the larger point. To repeat what I've said repeatedly I'm not defending every single instance of UB in the standard. And I can't keep going back and forth with you to to debate every single one (yes, int overflow = no UB, NULL deref = yes UB, out-of-bounds = maybe UB, etc.), which is what we're ending up doing rather pointlessly right now. The point to take away here is that UB itself as a notion is something people in both camps desire in many scenarios, so you can't just get rid of it in its entirety and say "map it to hardware" or "always reason forward". Because, again, if you do, in many cases, those would inhibit optimizations that people want. The only real solution is for people to stop seeing C as a portable assembly language, which it is simply not. It's defined in terms of an abstract machine, so either people need to switch languages, or switch their mental models.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by BeeOnRope on Sunday July 14, 2019 @11:44PM (#20437969)
I don't think emitting a warning is feasible in most cases. The compiler (generally) doesn't know at compile time that UB definitely occurs, only that in some UB exists on some path that may or may not be reachable in theory or practice.

Usually these are not reachable in practice so warnings that these exist would cause a tidal wave of pointless warnings. Instead, the compiler simply prunes those paths which can lead to better code generation for the paths that are taken.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by taneq on Sunday July 14, 2019 @07:51PM (#20437042)
What would nasal demons be if not "ignoring the situation completely with unpredictable results"?
Re:“What the Hardware Does” Is Not What Your Program Does: U... by mpweiher on Sunday July 14, 2019 @06:49PM (#20436765)
Yeah, for example just reading beyond the array bounds.

What current compilers do is about as far away from “ignoring the situation completely” as it is possible to get.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Sunday July 14, 2019 @06:56PM (#20436796)
Depends how you look at it. They don't ignore it during translation but that's because they work hard to make the program "ignore it completely" (i.e., not spend a single cycle on the possibility) during execution.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by mpweiher on Monday July 15, 2019 @06:04AM (#20439378)
(a) That's not what the text says.

(b) What compilers are doing does not match "ignore at execution", because they also use it to remove completely separate code.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Monday July 15, 2019 @06:16AM (#20439414)
If stripping code whose only relevance is in a UB situation doesn't amount to ignoring the UB situation completely, I don't know what does. It's literally the production of code that is completely ignorant of the UB situation.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by mpweiher on Monday July 15, 2019 @01:43PM (#20443258)
If that were what it does, I'd agree.

It isn't.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by mehrdadn on Monday July 15, 2019 @01:46PM (#20443287)
If you could give an example to actually illustrate what you mean, maybe I'd agree too, but it's a little tough when you don't...
Re:“What the Hardware Does” Is Not What Your Program Does: U... by pcwalton on Sunday July 14, 2019 @09:27PM (#20437435)
The undefined behavior exploitation that compilers do is entirely reasonable and not something that we should go back on. Defining overflow as wrapping, for example, would be bad for security because it means we couldn't check it with UBSan.

Rather than rehashing the same arguments I've made over and over, I'll just link to parts of a Twitter thread where Daniel Micay argues eloquently that keeping the sources of UB that we have today as they are is important:

https://twitter.com/DanielMicay/status/1118017342644998144

https://twitter.com/DanielMicay/status/1118034688935747584

Re:“What the Hardware Does” Is Not What Your Program Does: U... by tylerhou on Sunday July 14, 2019 @10:11PM (#20437624)
> Defining overflow as wrapping, for example, would be bad for security because it means we couldn't check it with UBSan.

You could always write “WrapAroundSan”.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by pcwalton on Sunday July 14, 2019 @10:43PM (#20437738)
The problem is that if you did that then you couldn't check regular C programs anymore, since overflow would be valid. Right now we're in the nice situation in which normal C programs are expected not to exhibit signed overflow. Change that state of affairs and suddenly a lot of obvious mistakes become valid.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by userbinator on Monday July 15, 2019 @07:25AM (#20439744)
The problem is that if you did that then you couldn't check regular C programs anymore, since overflow would be valid.

That also means it's possible to write overflow checks easily, and ones that the compiler won't optimise out. Before compilers became UB-crazy, you could write such checks in the most straightforward way, and get exactly what you expected. I'd consider that a far bigger advantage for security than arguing for the existence of a tool whose sole reason for existence seems to be due to the presence of UB in the first place.

Re:“What the Hardware Does” Is Not What Your Program Does: U... by ralfjung on Monday July 15, 2019 @07:04AM (#20439625)
You could always say that wrap-around has to either (a) cause SIGILL or (b) return the wrapped-around result. That still allows linting with a sanitizer without involving any UB at all.

This is effectively what Rust does (replace "SIGILL" by "panic").

Re:“What the Hardware Does” Is Not What Your Program Does: U... by enedil on Monday July 15, 2019 @01:17AM (#20438325)
This isn't the reason why signed overflow is UB in C.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by saagarjha on Monday July 15, 2019 @02:19AM (#20438571)
As far as I can tell, signed overflow is undefined behavior because when the standard was defined there were a lot of machines where it would trap or do something weird, and for some reason the standards authors did not choose to make it implementation-defined behavior.
Re:“What the Hardware Does” Is Not What Your Program Does: U... by jcelerier on Monday July 15, 2019 @02:36AM (#20438621)
> Defining overflow as wrapping, for example, would be bad for security because it means we couldn't check it with UBSan.

no, because unsigned overflow is valid and yet ubsan is able to check for it with -funsigned-integer-overflow (and I caught so many bugs like this)

Re:“What the Hardware Does” Is Not What Your Program Does: U... by ralfjung on Monday July 15, 2019 @06:50AM (#20439555)
UB has [developed a lot][1] since then. Now UB is a way for the programmer to help the compiler generate better code by providing extra information that is hard for the compiler to prove itself. I think, in general, this is actually an ingenious idea (I have [written about this][2] in the context of Rust before). But it can surely be taken too far, and it is particularly a problem when the programmer is not aware of the promises they are making. This is more an API design problem though than a fundamental problem with UB itself.

[1]: https://raphlinus.github.io/programming/rust/2018/08/17/unde...

[2]: https://www.ralfj.de/blog/2017/07/14/undefined-behavior.html

Re:“What the Hardware Does” Is Not What Your Program Does: U... by frutiger on Sunday July 14, 2019 @06:22PM (#20436581)
> When K&R invented C

Side note, Kernighan (of K&R) did not have any part in the invention of C, it was all Dennis Ritchie. Kernighan famously wrote the book on it with Ritchie but that was it.

In his own words[1]:

> remember, C is entirely the work of Dennis Ritchie, I am but a popularizer

1. https://www.cs.cmu.edu/~mihaib/kernighan-interview/

Re:“What the Hardware Does” Is Not What Your Program Does: U... by noobermin on Monday July 15, 2019 @04:25AM (#20439017)
While I agree with you, it is true that C of the K&R days doesn't exist anymore because computers are no longer like PDP-11s. This bookmark of mine is under "importantkeep"[0] (also cited in the article).

I agree though, the moment abstract machines distract from actually creating something is the moment one has gone too far.

[0] https://queue.acm.org/detail.cfm?id=3212479

Re:“What the Hardware Does” Is Not What Your Program Does: U... by ralfjung on Monday July 15, 2019 @07:06AM (#20439632)
IMO the real machines are much more distracting than the abstract ones. ;)
Re:“What the Hardware Does” Is Not What Your Program Does: U... by jjoonathan on Sunday July 14, 2019 @09:38PM (#20437485)
Yes! The GPL says that GCC is provided on an

> "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, ... FITNESS FOR A PARTICULAR PURPOSE.

which would permit the GCC steering committee to decide tomorrow that every other statement must be "HAIL SATAN;" or your code won't compile.

Of course, "can" doesn't mean "should," and if they actually did it, it wouldn't say anything particularly deep about the GPL being a bad license, it would merely indicate that the GCC steering committee had become untrustworthy, and that the community should act accordingly.

Undefined behavior is exactly analogous. It was a degree of freedom designed to allow compiler writers to smooth over CPU architecture friction back in a time when the CPU architecture scene was far less settled than it is now. Trust and responsibility were always understood to be necessary components to make it work. The fact that trust can be broken isn't deep, isn't surprising, and isn't a failure of C.

If C compiler writers want to use UB as an excuse to abuse the trust they have been given, that's on them. I am moving away from C, for many reasons, but the UB-related reason has very little to do with UB being inherently evil and very much to do with the fact that it seems to be placed in increasingly irresponsible hands.