On 23 November 2015 at 10:20, Ramakrishnan Muthukrishnan <[email protected]>
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.

Reply via email to