Live data from Hacker News

Falsehoods programmers believe about undefined behavior

predr.ag

91–100 of 233 posts

Re: Falsehoods programmers believe about undefined behavior

#91
post #87
post #22

13. But if the line with UB isn't executed, then the program will work normally as if the UB wasn't there. 14. Okay, but if the line with UB is unreachable (dead) code, then it's as if the UB wasn't there. 15. If the line with UB is unreachable code, then the program won't crash because of the UB. 16. If the line with UB is unreachable code, then the program will at least stop running somehow and at some point. This…

Can someone with more knowledge chip in? If I define void bar(int* const p, int n) { for (int i=0; i it might get optimized via loop-invariant code motion to void bar(int* const p, int n) { int m = *p for (int i=0; i so it could still be UB when called with p=NULL and n=0, right? Edit: Oops, in the previous version I used a write instead of a read on *p, making the optimization invalid.

No, that transformation is straight-up buggy unless the compiler can also prove that n > 0 (ie by inlining the bar() function into a context where n is always positive).

If you had *p == 0 before calling bar(p, 0) then *p had better not be 1 after!

Re: Falsehoods programmers believe about undefined behavior

#92
post #22

13. But if the line with UB isn't executed, then the program will work normally as if the UB wasn't there. 14. Okay, but if the line with UB is unreachable (dead) code, then it's as if the UB wasn't there. 15. If the line with UB is unreachable code, then the program won't crash because of the UB. 16. If the line with UB is unreachable code, then the program will at least stop running somehow and at some point. This…

"The line with UB" becomes a very vague notion well before the program even executes. You can see this by dumping the disassembly of your program. The compiler can determine when values are defined and used and will emit code that satisfies the semantics of your program (according to the language specification). This often means that expressions within the same statement get evaluated at significantly different times…

The assembly dump does not matter for this analysis (except for finding buggy compilers!) - the C abstract machine itself applies all side-effects before each sequence point.

Re: Falsehoods programmers believe about undefined behavior

#93
post #15

Earlier quoted context omitted.

No, it isn't. The line with UB has to be reached in the execution for the execution to be undefined.

The compiler isn't required to know if code is unreachable. For example, `if (fermats_last_theorem_is_wrong()) {*p == 1} ` will imply to a modern compiler that p is not NULL in the scope where it is defined, even if we now know that this code will never be reached (assuming that function is correctly written). Or, here is a better example: for(int i=0; i > n;) { } *p=1; Here the compiler will assume that the loop ter…

The compiler is required to successfully translate a program that contains unreachable UB, and such a program is conforming if undefined behavior is never reached. This is explicitly spelled out in https://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_109.html

> Furthermore, if every possible execution of a given program would result in undefined behavior, the given program is not strictly conforming. A conforming implementation must not fail to translate a strictly conforming program simply because some possible execution of that program would result in undefined behavior. Because foo might never be called, the example given must be successfully translated by a conforming implementation.

Re: Falsehoods programmers believe about undefined behavior

#94

Earlier quoted context omitted.

That's irrelevant. A C compiler targetting x86 has no obligation at all to handle signed integer overflow in the same way the processor natively does. Because it is not an assembler - it is compiling against the theoretical C virtual machine. This is for the same sort of reason that unsigned overflow does have a well defined meaning in C, and will always do exactly that even for targets that do not natively do that (…

Compiler developers may not think they have that obligation, but they should

Should loop-invariant code motion be an allowed optimization only when the compiler can statically prove that a for loop's increment won't overflow?

Re: Falsehoods programmers believe about undefined behavior

#95
post #31

> 14. Okay, but if the line with UB is unreachable (dead) code, then it's as if the UB wasn't there. This one came as a surprise to me. Is this really (unconditionally) true? And if so, why? Seems trivial to me to ensure that UB that will never under any circumstance execute will not affect the functioning of an otherwise correct program.

The compiler may make optimization decisions based on the presence of UB so the code only needs to be present. The compiler can't know that an arbitrary part of a function is unreachable if, for instance, that code path is controlled by a parameter or global state since that equates to solving the halting problem. https://blog.llvm.org/2011/05/what-every-c-programmer-should...

I don't think this is correct. If UB is never invoked, the program is conforming and must be translated/executed correctly.

DR #109 specifically states that a compiler may not fail to translate a strictly conforming program just because some possible executions could trigger UB: https://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_109.html

Edit: downvoters, please explain your disagreement. I cited a primary document in support of my position.

Re: Falsehoods programmers believe about undefined behavior

#96
post #94

Earlier quoted context omitted.

Compiler developers may not think they have that obligation, but they should

Should loop-invariant code motion be an allowed optimization only when the compiler can statically prove that a for loop's increment won't overflow?

If it would result in different behavior in the event of an overflow (which I think is generally not the case), then no. A typical for loop (using <) can easily been seen to not overflow, so this is a rare case anyway. Loops using signed comparison with <= where the compiler can't rule overflow out should result in a compiler or linter warning.

Re: Falsehoods programmers believe about undefined behavior

#97

Earlier quoted context omitted.

We're re-litigating that other thread... but the function in the other thread had a conditional (trying to check for overflow after the fact) which would never be true, regardless of x. And it could statically prove this. And that proof, the compiler then decided to use to remove the code, ignoring the red flag that the programmer undoubtedly had tried (and failed!) to achieve something with it. I would have preferre…

While I agree that in general a warning about "condition is always true/false"-style checks is useful, it's also a bit tricky to do without false positives. With macros and inlining (and in C++, templates) you can easily end up with conditionals of which any given instance is always true or false, but that aren't superfluous. Portability is another example. Depending on your environment and code style hitting these m…

I also see this come up a lot in code generation and simd code. On the code generation it's way easier to just push all optimizations to the compiler, including constant propagation (i.e. easier to just mark an upstream boolean as constexpr true, instead of adding your own constant propagation). For simd it's common in my experience to do lots of (if size > X), where size and X are both known at compile time but might vary by target.

Re: Falsehoods programmers believe about undefined behavior

#98
post #8

Earlier quoted context omitted.

> gcc screwing the developer over because it was UB when they thought it was just implementation defined No, the developer thought "UB" produced an integer with an undefined (but still valid integral?) value. They misunderstood what UB is, not whether or not something was UB.

That's from the spec POV. On x86 for example, signed int overflow is well defined.

x86 also doesn't support 64 bit integers, so would those be entirely undefined behavior or simply compile time errors?

Re: Falsehoods programmers believe about undefined behavior

#99
post #15

> 14. Okay, but if the line with UB is unreachable (dead) code, then it's as if the UB wasn't there. This one came as a surprise to me. Is this really (unconditionally) true? And if so, why? Seems trivial to me to ensure that UB that will never under any circumstance execute will not affect the functioning of an otherwise correct program.

No, it isn't. The line with UB has to be reached in the execution for the execution to be undefined.

[deleted]
Post reply on HN