1

Is address computation on a null pointer defined behavior in C++? Here's a simple example program.

struct A { int x; };
int main() {
  A* p = nullptr;
  &(p->x);  // is this undefined behavior?
  return 0;
}

Thanks.

EDIT Subscripting is covered in this other question.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Gregory
  • 1,205
  • 10
  • 17
  • Looks like UB to me. (For the first example, did you mean ` &(p->x);`?) – Eljay Jun 12 '20 at 01:17
  • @cigien Thanks for the pointer (no pun intended). That answers the second question, but not the first about member access. – Gregory Jun 12 '20 at 01:25
  • 1
    Definitely UB, there's no object at where `p` is pointing, so even before you take the address, doing `p->x` is the same as `(*p).x`, which is UB. – cigien Jun 12 '20 at 01:26
  • You're asking two different questions here. Member access and subscripting aren't the same. One of the questions is more nuanced than the other. – Brian Bi Jun 12 '20 at 01:27
  • Does this answer your question: https://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-beha – M.M Jun 12 '20 at 02:03

1 Answers1

2
&(p->x);  // is this undefined behavior?

Standard is a bit vague regarding this:

[expr.ref] ... The expression E1->E2 is converted to the equivalent form (*(E1)).E2;

[expr.unary.op] The unary * operator ... the result is an lvalue referring to the object ... to which the expression points.

There is no explicit mention of UB in the section. The quoted rule does appear to conflict with the fact that the null pointer doesn't point to any object. This could be interpreted that yes, behaviour is undefined.

[expr.unary.op] The result of the unary & operator is a pointer to its operand. ... if the operand is an lvalue of type T, the resulting expression is a prvalue of type “pointer to T” whose result is a pointer to the designated object ([intro.memory]).

Again, no designated object exists. Note that at no point is the operand lvalue converted to an rvalue, which would definitely have been UB.

Back in 2000 there was CWG issue to clarify whether indirection through null is undefined. The proposed resolution (2004), that would clarify that indirection through null is not UB, appears to not have been added to the standard so far.

However whether it is or isn't UB doesn't matter much since you don't need to do this. At the very least, the resulting pointer will be invalid and thus useless.

If you were planning to convert the pointer to an integer to get the offset of the member, there is no need to do this because you can instead us the offsetof macro from the standard library, which doesn't have UB.


&(p[1]); // undefined?

Here, behaviour is quite clearly undefined:

[expr.sub] ... The expression E1[E2] is identical (by definition) to *((E1)+(E2)), except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.

[expr.add] When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.

  • If P evaluates to a null pointer value and J evaluates to 0 (does not apply)

  • Otherwise, if P points to an array element (does not apply)

  • Otherwise, the behavior is undefined.


&(p[0]); // undefined?

As per previous rules, the first option applies:

If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

And now we are back to the question of whether indirection through this null is UB. See the beginning of the answer.

Still, doesn't really matter. There is no need to write this, since this is simply unnecessarily complicated way to write sizeof(int) * i (with i being 1 and 0 respectively).

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • "This could be interpreted that yes, behaviour is undefined." -- I don't see any other possible interpretation. Such an interpretation would have to explain which object the expression points to – M.M Jun 12 '20 at 02:03
  • @M.M Fair enough. I removed that. – eerorika Jun 12 '20 at 02:16