Live data from Hacker News

Undefined behavior in C is a reading error

yodaiken.com

201–210 of 503 posts

Re: Undefined behavior in C is a reading error

#201
post #111

Earlier quoted context omitted.

Assuming you defined signed integer overflow to follow two’s complement rules (the only reasonable interpretation other than UB), it would still be a guaranteed loop count of 16. (EDIT: i’m a dumbass, this is obvs not true. disregard this paragraph) There’s an interesting thing to note with that example though: even if you did make signed integer overflow defined, that code is still obviously incorrect if param + 16…

The real problem is in a better world 'int' would be replaced by types that actually exhibit the correct behavior. for a loop counter you want an index type that will seg fault on overflow. If you think not having that check is worth it the programmer would need to tag it with unsafe. It's also problematic because it's size is defined as at least 16 bits. But programmers which means you should never use it to store a…

Many people write C programs that are not intended to be portable to 16-bit architectures.

Re: Undefined behavior in C is a reading error

#202

Two points: The notion that compilers that encounter undefined behavior are allowed to generate any code they want is a new interpretation, for some value of "new". I can't remember the first time I encountered such an interpretation being used by compiler writers to justify something they wanted to do until sometime after 2000. The notion that John Regehr has (quoted in the article) that undefined behavior implies t…

> Wouldn’t all sequence points executed before undefined behavior is encountered be required to occur as if the undefined behavior wasn’t there? It would seem so:

No. Code optimization is a series of logic proofs. It is like playing Minesweeper. If a revealed square has 1 neighboring mine and a count of 1, then you know that all 7 other squares are safe. In other Minesweeper situations you make a proof that is much more complex and allows you to clear squares many steps away from a revealed mine. If you make a false assumption of where a mine is, via a faulty proof, then you explode.

The compiler is exactly like that. "If there is only one possible code path through this function, then I can assume the range of inputs to this function, then I can assume which function generated those inputs..."

You can see how the compiler's optimization proof goes "back in time" proving further facts about the program's valid behavior.

If the only valid array indexes are 0 and 1 then the only valid values used to compute those indexes are those values that produce 0 and 1.

This isn't even program execution. In many cases the code is collapsed into precomputed results which is why code benchmarking is complicated and not for beginners. Many naive benchmark programs collapse 500 lines of code and loops into "xor eax,eax; ret;" A series of putchar, printf and puts calls can be reduced to a single fwrite and a malloc/free pair can be replaced with an implicit stack alloca because all Standard Library functions are known and defined and there is no need to actually call them as written.

Re: Undefined behavior in C is a reading error

#203
post #61
post #24

I think the real problem stems from the mismatch between modern processors and the processors C was originally designed for. C programmers want their code to be fast. Vanilla C no longer gives them the tools to do that on a modern processor. Either the language needs to be extended or the compiler needs to get more creative in interpreting the existing language. The latter is the least disruptive and it doesn't stop…

Even on modern processors, an ADD instruction does not corrupt memory. The C standard, in declaring that an integer overflow results in all-bets-are-off UB, is not enabling compilers to provide valuable optimizations.

It would be nice if that were true, but it's not. The ability to assume incrementing a counter won't overflow makes range analysis possible in many cases where it otherwise wouldn't be. Because of this you can perform vectorization because the compiler can assume it knows how many times the loop will run.

The performance differences are not small.

You can also tell some compilers to treat signed integer overflow as wrapping-- but people don't usually do this because the optimizations you lose are valuable.

Re: Undefined behavior in C is a reading error

#204

Earlier quoted context omitted.

That you wish that the C Standard mandated this interpretation does not change the fact that this is not what the C Standard says.

You are mistaken, the C standard is quite clear that it does not make any guarantees regarding the behavior of programs that exhibit undefined behavior, and that signed integer overflow is undefined behavior.

Perhaps there's an implicit quantifier here: "for all valid implementations of the C standard, the loop count is guaranteed to be 16" versus "there exists a valid implementation of the C standard in which...".

Re: Undefined behavior in C is a reading error

#205

Earlier quoted context omitted.

That you wish that the C Standard mandated this interpretation does not change the fact that this is not what the C Standard says.

