Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

411–420 of 748 posts

Re: Everything in C is undefined behavior

#411

Earlier quoted context omitted.

>It's partly the standards fault here - rather than saying "We don't know how vendors will implement this, so we shall leave it as implementation-defined", they say "We don't know how vendors will implement this, so we will leave it as undefined I'd agree to a point. I still think it's unreasonable for compiler writers to get all lawyery about precise terminology. After all "implementation defined" could still be sub…

But it's genuinely useful. In all seriousness, are you sure you aren't perhaps just using the wrong language? At this point UB and leveraging it for optimization are core parts of the most performant C implementations. That said, I think there are many cases where compilers could make a better effort to link UB they're optimizing against to UB that appears in the code as originally authored and emit a diagnostic or e…

> At this point UB and leveraging it for optimization are core parts of the most performant C implementations.

I am skeptical that NULL-pointer checks being removed contribute anything more than a rounding error in performance gains in any non-trivial program.

Re: Everything in C is undefined behavior

#412

Earlier quoted context omitted.

Which is totally fine and expected for any decent programmer. Casting pointers is clearly here be dragons territory.

Many, many programmers come to C (and C++) with a lower-level understanding that actually gets in the way here. They understand that all types "are" just bytes and that all pointers "are" just register-sized integer addresses, because that's how the hardware works and has worked for decades. It's perfectly reasonable to expect any load through `int*` to just load 4 bytes from memory, done and done. They get surprised…

I'm not sure that's right. For instance, the Pentium 4 spec explicitly says unaligned int32 loads take longer. And x86/x64 is very gentle in that regard, other archs would whip you. So an unaligned int access is rightfully treated differently. It should be IB.

Just creating the pointer, though, should not be UB, even though it apparently is. It should not even be IB.

Re: Everything in C is undefined behavior

#413
post #317
post #284

Earlier quoted context omitted.

The problem is that a lot of the flexibility introduced by UB doesn't serve the developer . Take signed integer overflow, for example. Making it UB might've made sense in the 1970s when PDP-1 owners would've started a fight over having to do an expensive check on every single addition . But it's 2026 now. Everyone settled on two's complement, and with speculative execution the check is basically free anyways. Leaving…

If we're talking two's complement it's not undefined that is right. Having to emit checks though, that is where I beg to differ. A check is only useful if you want to actually change the behavior when it happens, otherwise it is useless. Furthermore, it might be "essentially free" from a branch prediction point, but low and behold caches exist. You would pollute both the instruction cache with those instructions _and…

> A check is only useful if you want to actually change the behavior when it happens, otherwise it is useless.

You almost always want to change the behavior to erroring out on overflow. The few cases where overflow really is intended and fine can be handled by explicit opt-out.

And I refuse to buy the argument that "small things add up" in the world where we do string building and parsing every few microseconds. Checked math will have unnoticable impact compared to all the other things we do, in almost every type of program.

Re: Everything in C is undefined behavior

#414
post #284

Earlier quoted context omitted.

I would agree that C is "really flexible", but I would say it's primarily flexible because it lets you cast say from a void pointer to a typed pointer without requiring much boilerplate. It's also flexible because it lets you control memory layout and resource management patterns quite closely. If you want to be standards correct, yes you have to know the standard well. True. And you can always slip, and learn anothe…

The problem is that a lot of the flexibility introduced by UB doesn't serve the developer . Take signed integer overflow, for example. Making it UB might've made sense in the 1970s when PDP-1 owners would've started a fight over having to do an expensive check on every single addition . But it's 2026 now. Everyone settled on two's complement, and with speculative execution the check is basically free anyways. Leaving…

You can run your code under ASAN and UBSAN nowadays, it will catch many or most of issues as they happen.

