Live data from Hacker News

Undefined behavior in C is a reading error

yodaiken.com

451–460 of 503 posts

Re: Undefined behavior in C is a reading error

#451

It's easy to pick on undefined behavior in C when you focus on the more gratuitous undefined behaviors such as signed overflow or oversized shifts. I'm not certain why these are undefined behavior instead of implementation-defined, but my suspicion is that these caused traps on some processors, and traps are inherently undefined behavior. Instead, if you dislike undefined behavior, I challenge you to come up with wor…

I'll bite. > int x = cond ? 2 : y; /* Is it legal to fold this to int x = 2; ? */ This is permissible (on typical hardware) only if the implementation chooses to 'initialize' y to 2 (possibly skipping the actual write if it is later overwritten), since doing otherwise would result in: int x1 = cond1 ? 2 : y; /* So int x1 = 2; */ int x2 = cond2 ? 3 : y; /* So int x2 = 3; */ No, no it may not do that. Edit1: actually,…

> This is permissible (on typical hardware)

Hardware doesn't define C semantics. C defines C semantics. I don't understand what your conditional example is trying to say, but you seem to assume that an uninitialized y is an actual uninitialized register or memory location. It's not.

>> A function marked _Noreturn returns.

> If written in C, the body of the function must include a return statement, and is thus a compile time error.

It might contain a return statement that is never reached because the function goes into an infinite loop or exits/aborts the program or does a longjmp.

Re: Undefined behavior in C is a reading error

#452

Earlier quoted context omitted.

You changed writes to indices offset..offset+15 to writes to indices 0..15.

the offset is used to compute the index, not the count.

