12
votes

Try as I might, the closest answer I've seen is this, with two completely opposing answers(!)

The question is simple, is this legal?

auto p = reinterpret_cast<int*>(0xbadface);
*p;  // legal?

My take on the matter

  1. Casting integer to pointer: no restrictions on what may be casted
  2. Indirection: only states the result is a lvalue.
  3. Lifetimes: only states what can't be done on objects, there is no object here
  4. Expression statements: *p is a discarded value expression
  5. Discarded value expressions: no lvalue-to-rvalue conversion occurs
  6. Undefined-ness of lvalues: aka strict aliasing rule, only if the lvalue is converted to a rvalue

So I conclude there is nothing explicitly saying this is undefined behaviour. Yet I distinctively remember that some platforms trap on indirection for invalid pointers. What went wrong with my reasoning?

2
Do you really think that could be legal?user2672107
@Passer "the only way it can have side effects is if it is UB ..." you caught my thought :-)user0042
From standard: "result is an lvalue referring to the object or function to which the expression points". Your pointer does not point to any object, so this line does not apply, and there is nothing else defining the result in that paragraph.Revolver_Ocelot

2 Answers

8
votes

[basic.compound] says:

Every value of pointer type is one of the following:

  • a pointer to an object or function (the pointer is said to point to the object or function), or
  • a pointer past the end of an object ([expr.add]), or
  • the null pointer value ([conv.ptr]) for that type, or
  • an invalid pointer value.

By the process of elimination we can deduce that p is an invalid pointer value.

[basic.stc] says:

Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

As indirection operator is said to perform indirection by [expr.unary.op], I would say, that expression *p causes UB no matter if the result is used or not.

1
votes

... some platforms trap on indirection for invalid pointers.

Most platforms trap on invalid address access. This does not contradict the issue in any way. The question of what happens in *p; boils down to whether an attempt to actually fetch at an invalid address takes place or not.

The question of fetching is very similar to the core issue 232 (indirection through a null pointer). As you have already pointed out, *p; is a discarded value expression, and as such no lvalue-to-rvalue conversion ("fetching") takes place:

Tom Plum:

...it is only the act of "fetching", of lvalue-to-rvalue conversion, that triggers the ill-formed or undefined behavior.

And subsequently:

Notes from the October 2003 meeting:

We agreed that the approach in the standard seems okay: p = 0; *p; is not inherently an error. An lvalue-to-rvalue conversion would give it undefined behavior.


As to whether or not reinterpret_cast<int*>(0xbadface) produces a valid pointer, indeed in implementations with strict pointer safety, it wouldn't be a safely-derived pointer, and as such is invalid and any use of it is UB.

But in case of relaxed pointer safety the resulting pointer is valid (otherwise it would be impossible to use pointers returned from binary libraries and components written in C or other languages).