But that's completely besides the point. UB on signed overflow, or really most of UB, is not unrelated to C flexibility. It is a detail of the spec related to portability and performance. IIRC it is even required to make such trivial optimizations as turning

    for (int i = 0; i 
into

    for (Foo *p = a, *last = a + n; p 
saving arithmetics and saving a register, on architectures where `int` is smaller than pointers. But there is also options like -fwrapv on GCC for example, allowing you to actually use signed overflow.

Re: Everything in C is undefined behavior

#415

Earlier quoted context omitted.

Wouldn’t be better to check both inputs before against the max value of that type instead of actually doing the overflow?

There are lots of better ways of doing this, but knowing why this one is bad/wrong requires the mental model described upthread. (But also, what you describe would be incorrect, since two MAX, and overflow)

> But also, what you describe would be incorrect, since two MAX, and overflow

I was maybe unclear. I meant, if you know a sum can introduce overflow (because you have a check right after), why not check the inputs before doing the sum, instead of checking the sum?

Re: Everything in C is undefined behavior

#416
post #341

Earlier quoted context omitted.

The compiler is not free to remove accesses to something marked volatile - its defined as a side-effect. Volatile means something else may be acting here. Something else may install anything into the register at any time - and every time you access. The compiler is required to preserve the order of accesses. In almost every C compiler, today, there are almost no optimisations the moment a volatile is introduced, for…

The print example has no defined order of accesses, function parameters can be evaluated in any order. But further, the entire problem with UB is that it supercedes the regular guarantees that you get (like with volatile) when it's encountered. Yes gcc and clang do the obvious thing that makes the most sense in this example, but what people are trying to tell you is that they could just not do that and they would sti…

Function parameters cannot be evaluated in any order, when one of them is a volatile.

> The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject

And what I am trying to tell people, is the standard has expectations around the volatile keyword, that the compilers took into account when designing how they would work - it isn't just kindness, its compliance. But no one is actually talking about the quotes from the standard, and just quoting themselves and their own understandings.

Re: Everything in C is undefined behavior

#417

Earlier quoted context omitted.

No it doesn't. Compilers are only required to emit the read for volatile types. If the type is non-volatile, misaligned, and can be optimised out then it would be perfectly fine to omit it (that would be the "succeed" option).

If a trap is observable behaviour, then the compiler either needs to add code, that checks for the condition and then traps explicitly or it needs to actually perform the read. Currently it can be optimized out, because it is UB.

You're merely attacking his particular suggestion and using this as an argument to defend UB, when those are completely independent concerns.

What people want is for a compiler that assumes that all pointers are aligned to use an aligned store or load instruction whenever the compiler wants to issue such an instruction. There is no need for UB here.

In other words, they want the compiler to stick with the decision it made and not randomly say "I can't do the thing I've been doing correctly for decades, because that's UB, my hands are tied, I must ruin the code, there's no other way."

Re: Everything in C is undefined behavior

#418
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…

> For most stuff, like an experiment, we obviously don't care, but when I do, I can usually one shot a file without any UB (which I check by reading the assembly output after building it with UBSAN)

Does this depend on the project, or part of a project? I'm wondering how far that scales, I don't know labor intensive it is -- maybe you can just look at the output and see that nothing funny is happening?

Re: Everything in C is undefined behavior

#419

Earlier quoted context omitted.

Calling something "simple" to use and learn is a valid use of the word, sorry. Not going to stop doing that. > The cognitive load of _actually delivering software_ written in C is immensely greater than doing so with Swift, or Rust, or Python, or Java, even Zig, despite all of those leveraging much heavier machinery in order to deliver a friendlier abstract model for you to program against Sorry, I couldn't disagree…

> I've got 40 years of programming in C so far, and the nightmare stories ran out after the first few years. You need to find something more interesting to do ;)

Oh, I do. I'm building a two-story 1000 sq.ft garage right now - more workshop than garage tbh [1], I've just built a roll-off-roof observatory [2], the currently empty pad behind it is for a radio-telescope, last set up in London [3], still needs to be assembled in the new house. Right now I'm into the fun stuff of automating everything in the observatory. I've also recently taken up archery, and I'm enjoying that. I've written (well Claude has) an optimising compiler for a memory-managing language for the 6502 [4], but I'm just instrumenting (this bit is me) the IR so it can also target the M chip on my Mac. Eventually it'll also target m68k so I can bring up the Atari ST on the FPGA that is currently just emulating the atari 8-bit (I have a 120MHz 6502 at the moment :). The 'x' in 'xt' is from 'atari Xl' and the 't' is from 'atari sT'. The compiler is called 'xtc'. Both will run MiNT and the blitter on the FPGA is designed to integrate well with GEM, the graphics environment on the ST - even the XL version will have a graphical UI running at 1080p :)

So I have a few things to keep me busy right now.

1: http://0x0000ff.co.uk/img/garage/garage-layout.png

2: http://0x0000ff.co.uk/img/observatory/roll-off-roof-observat...

3: http://0x0000ff.co.uk/img/dish/dish.jpg

4: http://atari-xt.com/

Re: Everything in C is undefined behavior

#420

Earlier quoted context omitted.

But be as you may you’re not following the standard.

what is your point?

If you don't follow the standard, gcc -O2 can introduce bugs to your code that you never even wrote. Skipping null checks, executing both branches of a conditional, and so on.
Post reply on HN