4 ms·
> Someone seeing that function may be tempted to say that it's not UB to call with a NULL value as long as the dereference doesn't happen (say, bar() could call
by haberman 4y ago
> Someone seeing that function may be tempted to say that it's not UB to call with a NULL value as long as the dereference doesn't happen (say, bar() could call exit() or it could run an infinite loop).
An infinite loop is UB for precisely this reason: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm So an infinite loop cannot prevent the invocation of UB, because an infinite loop is itself UB.
I would expect that a call to exit() inside bar() would prevent eliding of the NULL check. If the program calls exit() before the dereference, it does not invoke UB and therefore should run correctly. I tried your example and Clang and GCC do not actually elide the NULL check in this case, probably for this reason: https://godbolt.org/z/cnWPz3o59 https://godbolt.org/z/cnWPz3o59
> The standard talks about executions in the sense of theoretical executions by the C abstract machine, not actual executions of the compiled binary. I thought the other comment was rendering to the latter notion of execution, but perhaps I was wrong and it was also talking about the former.
I don't see how this would change the analysis. Running the binary triggers actual executions of both the abstract machine and the physical binary.
- gpderetta 4y agoThe fact that bar could exit or not return doesn't matter (although it was indeed my initial line of reasoning) as if the value is null bar won't be called and UB happens; hence the value can't be null and bar can be called unconditionally. The value is still dereferenced only after calling bar. Still gcc doesn't optimize the check away so it is possible there is some other line of reasoning that prevents the transformation.