4 ms·
> Over the last decade have increasingly abused this idea basically making the spec a land mine of UB and then claiming that UB allows them to do whatever they
by xenadu02 8y ago
> Over the last decade have increasingly abused this idea basically making the spec a land mine of UB and then claiming that UB allows them to do whatever they want, even when the programmer intent is obvious.
That is not an accurate or fair assessment.
However signed integer overflow being undefined behavior is a bit over the top given modern hardware. I'd like to see the C standard adopt a policy of wrapping for signed overflow, then either add new operators or functions for trapping behavior.
Most reasonable hardware has the instructions to trap or branch if add/sub/mul/div overflows or underflows so the checks are very cheap. Unlike the early days, in this day if C made it part of the standard processor manufacturers would simply stop selling CPUs without those features. Same goes for two's-compliment integer representations. They already did the same for 8-bit char/byte; other sizes are no longer supported.
- olliej 8y agoThere has been an ever increasing creep of undefined behaviour, which has broken existing code - type punning through unions was literally the “correct” mechanism for type coercion, which then became invalid when they established new, questionable, type aliasing rules that rendered it UB. The new type aliasing rules also mean that you can’t implement memcpy/memmove/bzero/memset without hitting UB. That requires hacks in the spec treatment of type aliasing to work around. Hell, even Malloc/free technically is UB due to type aliasing. Obviously there is signed integer overflow, which has resulted in numerous security flaws for questionable performance gains. Then there are other fun things, like technically it is UB for bzero to skip padding bytes in a struct (because that is UB), which means bzero(&somestruct, siseof(somestruct)) is not technically guaranteed to clear all of the struct, so I hope there’s not any secrets in left over memory.
- jcranmer 8y ago> There has been an ever increasing creep of undefined behaviour, which has broken existing code - type punning through unions was literally the “correct” mechanism for type coercion, which then became invalid when they established new, questionable, type aliasing rules that rendered it UB. Punning through unions is well-defined behavior in C99 and C11. In C++11 and newer, it's questionable, but it works in practice.
- olliej 8y agoWorks in practice resulted in the compilers adding security bugs - literally this article is about overflow checks that worked perfectly fine until the mid-2000s when compiler engineers realized they could abuse UB of overflow for “performance” and then a mountain of previously safe code became insecure.
- jcranmer 8y agoSpeaking as someone who works on compilers: Aliasing queries in the compiler basically work on a tiered system. There's a simple aliasing pass that first checks for really obvious alias information (such as, it's the same pointer, it's a bitcast of the pointer, it's a simple arithmetic expression of the same pointer), possibly some more advanced Andersen's-style alias passes, and only finally is there a last-ditch strict-aliasing based pass. If you take the address of a float and cast that to an integer pointer to get at the bits of the float (and don't let either pointer escape the function), it will work, even with "abusive" compilers that have aggressive optimization turned on, even if you modify the lvalue in the intervening code. It's literally more work to make the compiler not realize that the two pointers alias, and there's no benefit to pessimizing a trivial query, so I would be shocked if any compiler actually miscompiled that code.
- olliej 8y agoIt “working” isn’t the problem, the problem is when the compiler makes use of the “this is UB” to make formerly correct code incorrect. The definition of UB would allow a type punned union on the stack for instance to be treated as logically a struct - eg changes to the float value would not impact the integer value. While I agree that would not happen in practice today there is no reason it has to continue to work. The fact that compilers already make sane decisions regarding some UB - evaluation order of parameters used to be unspecified and gcc at least would change evaluation order depending of optimisation level, but all compilers have realized that just insane and so left to right evaluation. Similarly bzero will initialise padding bytes in a struct even though that is technically UB, so could technically be skipped. Sorry for run on horror sentences I’m typing on my phone :)