8

If I don't actually access the dereferenced "object", is dereferencing the null pointer still undefined?

int* p = 0;
int& r = *p;    // undefined?
int* q = &*p;   // undefined?

A slightly more practical example: can I dereference the null pointer to distinguish between overloads?

void foo(Bar&);
void foo(Baz&);

foo(*(Bar*)0);  // undefined?

Okay, the reference examples are definitely undefined behavior according to the standard:

a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.

Unfortunately, the emphasized part is ambiguous. Is it the binding part that causes undefined behavior, or is the dereferencing part sufficient?

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 1
    [This question covers the information you want.](http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-behav) – GManNickG Aug 20 '11 at 15:35
  • This must be an exact dupe. I know we have discussed this beore. – Martin York Aug 20 '11 at 16:56

3 Answers3

6

I think the second opus of What every C programmer should know about Undefined Behavior might help illustrate this issue.

Taking the example of the blog:

void contains_null_check(int *P) {
  int dead = *P;
  if (P == 0)
    return;
  *P = 4;
}

Might be optimized to (RNCE: Redundant Null Check Elimintation):

void contains_null_check_after_RNCE(int *P) {
  int dead = *P;
  if (false)  // P was dereferenced by this point, so it can't be null 
    return;
  *P = 4;
}

Which is turn optimized into (DCE: Dead Code Elimination):

void contains_null_check_after_RNCE_and_DCE(int *P) {
  //int dead = *P; -- dead store
  //if (false)     -- unreachable branch
  //  return;
  *P = 4;
}

As you can see, even though dead is never used, the simple int dead = *P assignment has caused Undefined Behavior to creep in the program.

To distinguish between overloads, I'd suggest using a pointer (which might be null) rather than artificially creating a null reference and exposing yourself to Undefined Behavior.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
5
int& r = *p;    // undefined?

I think right here you've undefined behavior even if you don't actually use r (or *p)- the dereferenced object. Because after this step (i.e dereferencing the null pointer), the program behaviour is not guaranteed by the language, as the program may crash immediately which is one of the possibilities of UB. You seem to think that only reading the value of r so as to be used in real purpose invokes UB. I don't think so.

Also, the language specification clearly says "the effect of dereferencing the null pointer" invokes undefined behavior. It does not say "the effect of actually using dereferenced object from a null pointer" invokes UB. The effect of dereferencing the null pointer (or in other words undefined behavior) doesn't mean that you will necessarily and immediately get problems, or it must crash immediately after dereferencing the null pointer. No. It simply means, the program behavior is not defined after dereferencing the null pointer. That is, the program may run normally, as expected, from start to end. Or it may crash immediately, or after after some time - after few minutes, hours or days. Anything can happen anytime after dereferencing the null pointer.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • I cannot find "the effect of dereferencing the null pointer" in the standard. Where exactly did you find it? – fredoverflow Aug 20 '11 at 10:51
  • 1
    @FredOverflow : §1.9/4 (C++03) says `Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. ]` – Nawaz Aug 20 '11 at 10:58
  • The FDIS replaced the null pointer example with `for example, the effect of attempting to modify a const object`, which might indicate that the rules about dereferencing the null pointer have changed. – fredoverflow Aug 20 '11 at 11:19
  • @Fred no. they replaced it because they want to change it to defined behavior in the long run (post-c++0x) and wanted a better example of undefined behavior. – Johannes Schaub - litb Aug 20 '11 at 15:05
  • It's actually worse than "anything can happen anytime after dereferencing the null pointer". In addition, "also, anything can happen anytime before dereferencing the null pointer." q.v. Raymond Chen's [Undefined behavior can result in time travel](https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633). – Eljay Apr 24 '20 at 15:16
4

Yes it is undefined behavior, because the spec says that an "lvalue designates an object or function" (at clause 3.10) and it says for the *-operator "the result [of dereferencing] is an lvalue referring to the object or function to which the expression points" (at clause 5.3.1).

That means there is no description for what happens when you dereference a null pointer. It's simply undefined behavior.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212