A path towards avoiding costs of undefined behaviour optimizations
A path towards avoiding costs of undefined behaviour optimizations
Posted Dec 13, 2013 1:29 UTC (Fri) by pjm (guest, #2080)In reply to: Optimization-unstable code by nybble41
Parent article: Optimization-unstable code
> the fact that the NULL dereference case is undefined means that the compiler can take this as a hint that you know something it can't: that the pointer won't be NULL at that point in the program
The danger of this “treat definedness as knowledge of data values” approach is of course that the resulting compiler behaviour (and behaviour of compiled binaries) makes C/C++ a more dangerous choice of language. Runtime efficiency is a significant reason why people choose to use C/C++, but it's worthwhile looking for other approaches to get that efficiency without the costs in security bugs and obstacles to debugging (nigh impossibility of reasoning about program behaviour when ‘if’ blocks can be optimized away).
A more explicit approach to conveying that information to the compiler would be something more along the lines of ‘__builtin_assume(tun != NULL)’. It could be wrapped in a macro that tests for compiler version and falls back to expr_ ? 0 : 1 << -1 (suitably parenthesized and void-cast), at least for the case that expr_ has no side effects. This could even be built into an assert-like macro in the NDEBUG case, so that such assertions provide both a testing benefit without NDEBUG, and a speed benefit with NDEBUG. Similarly, it mixes well with the design-by-contract approach of specifying all the preconditions of a function.
[Programmer-specified preconditions also give a path to overcoming those concerns about how to warn: if the program claims that the given preconditions are complete, and the compiler determines that the given preconditions don't imply tun != NULL, then the compiler can issue a warning or error as soon as it sees tun->sk. It requires work; but the payoff in debugging time and bug cost can be worthwhile.]
By itself, an ‘assume’ facility provides only optimization rather than undefinedness-bug-prevention; but by providing an alternative, it makes it more reasonable to change compiler behaviour to make C/C++ less dangerous choices of implementation language.