On 23 November 2015 at 10:20, Ramakrishnan Muthukrishnan <ram@rkrishnan.org> wrote:
Had been reading the SOSP paper:
<https://pdos.csail.mit.edu/papers/stack:sosp13.pdf>

As an example of how tricky it can be, one of their examples is

const uint8_t *data = /* buffer head */;
const uint8_t *data_end = /* buffer tail */;
int size = bytestream_get_be16(&data);
if (data + size >= data_end || data + size < data)
   return -1;

They say "A correct fix is to replace data + x >= data_end || data + x < data with x >= data_end − data, which is simpler and also avoids invoking undefined behavior; one should also add the check x < 0 if x can be negative."

Unfortunately, that replacement is itself well-defined only if data and data_end "point to elements of the same array object, or one past the last element of the array object" (and there's an implementation-dependent option for the interpretation of "one past" when ensuring the address can be represented). It looks from the comments as though that might be true in this particular case (or it's intended to be understood), but if not, avoiding the compiler's "optimisation" that messes up one form of undefined behaviour will lead you to write code that has different undefined states.

Generally, an optimising compiler for a systems language, especially one  in which pointer values can be manipulated explicitly,
needs to be sure of its ground when second-guessing the effect of a given statement or expression.