News for hackers. Stuff that matters.
Re:“gcc will quietly break nearly half of all the packages t... by zzalpha on Saturday October 24, 2015 @11:50AM (#10443926)
Headline is misleading.

What's going on here is that the GCC developers feel free to change the generated code for behaviour undefined in the C spec. This means they might alter the behaviour of code since 40% of all packages in Debian (the "half of all packages" mentioned here) contain code whose behaviour is undefined.

But the poster seems to define any change in behaviour as "breaking" code, which is ridiculous. How much of that 40% is rare edge cases or similar, such that in reality the behaviour of the code doesn't change in practice?

The follow-up email raises this exact point, noting that in the specific example of pointer overflow:

In executions where overflow does not happen, the gcc produced binary will match the behavior of the abstract machine in the C spec.

Which means that the cited static analysis, while correctly identifying code containing UB, may not actually have an issue at runtime as the condition may never occur in practice.

The real problem is any software that truly relies on undefined behaviour for correct operation (which, I'll bet, is far less than the 40% cited here). That code is fundamentally non-portable to other compilers specifically because each compiler may produce semantically different output.

Re:“gcc will quietly break nearly half of all the packages t... by barrkel on Saturday October 24, 2015 @01:26PM (#10444235)
The real problem is any software that truly relies on undefined behaviour for correct operation (which, I'll bet, is far less than the 40% cited here).

I'd bet it's well into double digits relying on undefined behaviour, and over 50% relying on unspecified behaviour. It's hard to write interesting code in C that doesn't, where interesting means code that couldn't just as profitably be written in a different language with stronger memory safety.

Programmers have a mental model of many things - in particular, 2's complement signed numbers, and the idea that pointers are just numbers indexing memory - that are not guaranteed by the C spec. Much of the reason for programming in a lower level language is to take advantage of lower level machine characteristics, like tagged pointers, unsafe unions, structs with blobs of data appended to avoid an indirection, custom memory allocators, etc., but the C abstract machine doesn't necessarily give all the guarantees required, without a lot of care and attention to details.

Re:“gcc will quietly break nearly half of all the packages t... by makomk on Saturday October 24, 2015 @02:38PM (#10444453)
Even C compiler developers can't always get it right. There have been a few bugs where, for example, one compiler pass optimised a struct initialisation into a single write that wrote into the slack space after the end of the struct, and a subsequent pass detected this undefined behaviour and removed the initialisation altogether. (These optimisation tricks inherently make compiler development more risky, because they mean that composing safe compiler passes is likely to create something unsafe.)
[deleted]
Re:“gcc will quietly break nearly half of all the packages t... by DanWaterworth on Saturday October 24, 2015 @12:05PM (#10443982)
Just read the email.
Re:“gcc will quietly break nearly half of all the packages t... by zzalpha on Saturday October 24, 2015 @12:10PM (#10443994)
Actually it's still a useful question, I think.

A simple example is function argument evaluation order. If you have:

foo(bar(), baz())

A compiler is free to call these functions in either order. That means if baz relies on state mutated by bar, the program may behave differently if the compiler chooses to reorder evaluation.

Re:“gcc will quietly break nearly half of all the packages t... by copsarebastards on Saturday October 24, 2015 @12:32PM (#10444086)
There's a parable where a man goes to the doctor and says, "Doctor, whenever I drink my coffee with the spoon in the cup, the spoon handle pokes me in the eye and it hurts." And the doctor says, "Well, stop doing that."

If you wrote `foo(bar(), baz())` and `baz()` relies on state mutated by `bar()`, your code is bad, and you should feel bad, because experiencing those bad feelings is the way you learn to not write bad code. This code was wrong before the compiler reordered the calls, it just failed silently for a while. The compiler isn't responsible for fixing your bugs, you are.

People need to stop expecting other people to fix their problems.

Re:“gcc will quietly break nearly half of all the packages t... by zzalpha on Saturday October 24, 2015 @12:51PM (#10444141)
Uhh... The question was "what's an example of undefined behaviour". I gave one, specifically of an example that could realistically break by relying on undefined behaviour.

That's it. Simple education.

In the context of this post I think that's a good thing because not everyone will understand the topic.

You, however, seen to have read some sort of agenda in the question, which I find a little baffling...

Re:“gcc will quietly break nearly half of all the packages t... by copsarebastards on Saturday October 24, 2015 @01:15PM (#10444205)
You're right; I'm sorry for misreading your intention. I've edited my post so it's not as directed at you.
Re:“gcc will quietly break nearly half of all the packages t... by Dylan16807 on Saturday October 24, 2015 @01:47PM (#10444296)
But that's not "undefined behavior" either. The post misleads people.

Certain things are unspecified. It can call in any order for example.

Other things are undefined. If you do them your program is no longer valid at all, and can crash or corrupt.

Re:“gcc will quietly break nearly half of all the packages t... by nitrogen on Saturday October 24, 2015 @01:57PM (#10444330)
To reiterate/emphasize this point: "undefined", "unspecified", and a few other related terms are Things in C. They have specific, non-interchangeable, well-defined meanings in the C specifications.
Re:“gcc will quietly break nearly half of all the packages t... by dbaupp on Saturday October 24, 2015 @08:34PM (#10445437)
The eye-spoon defence of C undefined and unspecified behaviours is very unfortunate and misleading: it makes it sound like avoiding them is as easy as just taking a spoon out of a cup.

Theoretically "stop doing that" works... but history has shown that it really doesn't work in practice, in C, in programming more broadly, and, really, in any human endeavour ("planes don't need safety procedures, just stop making mistakes").

Re:“gcc will quietly break nearly half of all the packages t... by dvogel on Saturday October 24, 2015 @03:28PM (#10444577)
Who is at fault in your example becomes much less clear cut when you consider the variant where the author of foo doesn't have access to the source code of bar and baz and they only rely on shared state on some systems or in some corner cases.
Re:“gcc will quietly break nearly half of all the packages t... by snarfy on Saturday October 24, 2015 @12:51PM (#10444140)
If bar() returned the mutated state, he could just do:

    foo(baz(bar()))
Re:“gcc will quietly break nearly half of all the packages t... by copsarebastards on Saturday October 24, 2015 @01:43PM (#10444288)
I think a better design would be to separate mutators from pure functions. If a procedure mutates state, it should have a void return type, and if a procedure returns a value it should be a pure function that doesn't mutate state.

This is, of course, a rule of thumb, not a hard law. Some exceptions:

1. I think it's okay (and in fact, idiomatic in C) to mutate state and return some sort of information about what occurred (i.e. a success flag, a number of characters written, etc.).

2. Isolated mutations such as logging sometimes make sense in an otherwise pure function.

Re:“gcc will quietly break nearly half of all the packages t... by snarfy on Sunday October 25, 2015 @11:47AM (#10447169)
I'm a fan of fluent design myself, and dislike flags.

    return foo().baz().bar();
With flags you start with success/fail, and end up with HRESULT.
Re:“gcc will quietly break nearly half of all the packages t... by copsarebastards on Monday October 26, 2015 @04:21PM (#10454170)
I'd agree with you in some languages, but in C this would be prohibitively difficult. In general, good fluent design uses immutable objects, which makes it basically just a syntactic sugar for functional programming. While fluent syntax is nice, the functional semantics are the real value, and are much easier to do in C (although, as soon as you add in memory management, functional programming often becomes prohibitively difficult too).
Re:“gcc will quietly break nearly half of all the packages t... by tedunangst on Saturday October 24, 2015 @12:12PM (#10444011)
A perhaps more interesting, quite realistic example:

    lock_two_widgets(widget *a, widget *b) {
        if (a < b) {
            lock(&a->lock);
            lock(&b->lock);
        } else {
            lock(&b->lock);
            lock(&a->lock);
        }
    }
Re:“gcc will quietly break nearly half of all the packages t... by just_curioussss on Saturday October 24, 2015 @12:22PM (#10444037)
If lock calls include a memory barrier, which they should, then they cannot be reordered.

Edit: Your code has undefined behavior, unless the two pointers point to the same object, which is unlikely in a realistic example.

Re:“gcc will quietly break nearly half of all the packages t... by ufo on Saturday October 24, 2015 @12:43PM (#10444119)
Yes, the pointer comparison is UB but if the compiler didn't go out of its way to screw you over UB code then it would be a reasonable way to prevent deadlock.
Re:“gcc will quietly break nearly half of all the packages t... by just_curioussss on Saturday October 24, 2015 @12:49PM (#10444131)
There is a defined method for comparing such pointers. Take unsigned char pointers to them and inspect their bytes. Then write your code, using that information, that does the comparison, assuming you know your architecture.

It is defined behavior to read the bytes of any object using unsigned char.

Re:“gcc will quietly break nearly half of all the packages t... by kbwt on Saturday October 24, 2015 @01:05PM (#10444178)
Alternatively, if the implementation supports uintptr_t, you can convert to that and then compare the respective integral values.
Re:“gcc will quietly break nearly half of all the packages t... by DanWaterworth on Saturday October 24, 2015 @12:23PM (#10444045)
Right, because you can get to the end of a non-void function without producing a value. The pointer comparison isn't necessarily UB.
Re:“gcc will quietly break nearly half of all the packages t... by just_curioussss on Saturday October 24, 2015 @12:35PM (#10444099)
That is called unspecified behavior not undefined behavior. Major difference.
Re:“gcc will quietly break nearly half of all the packages t... by mlvljr on Saturday October 24, 2015 @12:55PM (#10444150)
Not many know (and less people care), funnily :)

I have yet to see a thorough (source-to-compiler-intent-to-assembly) comparative description of undefined, unspecified and implementation-defined behaviors, though (not just a somewhat insightful blog, or techno gospel, which the C and C++ standards are).

Re:“gcc will quietly break nearly half of all the packages t... by nitrogen on Saturday October 24, 2015 @02:03PM (#10444353)
You could always write one. I recommend the work of John Regehr as a starting reference: http://blog.regehr.org/
Re:“gcc will quietly break nearly half of all the packages t... by mlvljr on Saturday October 24, 2015 @02:59PM (#10444514)
I wish I had time to learn this first :)

But yes, authoring a book titled "Well-defined C (and C++)" one day would be awesome.

Thanks for the link.

Re:“gcc will quietly break nearly half of all the packages t... by coherentpony on Saturday October 24, 2015 @01:01PM (#10444164)
Nasal demons.