Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

601–610 of 748 posts

Re: Everything in C is undefined behavior

#601
post #113

Yes there is tons of surprising and weird UB in C, but this article doesn't do a great job of showcasing it. It barely scratches the surface. Here's a way weirder example: volatile int x = 5; printf("%d in hex is 0x%x.\n", x, x); This is totally fine if x is just an int, but the volatile makes it UB. Why? 5.1.2.4.1 says any volatile access - including just reading it - is a side effect. 6.5.1.2 says that unsequenced…

Author here. > It barely scratches the surface. I agree. The point of the post is not to enumerate and explain the implications of all 283 uses of the word "undefined" in the standard. Nor enumerate all the things that are undefined by omission. The point of the post is to say it's not possible to avoid them. Or at least, no human since the invention of C in 1972 has. And if it's not succeeded for 54 years, "try hard…

> if nobody can do it right, how is it even fair to blame the programmer? My point is that ALL

It's fair to blame the programmer for the choice of programming in a language like this, if it was in fact their choice. As you've so eloquently put, choosing those languages is essentially equivalent to choosing UB, so starting a new project with one of them is 100% blameworthy when the UB is inevitably found.

Re: Everything in C is undefined behavior

#602
post #511

Earlier quoted context omitted.

> The reason for the hack is that very early C compilers just always spill, so you can write MMIO driver code by setting a pointer to point at the MMIO hardware and it actually works because every time you change x the CPU instruction performs a memory write. Source?

This is one of those "everyone doing this kind of work knows" that's rather hard to source, but: this is basically the point of volatile. Especially for reads rather than writes, where you may want to read some location that is being written into by a different piece of hardware. People used to use it for thread synchronization before proper memory barrier primitives (see https://mariadb.org/wp-content/uploads/2017/1…

Yeah. I could have sworn that I've read somewhere an anecdote from the Bell Labs era in which this comes up, but I can't find it and might be misremembering. The whole volatile keyword doesn't exist in K&R C as released, there are no "type qualifiers" at all in that language, both volatile and const are introduced in C89.

Duff's famous Device, often misunderstood as some insight about memory copying or something silly, was an MMIO hack, it doesn't look like an MMIO hack to us because it doesn't say volatile, but that's because Duff's compiler did not have that keyword, the reason Duff doesn't change the destination pointer is that it's pointing at hardware and the hardware isn't going anywhere, writing different bytes to the same address is I/O.

Re: Everything in C is undefined behavior

#603
I like the ideas of this article but would not use SPARC as a main badguy in my examples. A naive and probably popular takeaway would be, "Thank goodness I am not writing for SPARC and don't need to worry about these SPARC architectural concerns!"

Re: Everything in C is undefined behavior

#604

The problem is incorrectly assuming that the spec is meaningful in some kind of rigorous way. It’s not. All that matters is what C compilers actually do and what real C programs expect. This is a good thing. It creates a culture where the two sides meet each other where they’re at

We also have a very limited number of compilers and a small number of prevalent architectures today. As long as you know the behavior of the target compiler and architecture, the behavior is defined, it's just not specified.

Re: Everything in C is undefined behavior

#605

I have never in my 20 years of writing C heard so much about undefined behavior as I have in the past 6 months on Hacker News. It has never entered the conversation. You write the code. If it doesn't work, you debug it and apply a fix or a workaround. Why does the idea of undefined behavior in C get to the front page so consistently?

So, you never iterated past an array, you never used after a free(), you never tried doing i = ++i + ++i; ?

Re: Everything in C is undefined behavior

#607
post #113

Yes there is tons of surprising and weird UB in C, but this article doesn't do a great job of showcasing it. It barely scratches the surface. Here's a way weirder example: volatile int x = 5; printf("%d in hex is 0x%x.\n", x, x); This is totally fine if x is just an int, but the volatile makes it UB. Why? 5.1.2.4.1 says any volatile access - including just reading it - is a side effect. 6.5.1.2 says that unsequenced…

What's weird about it?

If you are using volatile you are reading from a device port mapped to that address.

Since C doesn't mandate in which order function arguments are evaluated, you don't know which argument will be read from port first.

How can that be anything but UB?

Re: Everything in C is undefined behavior

#608

Earlier quoted context omitted.

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…

> 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. I'd clarify this with "They understand that all values are just bytes" . > Meanwhile, the actual computers we have been using for decades have no problems actually just loading 4 bytes through any arbitrary pointer with zero overhead. It…

> A clear majority of the UB problems with C could be fixed if the standards committee slowly moved all UB into IB

There is no such thing as getting rid of "all UB."

What behavior is the implementation supposed to prescribe for a write to an unpredictable garbage address you read from the network? It could overwrite your code. It could overwrite any value anywhere. It could overlap with anything. Prescribing defined behavior for absolutely everything would require defining a precise, unoptimizable 1-to-1 mapping to assembly code and disallowing any multithreading.

Re: Everything in C is undefined behavior

#609
post #181

Earlier quoted context omitted.

In many architectures does not mean you can. The standard is supposed to cover all architectures.

If some architecture traps on unaligned access, then the compiler can and should simply generate the correct code so that it loads the integer piece by piece instead. Load multiple integers and shift and mask away the irrelevant bits, done. This is exactly what modern architectures already do in hardware. Works, it's just a little slower. This is exactly what the compilers do if you use a packed structure to access u…

> If some architecture traps on unaligned access, then the compiler can and should simply generate the correct code so that it loads the integer piece by piece instead.

LMAO what?!

The compiler should pessimize each and every memory access everywhere with an alignment check on the pointer and a branch, or forego the efficient memory access method of the platform entirely and just do bytewise loads only?!

Re: Everything in C is undefined behavior

#610

Earlier quoted context omitted.

Not true, C++ made it so trivial infinite loops are not UB because it turns out they do have legitimate uses. https://lists.isocpp.org/std-proposals/2020/05/1322.php https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p28...

Yes, the C++ committee has been making some stupid decisions lately. This is not the only one. Low level platform-specific code that needs to hot spin until an interrupt happens can use assembly for that part which it will need to do for the interrupt handler anyway.

You don't even need to use assembly for this, the wait for interrupt typically involves side effects.
Post reply on HN