But you're not using the offset to compute the index in bar().

    void foo(int offset, int *arr) {
        for(int i = offset; i 
If you call this with offset = 100, the arr[i] in the loop will write to arr[100], arr[101], ..., arr[115].

    void bar(unsigned int offset, int *arr) {
        if(offset+16 
If you call this with offset = 100, the arr[i] in the loop will write to arr[0], arr[1], ..., arr[15].

Re: Undefined behavior in C is a reading error

#453

Earlier quoted context omitted.

I'll bite. > int x = cond ? 2 : y; /* Is it legal to fold this to int x = 2; ? */ This is permissible (on typical hardware) only if the implementation chooses to 'initialize' y to 2 (possibly skipping the actual write if it is later overwritten), since doing otherwise would result in: int x1 = cond1 ? 2 : y; /* So int x1 = 2; */ int x2 = cond2 ? 3 : y; /* So int x2 = 3; */ No, no it may not do that. Edit1: actually,…

> This is permissible (on typical hardware) Hardware doesn't define C semantics. C defines C semantics. I don't understand what your conditional example is trying to say, but you seem to assume that an uninitialized y is an actual uninitialized register or memory location. It's not. >> A function marked _Noreturn returns. > If written in C, the body of the function must include a return statement, and is thus a compi…

> Hardware doesn't define C semantics. C defines C semantics.

C does not define C sematics for undefined behaviour; that's what makes it undefined behaviour.

> an uninitialized y is an actual uninitialized register or memory location.

On typical hardware, yes.

Re: Undefined behavior in C is a reading error

#454
post #207

Earlier quoted context omitted.

The union punning trick is UB in C89 and well-defined in C99 and later, although it was erroneously listed in the (non-normative) Annex listing UBs in C99 (removed by C11). Strict aliasing is another category of UB that I'd consider gratuitous.

> Strict aliasing is another category of UB that I'd consider gratuitous. Without it you cannot vectorize (or even internally re-order) many loops which are currently vectorizable because the compiler can't statically prove arguments won't alias otherwise.

That is completely false. Look up "restrict" and there are many other contexts. BTW, "prove" and "assume" are different things. This is an old argument, which in a just world would have been settled by Dennis Ritchie's comments.

Re: Undefined behavior in C is a reading error

#455

Earlier quoted context omitted.

> This is permissible (on typical hardware) Hardware doesn't define C semantics. C defines C semantics. I don't understand what your conditional example is trying to say, but you seem to assume that an uninitialized y is an actual uninitialized register or memory location. It's not. >> A function marked _Noreturn returns. > If written in C, the body of the function must include a return statement, and is thus a compi…

> Hardware doesn't define C semantics. C defines C semantics. C does not define C sematics for undefined behaviour ; that's what makes it undefined behaviour. > an uninitialized y is an actual uninitialized register or memory location. On typical hardware, yes.

>> an uninitialized y is an actual uninitialized register or memory location.

> On typical hardware, yes.

Maybe you can help me identify the register or memory location for y in your example: https://gcc.godbolt.org/z/3b4z56Y87

Re: Undefined behavior in C is a reading error

#456

Earlier quoted context omitted.

> Would something like "Program behavior on overflow is determined by processor model and configuration" not work? Not sure; if nothing else, that seems like it would allow the implementation to avoid documenting any implementation-defined behaviour with a blanket "all implementation-defined behaviour is whatever the hardware happens to do when executing the relevant code".

I mean, that works ? It's not great by any means, but it at least eliminates the ability to make the assumptions underlying more aggressive optimizations, which seems like it'd address one of the bigger concerns around said optimizations.

Perhaps I should have phrased it as "all implementation-defined behaviour is whatever the hardware happens to do when executing whatever code the compiler happens to generate".

The point of implementation-defined behaviour is that the implementation should be required to actually define the behaviour. Whereas undefined behaviour doesn't impose any requirements; the implementation can do whatever seems reasonable on a given hardware architechure. That doesn't mean that backdoor-injection malware pretending to be a implementation is a conforming implementation.

Re: Undefined behavior in C is a reading error

#457
post #165

Quoting from the same passage in the standard as the article does: > Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to ... Ignoring the situation completely with unpredictable results seems like it covers the current compiler behavior. The author does not like how current compilers work. But his argument against it mixes "it would be better if it worked differ…

> ignoring the situation completely with unpredictable results That needn't mean "delete the code". TFA is certainly right that this situation is killing C. But then, so is C's old type model. Rust is clearly better, so it's just as well. That said, I think the C99 UB stance is a disaster for any language that might adopt it. Perhaps the standard should not define `1 (char )0`, or signed integer overflow. But it's ea…

> 1. write your own compiler that does it right (ETOOHARD now that clang didn't)

The problem here is that "right" is not quite that black-and-white. To a lot of users, "right" is "my code appears to work," optionally with "at a given performance level." A new compiler that's slower, or changes semantics compared to some baseline, won't necessarily be seen as "better" unless there's some clear benefit, and "doesn't perform optimizations that may result in security holes" wasn't necessarily a clear benefit at the time clang was trying to gain traction. "Better error messages" and "faster compiles", on the other hand, were, and those were some of the reasons Clang gained adoption despite (sometimes?) producing slower programs.

It's somewhat analogous to Microsoft's dedication to backwards compatibility. If a program did something technically illegal and a later version of Windows broke the program, users tend to blame Microsoft and/or Windows, not the program. Same thing here - if Clang didn't perform such aggressive optimization and was slower than GCC because of it, users will tend to think "Clang is slow", not "GCC is making nonsensical optimizations" or "My program invokes UB".

Re: Undefined behavior in C is a reading error

#458
post #429

Earlier quoted context omitted.

Syscalls are not any more UB than any other function call, though. Whether talking about write(2) or my_foo(), the call has the semantics given by the function signature visible in the current translation unit. Sure, the C standard doesn't define what write(2)'s effects will be, but that does not mean that calling it is UB according to the standard. If the function has not been declared by the time it is first used,…

> Sure, the C standard doesn't define what write(2)'s effects will be, but that does not mean that calling it is UB according to the standard. Yes, it does. I already explained exactly why it needs to be UB, but let me quote where the standard says so: C99 6.9 External definitions: > Semantics: > An external definition is an external declaration that is also a definition of a function (other than an inline definition…

> let me quote where the standard says so:

Wouldn't this hinge on what precisely "entire program" means? A definition for write(2) may not appear in the source code you wrote, but if "entire program" includes e.g., libraries dynamically linked in then it's quite feasible for the end result to be fully defined.

For example, 5.2.2 Paragraph 2 starts with (emphasis added):

> In the set of translation units and libraries that constitutes an entire program

Re: Undefined behavior in C is a reading error

#459

Earlier quoted context omitted.

the offset is used to compute the index, not the count.

But you're not using the offset to compute the index in bar(). void foo(int offset, int *arr) { for(int i = offset; i If you call this with offset = 100, the arr[i] in the loop will write to arr[100], arr[101], ..., arr[115]. void bar(unsigned int offset, int *arr) { if(offset+16 If you call this with offset = 100, the arr[i] in the loop will write to arr[0], arr[1], ..., arr[15].

Fixed it, but same kind of result

https://gcc.godbolt.org/z/hx1zjE5xW

Re: Undefined behavior in C is a reading error

#460

Earlier quoted context omitted.

C is designed to allow programmers to insert or remove checks as performance tuning. Compiler UB "optimizations" that remove that ability from the programmer make the language unusable.

Not knowing what is UB in C is equivalent to not knowing a core part of the C language. In that situation, yes, C would seem unusable for people who have superficial knowledge of it.

Nobody knows UB rules. The WG14 discussions are full of confusion.
Post reply on HN