Why dereferencing a null pointer is undefined behaviour?

Viewed 11334

According to ISO C++, dereferencing a null pointer is undefined behaviour. My curiosity is, why? Why standard has decided to declare it undefined behaviour? What is the rationale behind this decision? Compiler dependency? Doesn't seem, because according to C99 standard, as far as I know, it is well defined. Machine dependency? Any ideas?

13 Answers

Arguments have been made elsewhere that having well-defined behaviour for null-pointer-references is impossible without a lot of overhead, which I think is true. This is because AFAIU "well-defined" here also means "portable". If you would not treat nullptr references specially, you would end up generating instructions that simply try to read address 0, but that produces different behaviour on different processors, so that would not be well-defined.

So, I guess this is why derereferencing nullptr (and probably also other invalid pointers) is marked as undefined.

I do wonder why this is undefined rather then unspecified or implementation-defined, which are distict from undefined behaviour, but require more consistency.

In particular, when a program triggers undefined behaviour, the compiler can do pretty much anything (e.g. throw away your entire program maybe?) and still be considered correct, which is somewhat problematic. In practice, you would expect that compilers would just compile a null-pointer-dereference to a read of address zero, but with modern optimizers becoming better, but also more sensitive to undefined behaviour, I think, they sometimes do things that end up more thoroughly breaking the program. E.g. consider the following:

matthijs@grubby:~$ cat test.c
unsigned foo () {
        unsigned *foo = 0;
        return *foo;
}

matthijs@grubby:~$ arm-none-eabi-gcc  -c test.c -Os && objdump -d test.o 

test.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <foo>:
   0:   e3a03000        mov     r3, #0
   4:   e5933000        ldr     r3, [r3]
   8:   e7f000f0        udf     #0

This program just dereferences and accesses a null pointer, which results in an "Undefined instruction" being generated (halting the program at runtime).

This might be ok when this is an accidental nullpointer dereference, but in this case I was actually writing a bootloader that needs to read address 0 (which contains the reset vector), so I was quite surprised this happened.

So, not so much an answer, but some extra perspective on the matter.

Related