You are mistaken, the C standard is quite clear that it does not make any guarantees regarding the behavior of programs that exhibit undefined behavior, and that signed integer overflow is undefined behavior.

Perhaps there's an implicit quantifier here: "for all valid implementations of the C standard, the loop count is guaranteed to be 16" versus "there exists a valid implementation of the C standard in which...".

(This line of thought inspired by RankNTypes, "who chooses the type", etc.)

Re: Undefined behavior in C is a reading error

#206
post #149

Because there seems to be some confusion in this thread: - "Implementation-defined behavior" means that the C standard specifies the allowable behaviors that a C implementation must choose from, and the implementation must document its particular choice. - "Unspecified behavior" means that the C standard places no particular restrictions on the behavior, but a C implementation must pick a behavior and document its ch…

I would note that the article is explicitly contesting the definition of UB that you are giving here (though you are absolutely right that this is the de facto definition used by all major compilers, and the commtitee).

Basically the article is arguing that UB should be similar to Unspecified behavior - behavior that the implementation leaves up to the hardware and/or OS.

I'm not sure where I fall to this issue, though I would note that the definition of UB in the standard needs quite a bit of interpretation to arrive at the commonly used definition you are quoting. That is, while I think the definition you give is compatible with the one in the standard, I don't think it is the definition of the standard, which is much softer about how UB should impact the semantics of a C program. In particular, nothing in the wording of the standard expliclty says that an implementation is expected to assume UB doesn't happen, or that a standard-conforming program can't have UB.

Re: Undefined behavior in C is a reading error

#207

Earlier quoted context omitted.

Another thing is that the wording around some of the UB issues is just plain bad. The most extreme probably is the rules around strict aliasing. That there, for quite a while, was uncertainty whether the rules allow type punning by reading a union member when the last write was to another member of a good example of not taking reality into account. Yes memcpy exists - but it is even less type safe!

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.

Re: Undefined behavior in C is a reading error

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

> The article links to this [1] discussion. The link is supposed to show the peculiar arguments used by proponents of current behavior. What I read there is someone lashing out, calling names, and grand-standing.

Even worse, the person who raised that issue is mostly just wrong: the code they wrote had not worked with any optimizations turned on for about 13 years at the time they raised that bug. Teh fact that it worked in debug builds seems irrelevant, so the whole bug is complaining about a change that had no impact on the 99% of released code which is compiled with -O2 or -O3.

Re: Undefined behavior in C is a reading error

#209
post #184

Earlier quoted context omitted.

The real problem is in a better world 'int' would be replaced by types that actually exhibit the correct behavior. for a loop counter you want an index type that will seg fault on overflow. If you think not having that check is worth it the programmer would need to tag it with unsafe. It's also problematic because it's size is defined as at least 16 bits. But programmers which means you should never use it to store a…

I’m not sure I agree. If signed overflow is UB, loops like this can be optimized the hell out of. The most obvious way would be to unroll it and eliminate the loop (and loop variable) entirely, but you can also do things like vectorize it, maybe turn it in to just a small number of SIMD instructions. The performance gains are potentially enormous if this is in a hot loop. With your magic int that traps on overflow, y…

The broader argument is that signedness of the integer type used for indexing is a non-obvious gotcha affecting vectorizability. It makes sense once you understand C integer semantics, but putting on a language designer hat, I'd go with something more explicit.

Re: Undefined behavior in C is a reading error

#210

Earlier quoted context omitted.

> In my mind it's 100% not okay to (by default) optimize away a check for integer overflow. But a + 100 > a is not a check for overflow. If a >= INT_MAX - 100, it is an overflow. The "will this operation overflow" check would be a >= INT_MAX - 100, and GCC would not optimize that away.

What you've written doesn't demonstrate the issue outlined in the big report. The issue is that real-world code defends against certain hostile inputs like so, and that the optimization breaks those defenses: int a,b,c; a=INT_MAX; /\* statement ONE */ b=a+2; /* statement TWO */ c=(b>a); /* statement THREE \*/ Whether or not you think this is technically permissible by a sufficiently self-serving (from the perspective…

If you want pragmatism, check whether something is legal before you do it.
Post reply on HN