Live data from Hacker News

Falsehoods programmers believe about undefined behavior

predr.ag

101–110 of 233 posts

Re: Falsehoods programmers believe about undefined behavior

#101

It's surprising to see so much debate about when or where UB "happens". Unfortunately this article doesn't refer to the best tool to root out UB - UBSan. If you write C or C++, you should have a UBSan+ASan build that is configured to terminate with an error when it encounters violations. You'll save yourself a lot of hair-pulling later. Then you don't have to wonder about the nebulous topics like what "line" the UB "…

I really hope that Windows Clang would soon support UBSan. It already supports ASan and is really helpful, but sometimes you need to go the extra mile to catch the most hard-to-find errors.

Re: Falsehoods programmers believe about undefined behavior

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

Presumably (and really don't take my word for this - I'm a Java bod) the p dereference needs to come before the p NULL check for the p NULL check to be ignored. (Otherwise, how can a NULL check protect a dereference.) And therefore, the NULL check would be unreachable as well, and therefore never executed and not relevant.

Please correct my misunderstanding...

Re: Falsehoods programmers believe about undefined behavior

#103

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

This [0] is the linked article for that point, I don’t do systems programming, so I can’t say I understand if this is trivial or not ;) [0]: https://www.ralfj.de/blog/2020/07/15/unused-data.html

The linked article argues that making storing invalid values in the bool undefined (rather than just using such bools) is important because otherwise the compiler is not allowed to move the code (without adding appropriate checks that it would have been reached). The compiler can only make that transformation if it has no effect on any cases where the code wasn't reached at all, which includes not introducing any new UB in those cases. Predrag conclusion that this means having UB in dead code matters is simply wrong.

Re: Falsehoods programmers believe about undefined behavior

#104
post #31

Earlier quoted context omitted.

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

The undefined behavior can still affect code generation even though the program gets translated.

It's just that the generated code may not do exactly what you expect it to do because the presence of undefined behavior allowed the compiler to make assumptions which may surprise you.

edit: It seems that I am incorrect

Re: Falsehoods programmers believe about undefined behavior

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

Yes, thank you. It's clear these points are incorrect if you consider the purpose of undefined behavior. Compilers are allowed to assume undefined behavior is never invoked (which may be useful for optimization and other reasons); it is a promise from the programmer that they will not invoke undefined behavior specifically so that the compiler may assume they don't. Things are often made undefined behavior because the assumption is useful, but hard or impossible to prove in general with static analysis, so it requires a programmer who can consider the context of the code to assure the assumption always holds. If undefined behavior is invoked, some of the compiler's assumptions are wrong, so anything could happen (see the "principle of explosion"[1]). If no undefined behavior is invoked, all of the compiler's assumptions are correct, so the program must behave correctly.

For example, imagine a C programmer writes a function that adds two `int` values. Hypothetically, with some inputs, the addition may overflow. That would be undefined behavior, so the compiler assumes the function is never called with such inputs, and optimizes accordingly. The programmer knows this, and assures the function is never called with those inputs. Since the only assumption the compiler made was that the function wasn't called with input which would cause the addition to overflow, and the programmer assured that assumption is correct, the function always behaves correctly.

Consider if the same function's inputs were provided at runtime from stdin. The behavior of the whole program is undefined if invalid inputs are given, but if only valid inputs are given, the program must behave correctly.

[1]: https://en.wikipedia.org/wiki/Principle_of_explosion

Re: Falsehoods programmers believe about undefined behavior

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

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

No it won't. Otherwise all precondition checks would be meaningless. The compiler can only assume that it isn't null when fermats_last_theorem_is_wrong() is true. If the compiler cannot reason about fermats_last_theorem_is_wrong() then it can't just ignore it.

> for(int i=0; i > n;) { } *p=1;

> Here the compiler will assume that the loop terminates, since non-terminating loops without side-effects are UB in C++.

Infinite loops are UB precisely because otherwise the compiler would NOT be able to reason about this. So yes, here the comiler can assume that p is a valid pointer - but only because it can also assume that *p=1 is NOT dead. This falls entirely under the umbrella of behavior not being defined at all after you execute undefined behavior (the infinite loop).

> This remains valid even if you call this function with an n such that *p=1 is unreachable.

Only because the loop itself is undefined behavior in that case.

Re: Falsehoods programmers believe about undefined behavior

#107
I have a suggestion - it may be completely off the wall, but hear me out.

C needs a mechanism to declare in a source file that certain behaviour must be defined, where that behaviour is undefined in the C standard but the target architecture behaves the defined way. Then, when the source is compiled on the target architecture it works as expected, but when compiled on something else it refuses to compile.

For example, unsigned ints. It'd be great to be able to declare "I define int to be 32 bits and to overflow like a sensible 32-bit int - treat this as defined behaviour, and refuse to compile on a system where this isn't true." The number of platforms where this would fail to compile would be extremely small, and at least they would give a sensible compile error on systems that are weird.

Re: Falsehoods programmers believe about undefined behavior

#108

Earlier quoted context omitted.

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…

Presumably (and really don't take my word for this - I'm a Java bod) the p dereference needs to come before the p NULL check for the p NULL check to be ignored. (Otherwise, how can a NULL check protect a dereference.) And therefore, the NULL check would be unreachable as well, and therefore never executed and not relevant. Please correct my misunderstanding...

Nope, the C spec is just really bad. The NULL check is allowed to be removed.

Re: Falsehoods programmers believe about undefined behavior

#109

I have a suggestion - it may be completely off the wall, but hear me out. C needs a mechanism to declare in a source file that certain behaviour must be defined, where that behaviour is undefined in the C standard but the target architecture behaves the defined way. Then, when the source is compiled on the target architecture it works as expected, but when compiled on something else it refuses to compile. For example…

I have almost no idea about C compilation but would it be possible with macros or somehow redefining int?

Re: Falsehoods programmers believe about undefined behavior

#110
post #104

Earlier quoted context omitted.

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

The undefined behavior can still affect code generation even though the program gets translated. It's just that the generated code may not do exactly what you expect it to do because the presence of undefined behavior allowed the compiler to make assumptions which may surprise you. edit: It seems that I am incorrect

DR 109 allows that a program may be strictly conforming even if some possible executions of the program invoke UB:

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

This text specifically allows for the case that a program is strictly conforming even if there is a possible execution that invokes UB. If a program is strictly conforming, it must produce the correct behavior.

I would challenge you to show an example where GCC or Clang will break the correctness of a program on account of UB that is not reached during program execution.

Here is an example where GCC and Clang specifically respects the correctness of a program as long as it does not reach the UB: https://godbolt.org/z/befWah77W

Post reply on HN