After my post on undefined behavior in C some people insisted that it’s demonstrably fine, we know what the code will do, and at worst we’ll get a segfault.

This is false.

Here’s an example.

C code

#include<utility>

// Let's pretend this is a memory mapped device controlling
// motors and gears and stuff.
volatile int device_command = 0;

void serve_hot_chocolate() {
        device_command = 42;

        // Oh no, we spilled some hot chocolate, invoking UB.
        //
        // The definition of `std::unreachable()` is:
        //     Invokes undefined behavior at a given point.
        std::unreachable();
}

void explode() {
        device_command = 3;
}

int main() {
        serve_hot_chocolate();
}

Example assembly output

With GCC 16.2 with -O1.

"serve_hot_chocolate()":
        mov     DWORD PTR "device_command"[rip], 42
"explode()":
        mov     DWORD PTR "device_command"[rip], 3
        ret
"main":
        mov     DWORD PTR "device_command"[rip], 42
"device_command":
.zero   4

Ruh roh. Exploding chocolate! The function explode() will be executed, even though it was never called!

Another example: dereferencing a null pointer

Some people insisted that dereferencing a null pointer is fine. It’ll just try to access address zero! And these people supposedly know what happens when you try: if nothing is mapped there, you’ll get a segfault.

Again, not true.

Let’s say we change std::unreachable() to int* ptr = nullptr; *ptr = 99; in the previous example. Now we get this:

"serve_hot_chocolate()":
        mov     DWORD PTR ds:0, 0
        ud2

Curious, eh? First it writes zero, not 99, to memory address zero. Then it crashes the program. The number 99 never appears in the generated program. But the null pointer write does.

godbolt link.

And to think that some people don’t believe in nasal demons.

Further experimentation

Experiment more at godbolt.org.