5 ms·
Always missing in this argument is the logic of how to go from "undefined" to "can never happen". If the spec did not want it to happen they would have said "c
by somat 4y ago
Always missing in this argument is the logic of how to go from "undefined" to "can never happen". If the spec did not want it to happen they would have said "can not happen/illegal". but no, it is undefined by the spec. The spec knows that it can and will happen they just did not want to pin down the behavior of the compiler. So the compiler optimization team saying "we can assume this will never happen" is a blind almost maliciously complaint viewpoint.
- aw1621107 4y ago> Always missing in this argument is the logic of how to go from "undefined" to "can never happen". The reasoning is something like "if we assume UB doesn't happen, but it does happen, the resulting behavior is unpredictable. This is allowed by the standard, though, because UB allows for any behavior, including that produced by assuming UB doesn't happen." In other words, major implementations treat UB as preconditions. Violating those preconditions gets you Interesting Results (TM), but that's allowed by the standard because "unpredictable results " really means unpredictable results. For example, null pointer dereference is UB. If an implementation assumes null pointers can never be dereferenced, it can better optimize some code. If it turns out a null pointer is dereferenced, the argument is that whatever happens then is still permitted by the standard as the standard does not define any program semantics for programs containing UB.
- uecker 4y agoI agree that this does not follow from the wording in the standard and I am relatively sure that this was originally not implied. But this view point is repeated quite often nowadays. I think this is because prominent compiler developers promoted this point of view and used this for blaming the user ("Because you have UB in your program it is completely invalid. It is now ok that the compiler breaks it, and it is alone your fault".) The other response to your post is correct so, but this explanation would not allow UB to affect prior observable behavior.
- gpderetta 4y agoEx falso quodlibet
- chalst 4y ago...is taken as true but is a really lousy principle for modelling informal reasoning.
- Karellen 4y agoFrom the C standard §3.4.3: undefined behavior behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements 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). EXAMPLE An example of undefined behavior is the behavior on integer overflow https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf The important wording here is "this International Standard imposes no requirements" i.e. an implementation is allowed to do literally anything in the case of undefined behaviour. It's not quite that the compiler writers are saying "this can never happen", it's more along the lines of "if this does happen, we can do anything at all, including acting as if the conditions were such that UB could not have happened." So if you multiply two signed ints that the compiler knows are positive, the compiler can assume that the result can't overflow. Because, if it does overflow, the compiler can emit code that does absolutely anything in that case - including acting as if it didn't overflow. Therefore, it can elide checks for a negative result, because either there was no overflow in which case the check is redundant, or there was but the code is allowed to do anything at all - including not performing the check for a negative result.
- uecker 4y agoI agree with this logic. But note there is one caveat: Observable behavior that has already happened when the condition for UB is encountered can then not be affected. The C++ committee later clarified that for UB also the previous observable behavior can be affected. It is unclear whether this affects C as the C committee never added this clarification, but compiler writers often apply this interpretation to C as well. In my opinion the C++ made a mistake here, as this makes UB more dangerous.
- andrewaylett 4y agoWhen do you consider that "the condition for UB" would be encountered, for any particular behaviour that lacks a definition? The optimiser is -- in general -- allowed to re-order operations and restructure code if it doesn't change the behaviour of the program. In doing this, it needs to trust the programmer that the program is valid. Otherwise it can't even re-order two signed additions, lest the first one overflow. You might want a language that restricts this, but C is not that language. Or you might want a language that defines all its behaviours, but C is not that language either. Compiler writers put a lot of effort into making their compilers do exactly what the programmer tells them to do. My personal take is that the correct response to the difficulties of ensuring your C program doesn't exhibit undefined behaviour is probably to avoid writing new code in C. But if you do still need to write C for whatever reason (which I do, occasionally) then it's only sensible to take as much care as the language design expects programmers to take: the compiler trusts the programmer to only attempt operations with defined results.