4 ms·
Undefined behavior is probably the worst way we can imagine to define constraints usable by optimizers. Sad that major languages and implementations went this w
by temac 4y ago
Undefined behavior is probably the worst way we can imagine to define constraints usable by optimizers. Sad that major languages and implementations went this way.
- Karellen 4y agoYeah, I think a lot of C's `undefined behaviour` semantics around assignments to ints should be reconsidered and changed to `unspecified` or `implementation defined` behaviour, and compilers can just do "whatever the hardware does". If that includes traps on one arch, fine, let it trap. I think `undefined behaviour` still has its place in C - dereferencing a freed pointer comes to mind as an obvious example - but I think a good proportion of the really unintuitive UB conditions could be made saner without sacrificing portability or optimisation opportunities.
- owl57 4y agoIf you extend "unspecified" to allow traps, reading a bogus pointer can also be unspecified, only writes undefined in the current sense.
- Karellen 4y agoI don't think so. With "unspecified" and "implementation-defiend" behaviours, the implementation has to pick a behaviour and be consistent with it. The difference is whether they have to document that behaviour or not. If the hardware traps on bogus pointers, then reading a bogus pointer may trap. But if you read a recently-freed pointer, it may still be valid according to the hardware (e.g. will have valid PTEs into the processes address space) so won't trap. Therefore you won't be able to guarantee any particular behaviour on an invalid read, so I don't think you'd be able to get away with "unspecified" or "implementation defined" behaviour on most hardware.
- owl57 4y agoAFAIR reading uninitialized int, for example, is "unspecified" (any value could be there). If we consider adding "implementation defined with possible trap" for overflow, we might as well add "unspecified with possible trap" for reading an invalid pointer (any value could be there, or it could trap, but no nasal demons).
- temac 4y agoUsing unitialized values is UB. Going back to naive pointers is a lost cause because compilers have started to do crazy optims (not even currently allowed by the standards...) like origin analysis. You can't steal that toy from the people implementing optims.
- UncleMeat 4y ago"Implementation defined" is worse in a lot of ways. Now the compiler has way less authority to tell you to stop! And we still have the problem of the application probably not doing what you want.
- temac 4y agoCurrent compilers don't "tell you to stop". They silently transform your program into complete garbage without even causality restraints. The sanitizers can help but they are merely dynamic when the dangerous tranformations are static in the first place.
- UncleMeat 4y agoIt is true that the language has failed to provide tools that help developers prevent UB and that this is a very bad thing for the ecosystem. It can change, though. In practice, compilers aren't actually adversarial. A lot of the discussion around UB is catastrophizing and talks about how the compiler will order you pizza or delete your disk. Some problems are real and I know some people whose graduate school work was very specifically on the problems that this causes for security-related checks but compilers really really do not transform your program into "complete garbage." They transform your program into a program with a bug, which is a true statement about that program. I'm reminded of the apocryphal story about being asked how a computer knows how to do the right thing if given the wrong inputs. This feels similar.
- Karellen 4y agoNot apocryphal: > On two occasions I have been asked, — "Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?" In one case a member of the Upper, and in the other a member of the Lower, House put this question. I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. -- Charles Babbage https://en.wikiquote.org/wiki/Charles_Babbage#Passages_from_the_Life_of_a_Philosopher_(1864) https://en.wikiquote.org/wiki/Charles_Babbage#Passages_from_...
- UncleMeat 4y agoI do agree that the story around UB in C and C++ sucks. But UB doesn't exist because the compiler engineers want to be able to stick in optimizations. Once they are in the spec it makes sense to follow the rules but most UB comes from a desire for portability and to not privilege one platform over another. And further, defining a lot of UB won't actually improve things. Imagine we define signed integer overflowing behavior. Hooray. Now your program just has a different bug. If you've accidentally got signed integer overflow in your application then "did some weird things because the compiler assumed it would never overflow" is going to cause exactly the same amount of havoc as "integer overflowed and now your algorithm is almost certainly wrong."
- nayuki 4y ago> And further, defining a lot of UB won't actually improve things. Imagine we define signed integer overflowing behavior. Hooray. Now your program just has a different bug. This is exactly what JF Bastien argues in his hourlong talk: https://youtu.be/JhUxIVf1qok?t=2284 https://youtu.be/JhUxIVf1qok?t=2284 So yeah, defining signed integer overflow isn't going to fix bugs in the vast majority of existing programs. That being said, enforcing signed overflow wraparound at least makes debugging easier because it's reproducible. This is how it is in Java land - int overflow wraps around, and integer type widths are fixed, so if you trigger an overflow while testing then it is reliably reproducible across all conforming Java compiler and VM versions and platforms.
- UncleMeat 4y agoIt also makes tools less able to loudly yell at you for having it in your application. Yes, you can turn on optional warnings if you want but if you've got one or two intended uses for this behavior then now you need suppressions and all sorts of mess.