Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

531–540 of 748 posts

Re: Everything in C is undefined behavior

#531
post #223

Earlier quoted context omitted.

Not from the standard’s point of view. The traditional (in some circles) use of volatile for atomic variables was not sanctioned by the C11/C++11 thread model; if you want an atomic, write atomic, not volatile, or be aware of your dependency on a compiler (like MSVC) that explicitly amends the language definition so as to allow cross-thread access to volatile variables.

Thread was a poor choice of word. Outside the control of the program is a better way to put it. Like memory mapped io.

It's almost universally better to use inline assembly via a macro to read/write mmio rather than use volatile.

Re: Everything in C is undefined behavior

#532

Earlier quoted context omitted.

If that behavior is the entire point, then I think the bigger point is that the spec should reflect that and not call it undefined.

I suspect that many undefined behaviors reflect the inability of the standard committee to come to a consensus on the nuances involved. “Punt to the implementers” is a way to allow every tool vendor to select their own expected behavior in those cases.

You seem to be operating under the assumption "undefined behavior" means "the compiler authors can decide what to do." That's not what it means. It means "any program that causes this behavior to be triggered is not a valid C program, the programmer knows this and did not submit an invalid program, and the programmer explicitly prevented this from happening elsewhere in ways automated analysis cannot detect. Proceed with compilation knowing this branch is impossible."

The spelling for compiler authors getting to choose a behavior is "implementation defined", as the other comment mentions.

Re: Everything in C is undefined behavior

#533

Earlier quoted context omitted.

It is defined as an error. That error’s default handling is wrapping when debug_assertions is off, and panic when it’s on, but since it’s an incorrect program (though not UB) either behavior is acceptable in any mode.

If it is defined as an error, but the compiled build will continue to run with the value wrapped around, I would say that's indistinguishable from UB.

No. An integer getting deterministically set to an unintended value is a bug. A bug is not the same thing as UB. (Even if it were non-deterministic, it would still not be anything like UB.) It's not the same ballpark, not even the same sport.

Re: Everything in C is undefined behavior

#534

Earlier quoted context omitted.

"Just don't do that" is the correct approach to errors, even when they are easy to overlook and the programming language provides many opportunities for mistakes. For example, you seem to underestimate how wrong placing negative values in a signed char is: ordinary character encodings do not use negative codes, so either those negative values are not characters and they have no business being treated as such, or some…

> "Just don't do that" is the correct approach to errors We have 54 years of empirical data that literally nobody can follow this approach and reach UB-freeness. To stick to the plan is more like the in-debt gambler who just needs to work their system for a little longer, and they'll become rich. By this logic we don't need any traffic rules other than "just don't crash or hit anyone". And we can aspire to an absolut…

While, for the purpose of avoiding gratuitous mistakes, C is a serious disadvantage compared to less low-level languages, your discussion of UB pitfalls in C is aimed at a strawman.

First of all, traffic rules are good, and similar to good C programming rules: check number value ranges when there is a chance of casting or overflow, check Inf and NaN floating point values, declare alignment strategically (e.g. in all memory allocations) to avoid misaligned pointers and variables, and so on. Such rules have alternatives and exceptions and must not be part of the language.

Second, nobody needs perfection and "UB-freeness": it is reasonable to assume that many cases of UB won't be a problem, either because a library will be used correctly and they won't happen, or because the C implementation is neither weird nor hostile and they will be as benign as defined or implementation defined behaviour, or simply because we avoid doing something known to be inexact or hard to write correctly.

Practical programming requires knowing the relevant rules for what one is doing and learning new ones by making, diagnosing and overcoming mistakes; not omniscience, and definitely not the unfounded feeling of omniscience and unlimited resources that LLMs can give.

EDIT: I insist on the signed char example because it would be terribly wrong (processing who-knows-what as if it were a sequence of characters) even without undefined behaviour, even in different languages.

Re: Everything in C is undefined behavior

#535

Earlier quoted context omitted.

> because Assembly doesn't have UB To be pedantic, old hardware like 6502 family chips (Commodore 64, Apple II, etc) had illegal instructions which were often used by programmers, but it was completely up to the chip to do whatever it wanted with those like with UB.

> illegal instructions... were often used by programmers Intentionally, with an expected effect? I'd need a citation for that.

Some desultory googling turned up:

* https://www.nesdev.org/wiki/CPU_unofficial_opcodes#Games_usi...

* https://hitmen.c02.at/files/docs/c64/NoMoreSecrets-NMOS6510U... (doesn't name any software, but some copy protection schemes were already known to use them)

Re: Everything in C is undefined behavior

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

Volatile is a type system hack. They should have done a more principled fix, and certainly modern languages should not act as though "C did it" makes it a good idea. 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 wri…

By MMIO semantics do you mean explicit load and store instructions? I’ve never felt that pointer reads or writes were lacking descriptiveness here. I would argue the only surprising thing is that they might be optimized out (which is what volatile prevents).

Volatile on a non pointer value is not for MMIO, though, that’s typically for concurrency like with interrupts.

Re: Everything in C is undefined behavior

#538

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?

Hacker News is still skewed towards people interested in programming languages (as opposed to actually programming). Probably some sort of Y-combinator Lisp heritage. There's also a persistent minority of CS grads who think that developing / using new programming languages is the most fascinating thing in the world, and some of them hold on to that thought. It's reasonable that such people would also be interested in…

There was also a period around the mid-2010s where I had the strong impression that lots of younger ambitious devs were fanatically promoting rust against C's undefined behavior mostly because it gave them a way to differentiate themselves from older seniors within organizations. (And I say this not as an old C diehard, but as someone who watched more than one colleague position himself as the 'rust guy'.)

Re: Everything in C is undefined behavior

#539

Earlier quoted context omitted.

Turning undefined behavior into implementation defined behavior is rarely a fix, though.

It's a fix that removes the most pointy part of UB. "Going past the end of the array results in addressing arbitrary values" I can live with. "Going past the end of an array results in anything happening" is a hard sell.

Is that really a meaningful distinction?

Once you are addressing arbitrary values you are firmly in the realm of "anything happening" in practice, but you've now given up optimization opportunities. As has been repeatedly demonstrated over the years, once memory safety breaks it is practically impossible to make any guarantees about program behavior.

Re: Everything in C is undefined behavior

#540
I fear I will be downvoted into oblivion but I also want to learn from this.

First let me state the case for C. It’s meant to be used as a systems language that’s as close to assembly as possible while remaining portable (compared to assembly). As such it’s the first high-level language developed for any new processor.

Given the above predicate: Isn’t everything described in the article as it should be?

Add too much to the language and it becomes less possible to implement on new architectures, right? Because the undefined behavior lets implementors stand up new compilers fairly quickly.

For less undefined behavior isn’t it better to use languages that have that in their DNA? D, Zig, Go, Java, etc?

Post reply on HN