7
votes

In short, is the following code considered to have undefined behavior?

int main()
{
    int *p = <some invalid pointer value>;
}

For a compiling example, take the following code:

int main()
{
    int *p = new int;
    delete p; // Now p has an invalid pointer value.
    int *q = p; // UB?
}

I've done some research on the topic, so these are the relevant information I've found so far:

A pointer value (according to cppreference) can be one of:

  • A pointer to an object or function;
  • A pointer past the end of an object;
  • The null pointer value;
  • An invalid pointer value.

Also, according to cppreference,

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.

This thread addresses some uses of invalid pointers. Specifically, this answer mentions the Rationale document (C99), which has the following paragraph (section 6.3.2.3):

Regardless how an invalid pointer is created, any use of it yields undefined behavior. Even assignment, comparison with a null pointer constant, or comparison with itself, might on some systems result in an exception.

I'm not sure what's the state of affairs for C++, but I'd consider that, given the answers on the linked thread, uses of invalid pointers result in undefined behavior. Note, though, that assignment is not the same as initialization, so I'm not sure initialization is considered a use.

1
@super "As long as you don't try to dereference it all is ok." This is wrong. See the quotes from the standard provided by OP.melpomene
Not looking for the language standards, but loading a pointer into a 68000 address register or an x86 segment register would validate the address. If it is not currently mapped to RAM, it would trap.Bo Persson
That only proves implementation-defined. And BTW one would expect the implementation to not load into those registers if the pointer is never dereferenced.rustyx
@rustyx - Just pointing to reasons why copying an invalid pointer is not well defined. The guys writing the language standards were well aware of this. And if I had ever written a compiler for the 68000, I would surely have used the dedicated address registers for copying pointers. Why waste a data register for that?Bo Persson
@BoPersson The 68000 only checks the validity of the value stored in an address register when you try to dereference it. These registers are only 'special' in the sense that they can be used in indirect instructions whereas data registers cannot. And while you are correct that loading a segment register with an invalid value will cause an exception in x86, the compiler will only emit code to load such a register when it is going to dereference the pointer. This operation is expensive so the compiler won't do it unless it has to.Paul Sanders

1 Answers

4
votes

You’ve all but answered this yourself: it’s implementation defined, not undefined, in C++. The standard says just what you quoted (which I found by consulting the appropriate index). It doesn’t matter whether it’s initialization: the lvalue-to-rvalue conversion on the pointer object explicitly constitutes a use.