{"article":{"slug":"attention-people-who-think-ub-is-fine","title":"Attention people who think UB is fine","subtitle":null,"summary":"Thomas Habets follows up his post on undefined behaviour in C with a concrete example showing that UB is not 'at worst a segfault': the same line can run whatever is next in memory, write a random value and crash, or do what you naively expect.","content_type":"blog_post","language":"en","canonical_url":"https://blog.habets.se/2026/10/Attention-people-who-think-UB-is-fine.html","author":{"name":"Thomas Habets","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Blargh","url":"https://blog.habets.se/","listing_slug":null,"listing":null},"topics":[{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"C","slug":"c","url":"https://listedarticles.com/topics/c"},{"name":"Compilers","slug":"compilers","url":"https://listedarticles.com/topics/compilers"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":609,"reading_minutes":3,"published_at":"2026-10-22T00:00:00.000Z","added_at":"2026-10-23T23:15:01.884Z","updated_at":"2026-10-23T23:15:01.884Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/attention-people-who-think-ub-is-fine","markdown_url":"https://listedarticles.com/articles/attention-people-who-think-ub-is-fine.md","example":false,"citation":"Thomas Habets, Blargh. \"Attention people who think UB is fine.\" 22 Oct 2026. https://blog.habets.se/2026/10/Attention-people-who-think-UB-is-fine.html (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://blog.habets.se/2026/10/Attention-people-who-think-UB-is-fine.html"},"body_markdown":"# Attention people who think UB is fine\n\n2026-10-22,\nCategories: programming\n\nAfter [my post on undefined behavior in\nC](https://blog.habets.se/2026/05/Everything-in-C-is-undefined-behavior.html)\nsome people insisted that it’s demonstrably fine, we know what the code will\ndo, and at worst we’ll get a segfault.\n\nThis is false.\n\nHere’s an example.\n\n## C code\n\n```\n#include<utility>\n\n// Let's pretend this is a memory mapped device controlling\n// motors and gears and stuff.\nvolatile int device_command = 0;\n\nvoid serve_hot_chocolate() {\n        device_command = 42;\n\n        // Oh no, we spilled some hot chocolate, invoking UB.\n        //\n        // The definition of `std::unreachable()` is:\n        //     Invokes undefined behavior at a given point.\n        std::unreachable();\n}\n\nvoid explode() {\n        device_command = 3;\n}\n```\n\n## Example assembly output\n\nWith GCC 16.2 with `-O1`.\n\n```\n\"serve_hot_chocolate()\":\n        mov     DWORD PTR \"device_command\"[rip], 42\n\"explode()\":\n        mov     DWORD PTR \"device_command\"[rip], 3\n        ret\n\"device_command\":\n        .zero   4\n```\n\nRuh roh. Exploding chocolate! The function `explode()` will be executed, even\nthough it was never called!\n\n[godbolt link](https://godbolt.org/z/Y5844eTKe)\n\n## Another example: dereferencing a null pointer\n\nSome people insisted that dereferencing a null pointer is *fine*. It’ll just\ntry to access address zero! And these people supposedly know what happens when\nyou try: if nothing is mapped there, you’ll get a segfault.\n\nAgain, not true.\n\nLet’s say we change `std::unreachable()` to `int* ptr = nullptr; *ptr = 99;` in\nthe previous example. Now we [get this](https://godbolt.org/z/efqKrzefa):\n\n```\n\"serve_hot_chocolate()\":\n        mov     DWORD PTR \"device_command\"[rip], 42\n        mov     DWORD PTR ds:0, 0\n        ud2\n```\n\nCurious, eh? First it writes zero, **not** 99, to memory address zero. Then it\ncrashes the program using an invalid instruction. The number 99 never appears\nin the generated program. But the null pointer write does. Presumably the null\npointer write is done in order to improve debugger error messages.\n\nNow let’s check [clang with godbolt](https://godbolt.org/z/86M7MWTT8):\n\n```\n\"serve_hot_chocolate()\":\n        mov     dword ptr [rip + \"device_command\"], 42\n\n\"explode()\":\n        mov     dword ptr [rip + \"device_command\"], 3\n        ret\n\n\"device_command\":\n        .long   0\n```\n\nAgain we get exploding chocolate.\n\n## Let’s do some pointer arithmetic on the null pointer\n\nOk, so what happens if we add `ptr += 10`. That’s UB for three reasons:\n\n1. using a null pointer for anything other than comparison against other pointers,\n2. even if an object would be valid at the null pointer (which it’s not),\n   creating a pointer that points outside that object, or if an array, beyond\n   one-past the array, is UB,\n3. even if that were valid (which it’s not), we then dereference the address.\n\nLet’s [try it](https://godbolt.org/z/8z6hPPsvG).\n\n```\n\"serve_hot_chocolate\":\n        mov     DWORD PTR \"device_command\"[rip], 42\n        mov     DWORD PTR ds:40, 99\n        ret\n```\n\nWow. *Now* it did what someone naively would expect, taking the code at face\nvalue. Lucky.\n\nWhy did GCC (and clang, by the way) not detect that `*(ptr + 10) = 99` is\nequally UB as `*ptr = 99`, and do the same thing?\n\nWrong question. No compiler is obligated to “detect” UB at all. Looks to me\nlike GCC and clang, if we want to anthropomorphize them, saw “oh, null pointer\ndereference? Well that can’t happen, so I’ll stop emitting instructions for\nthis function, to save on the binary size”. Because of the [halting\nproblem](https://en.wikipedia.org/wiki/Halting_problem), it cannot in the\ngeneral case know if the code will ever be executed.\n\n## So what does UB do?\n\nAnything. I have now demonstrated three things UB can do, when UB was triggered\nin the same place:\n\n1. Run whatever happens to be next in memory (exploding chocolate).\n2. Store a (for all intents and purposes) *random* value at address zero (wrote\n   zero, not 99), and then deliberately crash.\n3. Do what one would naively expect: write the value to the address seen in the\n   code at face value.\n\nAnd to think that some people don’t believe in [nasal\ndemons](https://en.wikipedia.org/wiki/Undefined_behavior).\n","body_html":"<h1 id=\"attention-people-who-think-ub-is-fine\">Attention people who think UB is fine</h1>\n<p>2026-10-22,\nCategories: programming</p>\n<p>After <a href=\"https://blog.habets.se/2026/05/Everything-in-C-is-undefined-behavior.html\" rel=\"nofollow ugc noopener\">my post on undefined behavior in\nC</a>\nsome people insisted that it’s demonstrably fine, we know what the code will\ndo, and at worst we’ll get a segfault.</p>\n<p>This is false.</p>\n<p>Here’s an example.</p>\n<h2 id=\"c-code\">C code</h2>\n<pre><code>#include&lt;utility&gt;\n\n// Let&#39;s pretend this is a memory mapped device controlling\n// motors and gears and stuff.\nvolatile int device_command = 0;\n\nvoid serve_hot_chocolate() {\n        device_command = 42;\n\n        // Oh no, we spilled some hot chocolate, invoking UB.\n        //\n        // The definition of `std::unreachable()` is:\n        //     Invokes undefined behavior at a given point.\n        std::unreachable();\n}\n\nvoid explode() {\n        device_command = 3;\n}</code></pre>\n<h2 id=\"example-assembly-output\">Example assembly output</h2>\n<p>With GCC 16.2 with <code>-O1</code>.</p>\n<pre><code>&quot;serve_hot_chocolate()&quot;:\n        mov     DWORD PTR &quot;device_command&quot;[rip], 42\n&quot;explode()&quot;:\n        mov     DWORD PTR &quot;device_command&quot;[rip], 3\n        ret\n&quot;device_command&quot;:\n        .zero   4</code></pre>\n<p>Ruh roh. Exploding chocolate! The function <code>explode()</code> will be executed, even\nthough it was never called!</p>\n<p><a href=\"https://godbolt.org/z/Y5844eTKe\" rel=\"nofollow ugc noopener\">godbolt link</a></p>\n<h2 id=\"another-example-dereferencing-a-null-pointer\">Another example: dereferencing a null pointer</h2>\n<p>Some people insisted that dereferencing a null pointer is <em>fine</em>. It’ll just\ntry to access address zero! And these people supposedly know what happens when\nyou try: if nothing is mapped there, you’ll get a segfault.</p>\n<p>Again, not true.</p>\n<p>Let’s say we change <code>std::unreachable()</code> to <code>int* ptr = nullptr; *ptr = 99;</code> in\nthe previous example. Now we <a href=\"https://godbolt.org/z/efqKrzefa\" rel=\"nofollow ugc noopener\">get this</a>:</p>\n<pre><code>&quot;serve_hot_chocolate()&quot;:\n        mov     DWORD PTR &quot;device_command&quot;[rip], 42\n        mov     DWORD PTR ds:0, 0\n        ud2</code></pre>\n<p>Curious, eh? First it writes zero, <strong>not</strong> 99, to memory address zero. Then it\ncrashes the program using an invalid instruction. The number 99 never appears\nin the generated program. But the null pointer write does. Presumably the null\npointer write is done in order to improve debugger error messages.</p>\n<p>Now let’s check <a href=\"https://godbolt.org/z/86M7MWTT8\" rel=\"nofollow ugc noopener\">clang with godbolt</a>:</p>\n<pre><code>&quot;serve_hot_chocolate()&quot;:\n        mov     dword ptr [rip + &quot;device_command&quot;], 42\n\n&quot;explode()&quot;:\n        mov     dword ptr [rip + &quot;device_command&quot;], 3\n        ret\n\n&quot;device_command&quot;:\n        .long   0</code></pre>\n<p>Again we get exploding chocolate.</p>\n<h2 id=\"let-s-do-some-pointer-arithmetic-on-the-null-pointer\">Let’s do some pointer arithmetic on the null pointer</h2>\n<p>Ok, so what happens if we add <code>ptr += 10</code>. That’s UB for three reasons:</p>\n<ol><li>using a null pointer for anything other than comparison against other pointers,</li><li><p>even if an object would be valid at the null pointer (which it’s not),</p><p> creating a pointer that points outside that object, or if an array, beyond\n one-past the array, is UB,</p></li><li>even if that were valid (which it’s not), we then dereference the address.</li></ol>\n<p>Let’s <a href=\"https://godbolt.org/z/8z6hPPsvG\" rel=\"nofollow ugc noopener\">try it</a>.</p>\n<pre><code>&quot;serve_hot_chocolate&quot;:\n        mov     DWORD PTR &quot;device_command&quot;[rip], 42\n        mov     DWORD PTR ds:40, 99\n        ret</code></pre>\n<p>Wow. <em>Now</em> it did what someone naively would expect, taking the code at face\nvalue. Lucky.</p>\n<p>Why did GCC (and clang, by the way) not detect that <code>*(ptr + 10) = 99</code> is\nequally UB as <code>*ptr = 99</code>, and do the same thing?</p>\n<p>Wrong question. No compiler is obligated to “detect” UB at all. Looks to me\nlike GCC and clang, if we want to anthropomorphize them, saw “oh, null pointer\ndereference? Well that can’t happen, so I’ll stop emitting instructions for\nthis function, to save on the binary size”. Because of the <a href=\"https://en.wikipedia.org/wiki/Halting_problem\" rel=\"nofollow ugc noopener\">halting\nproblem</a>, it cannot in the\ngeneral case know if the code will ever be executed.</p>\n<h2 id=\"so-what-does-ub-do\">So what does UB do?</h2>\n<p>Anything. I have now demonstrated three things UB can do, when UB was triggered\nin the same place:</p>\n<ol><li>Run whatever happens to be next in memory (exploding chocolate).</li><li><p>Store a (for all intents and purposes) <em>random</em> value at address zero (wrote</p><p> zero, not 99), and then deliberately crash.</p></li><li><p>Do what one would naively expect: write the value to the address seen in the</p><p> code at face value.</p></li></ol>\n<p>And to think that some people don’t believe in <a href=\"https://en.wikipedia.org/wiki/Undefined_behavior\" rel=\"nofollow ugc noopener\">nasal\ndemons</a>.</p>","headings":[{"level":1,"text":"Attention people who think UB is fine","id":"attention-people-who-think-ub-is-fine"},{"level":2,"text":"C code","id":"c-code"},{"level":2,"text":"Example assembly output","id":"example-assembly-output"},{"level":2,"text":"Another example: dereferencing a null pointer","id":"another-example-dereferencing-a-null-pointer"},{"level":2,"text":"Let’s do some pointer arithmetic on the null pointer","id":"let-s-do-some-pointer-arithmetic-on-the-null-pointer"},{"level":2,"text":"So what does UB do?","id":"so-what-does-ub-do"}]}}