Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

371–380 of 748 posts

Re: Everything in C is undefined behavior

#371
post #324

Earlier quoted context omitted.

Yes, but undefined behaviour is undefined behaviour, and that behaviour can legally be that the code is not emitted at all, volatile (or any other side effect) or not. (and compilers do reason about undefined behaviour when optimising, so this isn't necessarily a completely theoretical argument, though I don't know whether the in compiler's actual logic which of 'don't optimise volatile' or the 'do assume undefined b…

Volatile wins. GCC calls that out [0] - volatile means things in memory may not be what they appear to be, and that there are asynchronous things happening, so something that may not appear to be possible, may become so, because volatile is a side-effect. So about the only optimisation allowed to happen, is combining multiple references. Clang is similar: > The compiler does not optimize out any accesses to variables…

That's cool and all if you are writing GCC or Clang dialect C, but it doesn't change the fact that it is UB in the C standard.

Re: Everything in C is undefined behavior

#372
post #315

Earlier quoted context omitted.

Only if there would be no side-effects. Which there are.

No this is irrelevant for making this decision

I've mentioned elsewhere the standards, and compilers as well, disagreeing with you here.

But feel free to run against the various compilers through godbolt. [0] They won't optimise the branch away. Access to a volatile, must be preserved, in the order that they exist. No optimisation, UB or otherwise, is allowed to impede that. Because an access is a side-effect.

[0] https://godbolt.org/z/85cGhq3Ta

Re: Everything in C is undefined behavior

#373

Is there a way to avoid undefined behavior Im C then? Could we write a new C compiler that adds some checks and fixes (e.g. raise documented exceptions) to each undefined behavior?

That post is just a hyperbolic rhetorical piece, not even a good technical shade. There are plenty of tools that restrict C into defined behavior subset. HN is just not aware of them. NASA, Aerospace and car industry are big customers, static analyzers and compilers. Good open source ones: Frama-C IKOS (from NASA)

It’s been a while since I programmed in C. Thank you for these resources.

Re: Everything in C is undefined behavior

#374

Earlier quoted context omitted.

Removing code paths that the programmer has explicitly laid out in the source code should be made a hard compile error unless the operation has been tagged with an attribute (anyone who wants to add the unsafe keyword to C? ). Another commenter suggested using LLMs, but I disagree. Having clangd emit warning squiggles for unchecked operations (like signed addition) would be a good start.

> Removing code paths that the programmer has explicitly laid out in the source code should be made a hard compile error unless the operation has been tagged with an attribute (anyone who wants to add the unsafe keyword to C? ). Dead code elimination is essential for performance, especially when using templates (this is basically what enables the fabled "zero cost abstraction" because complex template code may genera…

> free to eliminate code paths after UB

before.

Re: Everything in C is undefined behavior

#375
post #315

Earlier quoted context omitted.

Sure it can. That code path has unconditional UB and thus it is not valid.

Only if there would be no side-effects. Which there are.

This looks like a long back and fourth, that can easily be solved by a minute or two on godbolt...

Re: Everything in C is undefined behavior

#376

Earlier quoted context omitted.

Yeah, the unaligned accesses aren't going to be atomic unless the hardware supports it. > And in that time, the value of one of the two addresses that the hardware has to load can change. You mean volatile addresses that could spontaneously change in the middle of the reads? Like memory mapped I/O addresses? I would expect these to have stricter access requirements than arbitrary general purpose memory locations. > I…

> Anything that does that is broken and terrible anyway which is why it is undefined behaviour. the optimizer writers have told me consistently that if they can assume you're not doing this thing that's stupid anyway, they can make my code faster. And since I'm not doing that stupid thing anyway, I want my code to be faster.

Unaligned memory access isn't really stupid though. Not in the general case. Not to the point where it should give the compiler free reign to crash things or introduce security holes. It should just introduce a performance regression instead, which is a tractable problem. Just measure it and fix it by making things aligned.

Compilers can add some custom attributes that encode whatever semantics the badly designed hardware requires. This lets it freely break incorrect code in the small sections that are actually handling those special variables, while allowing the rest of the language to make sense.

Re: Everything in C is undefined behavior

#377
post #231

Earlier quoted context omitted.

This is a description of an imaginary compiler, evoked by the ANSI/ISO standards documents, which has never existed and will never exist. To understand what the program will do, you just have to understand the compiler behavior on your target platforms. A helpful intuition pump is: imagine the ANSI/ISO specifications simply do not exist; now what? Well, you just continue your engineering practice, the way you would f…

Not imaginary. Eliding checks on nullptr and integer overflow were both implemented, shipped, miscompiled the linux kernel and grew flags to disable them. I expect there are more if one goes looking.

Well yeah that just means some aspects of the imaginary compiler were in some configurations approximated by some historical compiler versions and were in some cases rejected by the community (which cares about sane semantics even for behavior left undefined by ANSI/ISO) and in some cases left in as defaults but made trivially configurable for anyone who wants to define the undefined behavior.

Re: Everything in C is undefined behavior

#378
post #242

Earlier quoted context omitted.

Author here. > -Acceptance: "Just dont write UB." The point of my article is that this is not possible. This cannot be our end state, as long as humans are the ones writing the code. No human can avoid writing UB in C/C++.

It's honestly not that difficult to be rigorous. The things you mentioned in the blog post are pretty obvious forms of degenerate practices once you get used to seeing them. The best way to make your argument would be to bring up pointer overflow being ub. What's great about undefined behavior is that the C language doesn't require you to care. You can play fast and loose as much as you want. You can even use implici…

> It's honestly not that difficult to be rigorous.

Ok, let's try it. I pointed GPT 5.5 at the smallest part of cosmopolitan as I could find in two seconds, net/finger. 299 lines.

describesyn.c:66: q + 13 constructs a pointer that can point well beyond the array plus one element.

C23 6.5.6p9:

> If the pointer operand and the result do not point to elements of the same array object or one past the last element of the array object, the behavior is undefined

Now… you may be trolling, but I do feel like this disproves your assertion. Not you, not me, not Theo de Raadt, can avoid UB.

> the compiler generating code that checks for pointer overflow.

Do you need to check for that specifically? What pointer are you constructing that is not either pointing at a valid object correctly aligned (not UB), or exactly one past the element of an array?

Do you mean for the latter, in case you have an array that ends on the maximum expressible pointer address?

I'm a bit unclear on what you mean by "pointer overflow". From mentioning 56 bit address spaces I'm guessing you mean like the pointer wrapped, not what I pointed to in cosmopolitan, above?

Ok, to be clear that it's not just that one type, if you forgive that one:

net/http/base32.c:64: read sc[0] even if sl=0. I assume this is never called with sl=0, so could be fine.

net/http/ssh.c:355: pointer address underflow? Should that be `e - lp`?

net/http/ssh.c:209/229: double destroy of key. can this code path have non-null members, meaning double free? Looks like it, since line 207 does the parsing and checks that parse worked.

net/http/ssh.c:123: uses memset, which assumes that it sets member variable pointers to NULL (per my post, depending on that means depending on UB), and later these pointers are given to free(), so that's UB.

I won't look deeper into net/http, but presenting just the possibly incorrect remaining comments from jippity:

  - ssh.c:211 and parsecidr.c:44: length-taking APIs use unbounded strstr() / strchr(), so explicit n with non-NUL-terminated input can read beyond the buffer.

  - tokenbucket.c:77 and tokenbucket.c:92: x >> (32 - c) is UB for c == 0 and for out-of-range c.

  - isacceptablehost.c:68: long numeric host labels can overflow signed int b before the function eventually rejects/accepts the host.

Re: Everything in C is undefined behavior

#379
Can anyone explain why this is undefined behaviour? UBSan calls it "indirect call of a function through a function pointer of the wrong type"

    struct foo {int i;};
    int func(struct foo *x) {return x->i;}
    int main() {
        int (*funcptr)(void*) = (int (*)(void*)) &func;
        struct foo foo = { 42 };
        return funcptr(&foo);
    }
While this is all kosher per the language lawyers:

    struct foo {int i;};
    int func(void *x) {return ((struct foo *)x)->i;}
    int main() {
        int (*funcptr)(void*) = &func;
        struct foo foo = { 42 };
        return funcptr(&foo);
    }

Re: Everything in C is undefined behavior

#380
Excellent post. But it's addressed to the wrong people.

The problem lies with compilers, not with the language and its specification, or with the creators of the C programming language.

Anyone can write a compiler that transforms all undefined behaviors (UB) into defined behaviors (DB). And your compiler will be used by people, including me.

Post reply on HN