9 ms·
Nah, it's a valid optimization as long as ereport() returns. The compiler doesn't need to follow the order of operations as long as the observed behavior is th
by moefh 8y ago
Nah, it's a valid optimization as long as ereport() returns.
The compiler doesn't need to follow the order of operations as long as the observed behavior is the same as if the operations were performed in the order in the code. Since the compiler doesn't have any responsibility if division by zero happens, it's fine to do the division before.
This is an interesting read: https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633 https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=...
- Asooka 8y agoIt is a compiler bug. The compiler can't reason what the effect of dividing by zero will be, because it's undefined. Therefore, hoisting the division before the if can change the observed behaviour, because the ereport function won't be executed. Ereport may not return, or it may print a debug message, or any other manner of things that are absolutely observable program behaviour. The function should be compiled with whatever division opcode or subroutine the compiler likes, including ones that crash the program, make it loop forever, make your cpu explode, or launch nukes at North Korea, however - it cannot reorder the function call after the division, because if it crashes, the program behaviour changes.
- lisper 8y ago> it cannot reorder the function call after the division Actually, it can because one of the things undefined behavior can do is go backwards in time. Undefined behavior anywhere in the program can legally make any part of the program do anything at any time. On top of that, there is no reliable way to tell if your program contains undefined behavior. This is madness.
- nickpsecurity 8y agoOn that last point, check out Rosu et al's KCC: an executable, formal semantics of C that addresses undefined behavior. https://github.com/kframework/c-semantics/blob/master/README.md https://github.com/kframework/c-semantics/blob/master/README...
- comex 8y agoSee my response to a sibling comment of yours making a similar point. It can only go back in time to a point where execution of undefined behavior is inevitable; it doesn’t count if the program aborts first: https://news.ycombinator.com/item?id=16917302 https://news.ycombinator.com/item?id=16917302
- jjnoakes 8y ago> Undefined behavior anywhere in the program can legally make any part of the program do anything at any time. This is only true if the undefined behavior is guaranteed to be reachable. This is not true in general. Putting "if (0) 1/0;" in a program does not cause undefined behavior.
- lisper 8y ago> This is only true if the undefined behavior is guaranteed to be reachable. Nope. It's true if the UB is possibly reachable. See: https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633/ https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=...
- jjnoakes 8y agoThat article agrees with me, not you. Even in the time travel examples, the code paths unrelated to the ub can't be touched. In other words, it can travel backward, but not sideways (which is what you originally claimed).
- lisper 8y ago> Even in the time travel examples, the code paths unrelated to the ub can't be touched. Of course they can. UB licenses the program to do anything including re-write any part of itself.
- jjnoakes 8y agoUB only licenses the program to do anything if it is reachable. Unreachable, unexecuted, cant-be-executed UB simply can't change a program's behavior. I'm not sure why you think it can. Do you think this program can "do anything" or "re-write any part of itself"? unsigned int x = <input from user>; unsigned int y = <input from user>; printf("%u\n", x / y); The compiler must output valid code for that program, and execution (not compilation) can only "do anything" if the user enters values that invoke UB (like "y == 0" for example). For all valid inputs this program must execute correctly and can not "do anything", even at runtime, do you agree? What about this one? unsigned int x = <input from user>; unsigned int y = <input from user>; if (y == 0) { printf("%u\n", x / y); } else { printf("%u\n", x * y); } Same idea: this program can only "do anything" if the user enters "y == 0". The compiler can see that "x / y" would invoke UB, and remove the entire "if (y == 0) { ... }" branch (because the compiler can assume it is never reached, otherwise it would invoke UB), but the compiler can not do anything to change the behavior of the "else" branch - entering any non-zero "y" value must produce correct output, so the program can't just be compiled to "do anything". Only the paths related to the UB can be optimized/modified/rewritten by the compiler based on that UB, and if those optimizations or modifications affect the proper execution of paths unrelated to the UB (i.e. paths where the UB can not be reached from), then the optimization or modification in question is a compiler bug.
- cesarb 8y ago> The compiler can't reason what the effect of dividing by zero will be, because it's undefined. It can reason: because it's undefined, it won't happen, that is, the code will never divide by zero. Therefore, the divisor is non-zero, and so the division instruction will not trap. Which means it can be moved above the call. If you mentally replace "undefined" with "impossible", the compiler behavior becomes more clear. And yeah, even in the absence of undefined behavior, optimizing compilers reason about impossible behavior all the time; for instance, after an "if (x == 2)", the compiler knows it's impossible for x to be 2 at the start of the else branch.
- comex 8y agoThe correct reasoning would be: “Because it’s undefined, it won’t happen, that is, the code will never divide by zero. Therefore, the divisor is non-zero or the division is never executed.” Undefined behavior can ‘go back in time’, but only to a point where the compiler can prove it will necessarily occur in the future. And there’s no language in the standard allowing compilers to assume that an arbitrary function will ever return, as opposed to terminating the program or entering an infinite loop. There are some cases where the compiler is allowed to assume a loop will eventually terminate (one of the less widely known forms of undefined behavior), but only if the loop has no input/output or other observable effects besides spinning: https://stackoverflow.com/questions/16436237/is-while1-undefined-behavior-in-c https://stackoverflow.com/questions/16436237/is-while1-undef... Edit: And according to the linked Debian bug report thread, the problematic optimization could no longer be reproduced on newer versions of GCC.
- saagarjha 8y ago> Undefined behavior can ‘go back in time’, but only to a point where the compiler can prove it will necessarily occur in the future. I don't quite get what you mean here. If the compiler can prove that you perform undefined behavior, isn't it legal for it to move it to the start of the program and literally produce no output?
- cesarb 8y ago