Ambiguity in the standard on undefined behaviour o

2019-04-13 19:41发布

问题:

ISO IEC 14882-2011 §5.7/5 States:

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

This section is used here on stackoverflow from time to time. For instance to argue why the increment of a pointer to nullptr is UB like here. It is then interpreted as, having a pointer that does not point to an element of an array object. Is undefined behaviour.

However, when I read this I understood it to refer to the evaluation of the pointer being UB. Which would mean that having such a pointer is well defined behaviour. And the behaviour becomes undefined when one tries to dereference it.

Which would mean that for example, incrementing a valid pointer beyond the array boundary is legal. Decrementing it again afterwards is legal. And since the pointer will then be the same value as before the increment, the evaluation is legal too.

Which of the two is the case?

回答1:

The paragraph you're quoting refers to pointer arithmetic, not to evaluation of pointers.

It states that the only time pointer addition p + i is defined is if
(treating subtraction of i as equivalent to addition of -i)

  1. p points to an element of an array object or one past the last element, and
  2. p + i points to an element of the same array object, or one past the last element

If p isn't a pointer to an array element or "one past the end" - for instance if it is the null pointer or "two past the end" - the behaviour is undefined.
You don't need to dereference the result to cause undefined behaviour - the effect of the addition itself is undefined.

That is to say

int p[1] = {0};
int *q = p;  // OK
q = q + 1;   // OK - one past the end
int *r = q + 1;   // Undefined behaviour
r = r - 1;   // Doesn't make r valid or the program un-undefined

and likewise

int *p = nullptr;
p++; // Undefined
p--; // Still undefined


回答2:

"The evaluation" means the evaluation of the additive operation; thus UB would not occur for (say) static_cast<int*>(nullptr) + 1 within a non-evaluated context (sizeof, decltype, etc).

It does not mean "the evaluation of the pointer", and certainly not dereferencing it; if the standard had intended that interpretation, it would have said so.



回答3:

Incrementing then decrementing a null pointer is still undefined behaviour. When UB occurs, anything can happen, so this would be a valid sequence of an events:

  1. Increment null pointer. Undefined behaviour, so we'll set the pointer to 0xDEADBEEF because we can.
  2. Decrement pointer. Also undefined behaviour unless 0xDEADBEEF happens to be in a valid array after the first element.
  3. Dereference pointer. Issue forth nasal demons.