Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

381–390 of 748 posts

Re: Everything in C is undefined behavior

#381

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 f…

Casting to a pointer of incompatible type is UB. The exception is casting to char*.

Re: Everything in C is undefined behavior

#382
post #337

Earlier quoted context omitted.

Great, can you fit it into 768 bytes of flash and 64 bytes of RAM?

It isn't 1970 anymore. You can get 32-bit ARM MCUs with tens of kilobytes of flash and multiple kilobytes of RAM for less than 10 cents. We've long since reached a point where chips are cheap enough to be disposable. They are included in paper transit tickets and price tags. There is basically no market left where your volume is small enough that custom application-specific ICs aren't an option, but your volume is la…

> It isn't 1970 anymore. You can get 32-bit ARM MCUs with tens of kilobytes of flash and multiple kilobytes of RAM for less than 10 cents.

Do they run at single-digit nA current draw?

Re: Everything in C is undefined behavior

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

> In C, we can have a data race on a single thread and without any writes!

Well, sure, that's what volatile means - that the value may be changed by something else. If it's a global variable then the something else might be an interrupt or signal handler, not just another thread. If it's a pointer to something (i.e. read from a specific address) then that could be a hardware device register who's value is changing.

The concept of a volatile variable isn't the problem - any language that is going to support writing interrupt routines and memory mapped I/O needs to have some way of telling the compiler "don't optimize this out" since reading from the same hardware device register twice isn't like reading from the same memory location twice.

I think the problem here is more that not all of the interactions between language features and restrictions have been fully thought out. It's pretty stupid to be able to explicity tell the language "this value can change at any time", and for it to still consider certain uses of that value as UB since it can change at any time! There should have been a carve out in the "unsequenced side effect" definitions for volatile variables.

Re: Everything in C is undefined behavior

#384
post #375
post #315

Earlier quoted context omitted.

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...

> that can easily be solved by a minute or two on godbolt...

Unfortunately it's not that simple when it comes to UB. If the snippet in question does in fact exhibit UB then there's no guarantee whatever Godbolt shows will generalize to other programs/versions/compilers/environments/etc.

Re: Everything in C is undefined behavior

#386

The 5 stages of learning about UB in C: -Denial: "I know what signed overflow does on my machine." -Anger: "This compiler is trash! why doesn't it just do what I say!?" -Bargaining: "I'm submitting this proposal to wg14 to fix C..." -Depression: "Can you rely on C code for anything?" -Acceptance: "Just dont write UB."

What stage is the "just make the compiler define the undefined" stage? Unaligned access? Packed structs. Compiler will magically generate the correct code, as if it had always known how to do it right all along! Because it has, in fact, always known how to do it right. It just didn't. Strict aliasing? Union type punning. Literally documented to work in any compiler that matters, despite the holy C standard never sayi…

A lot of the Central UB can not be defined, because they rely on detection. In order to have a well defined behaviour (by the standard or the compiler) the implementation needs to first detect that the behaviour is triggered, this is often very tricky or expensive. Its easy to define that a program should halt, if it writes outside an array, but detecting if it does can be both slow and hard to implement. There are implementations that do, but they are rarely used outside of debugging.

A better way to think about UB is as a contract between developer and implementation, so that the implementations can more easily reason about the code. How would you optimize:

(x * 2) / 2

An optimizer can optimize this out for a signed integer, because it doesn't have to consider overflow, but with a unsigned integer it can not. UB is a big reason why C is the most power efficient high level language.

Re: Everything in C is undefined behavior

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

GCC -O1 and clang -O1 will both optimize this function under the assumption that inputs that cause signed integer overflow are never passed: int will_overflow(int a, int b) { int sum = a + b; if (b > 0 && sum

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

Re: Everything in C is undefined behavior

#389
post #372

Earlier quoted context omitted.

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

That they won’t is as most a courtesy to you but they are not required to do this.

Re: Everything in C is undefined behavior

#390
post #375
post #315

Earlier quoted context omitted.

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...

No, compilers will often choose to not optimize on UB.
Post reply on HN