At what point does dereferencing the null pointer become undefined behavior?

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.

Leave a Comment