Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

431–440 of 748 posts

Re: Everything in C is undefined behavior

#431

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…

This series was a good explanation for me of why treating UB this way is genuinely useful: https://blog.llvm.org/2011/05/what-every-c-programmer-should... Being able to assume certain things don't happen is powerful when you're writing optimisations, not doing that would have a real performance cost

> Being able to assume certain things don't happen is powerful when you're writing optimisations, not doing that would have a real performance cost

A few of those are significant performance gains, the majority are not.

Emitting the instruction for a NULL pointer dereference is effectively no more costly than not emitting that instruction.

It's the code removal that's killing me.

Re: Everything in C is undefined behavior

#432
post #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*.

Tell me why struct* is incompatible with void* when it's such a standard case in C that you don't need a cast:

    struct foo *x = malloc(sizeof(struct foo)); /* malloc returns void* */
Or rather, tell me why the C11 standards committee decided to declare that struct* is incompatible with a void*

Re: Everything in C is undefined behavior

#433

Earlier quoted context omitted.

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?

You can do something like

       (y > 0 && x > INT_MAX - y) 
    || (y 
and hope the optimizer turns it back into just checking the result. Or you use -fwrapv to concretize the ISO ambiguity and specify the natural two's complement semantics, checking overflow with the classic Hacker's Delight formula;

    ((x ^ s) & (y ^ s)) 
But the best way is to use the intrinsic __builtin_add_overflow or, depending on compiler support, its C23 standardization via and ckd_add etc.

Re: Everything in C is undefined behavior

#434

Earlier quoted context omitted.

This series was a good explanation for me of why treating UB this way is genuinely useful: https://blog.llvm.org/2011/05/what-every-c-programmer-should... Being able to assume certain things don't happen is powerful when you're writing optimisations, not doing that would have a real performance cost

> Being able to assume certain things don't happen is powerful when you're writing optimisations, not doing that would have a real performance cost A few of those are significant performance gains, the majority are not. Emitting the instruction for a NULL pointer dereference is effectively no more costly than not emitting that instruction. It's the code removal that's killing me.

What if the compiler is able to use that to determine that a whole code path is dead, and then significantly improve the surrounding function because of that?

Compilers optimise in multiple passes and removing things earlier can expose optimisation opportunities later that can affect other parts of the code too

Re: Everything in C is undefined behavior

#435
post #416

Earlier quoted context omitted.

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

That quote doesn't have anything to do with parameter evaluation order. There is no order for function parameter evaluation.

And no, there is no exception for undefined behavior. There can't be, otherwise the behavior would be... defined. It's in the name. Again, what do you think the compiler emits when the undefined behavior causes the program to not compile altogether?

Re: Everything in C is undefined behavior

#436

Earlier quoted context omitted.

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.

I think it’s a really easy sell, actually: if you go past the end of the array far enough you end up accessing the stack which includes parts of the program like “where does this function return to” or “what is the index used to perform this access” or “there is no page mapped there”. None of these are arbitrary values.

The "anything can happen" means that the compiler can simply silently refuse to emit the code does the access.

Documenting that the instructions to access will always be eliminated makes it easier to predict what will happen.

Re: Everything in C is undefined behavior

#437

Earlier quoted context omitted.

The list of UB categories and rules is not infinite. The list of UB programs is, as is the list of all non UB programs.

It is not obvious to me that the list of categories is not infinite (unless the final category is "everything else" of course)

To be undefined behaviour, it must at least be valid syntax. The syntax is described in a finite document. Also it only gets executed by a finite machine, that has a finite number of finite descriptive documents.

Re: Everything in C is undefined behavior

#439

Earlier quoted context omitted.

> Being able to assume certain things don't happen is powerful when you're writing optimisations, not doing that would have a real performance cost A few of those are significant performance gains, the majority are not. Emitting the instruction for a NULL pointer dereference is effectively no more costly than not emitting that instruction. It's the code removal that's killing me.

What if the compiler is able to use that to determine that a whole code path is dead, and then significantly improve the surrounding function because of that? Compilers optimise in multiple passes and removing things earlier can expose optimisation opportunities later that can affect other parts of the code too

> What if the compiler is able to use that to determine that a whole code path is dead,

Then it should warn "unreachable code".

> and then significantly improve the surrounding function because of that?

It's not simply the removal that is the problem, it's that the code is silently removed.

Post reply on HN