Slide 20 lists no less than 8 toolchain bugs found with a codebase of less than 50k lines of C code (no C++), using only thoroughly trodden language features, without "massive functions" or anything else. Admittedly 4 of those bugs were in pre-release versions of gcc, but the rest weren't.
Perhaps historically ICC was buggy, but I don't think it's true anymore. I often test highly optimized C code with GCC, Clang, and ICC, and anecdotally I'd say that the likelihood of hitting a compiler bug when compiling for a current Intel processor is about the same for each.
For me, crashing bugs and true miscompilation are rare with all three, but come up occasionally. Performance differences are usually within +/- 20% on microbenchmarks, with each having about equal chances of being the fastest or slowest.
The circumstances needed to trigger this bug weren't special, I never nailed it down entirely but it was just something like performing an integer division at just the wrong spot. Vararg function calls are extremely well trodden, and clang at the time was pretty mature. Yet there was a bug, all the same.
char key[5] = { 0 };
and the "fix": // Work around VC++ 2015 Update 1 code-gen bug:
// https://connect.microsoft.com/VisualStudio/feedback/details/2291638
key[4] = 0;
https://chromium.googlesource.com/chromium/third_party/ffmpe...(((av_alias32*)(key))->u32 = (argc));
The first problem is that an int may have an alignment constraint. Since writing an int to an allocation that is made based on char could violate this constraint, the code is invalid. It doesn't matter that x86 won't actually enforce this. The code is still invalid. Since that line of code is invalid, all code paths that will reach it are also invalid, as are all code paths from it. This makes the entire test program invalid; it is legit for the compiler to emit a program that immediately crashes or insults your mom.
The second problem is when the char array is checked to see if it contains the 42. An access as char is always permitted, so the code narrowly misses having an aliasing violation, but remember that the type AS ACTUALLY WRITTEN is not char. The only thing that can be legitimately done with the value is to write it elsewhere, for example when implementing a function like memcpy. An int need not be stored in little-endian form, big-endian form, two's complement, or anything else sane... and the language standard allows for this by prohibiting what this code is doing. As with the other bug: all code paths which involve the standards violation are invalid, making the whole test program invalid. The compiler is permitted to emit code that crashes or insults your mom.
gcc/clang are within their rights to break programs that break the aliasing rules, but VC++ is not required to do so and they choose not to.
There have been some excellent articles talking about how the current state of undefined behavior as understood by gcc/clang is crazy. One that I like is this one: http://blog.regehr.org/archives/761
Obviously some types of undefined behavior cannot be 'normalized', such as use-after-free, but treating the aliasing in that bug as undefined behavior is a committee decision that many developers think is ill advised.
Another recent article that I can't find pokes some holes in the idea that the latitude given to compilers by undefined behavior improves performance.
For your second example of undefined behavior I'm afraid I don't understand. Are you saying that even if the line of code that aliases the array is removed that "if (key[0] != 42)" is still undefined behavior? If so please explain. You say "the type AS ACTUALLY WRITTEN is not char" but I'm not sure what type you are referring to, and if you mean '42' that is true but not relevant because in a comparison between key[0] and '42' "key[0]" is converted to int by the standard integral conversions and then a particularly boring comparison is done.
If that code is undefined then the standards committee is definitely crazy and no code is conforming.
Reading it out as a long or float would be prohibited by aliasing rules, even if those types happen to be the same size. When you do "if(key[0] != 42)" you are reading out the value in key[0] as char, which is OK, but the content is undefined. You can't legitimately compare an undefined value with 42.
There is a special exception for char. You don't violate the aliasing rules when you load part of the int as a char. This special exception is very limited. It's for implementing functions like memcpy. (but not of that name, since "memcpy" is reserved)
The special exception doesn't make the data meaningful when loaded as char. The bits could be in any order. When you load part of an int into a char, the only legitimate thing you can do with it is to store it as if doing a memcpy.
Depending on how you read the C standard, you might even need an unsigned char to avoid trap representations. People argue this both ways.
That all said, not even gcc is this cruel.
Consider that entire industries (aerospace, etc) routinely ship code with compiler optimization disabled, to avoid getting bit by compilers trying to do clever things.
I have come across a lot of transient miscompilation in visual studio, I guess, usually when doing incremental rebuilds. I was thinking more of persistent miscompilations as things you are unlikely to find on the 'well trodden path'
https://connect.microsoft.com/VisualStudio/feedback/details/...
I didn't file a bug as it'd already been reported - although in my case, the trigger was using a logging macro which used __LINE__ from a lambda IIRC. Nothing terribly spectacular.
The last bug I remember reporting was default constructor parameters not instantiating templates correctly. Something like void f(int i = some_template<int>::func()); would fail to generate, and thus link against, some_template<int>::func. f might've needed to be a constructor. Sadly the connect bug is 404 and web.archive.org didn't capture the page. They said they would fix it in VS2008 SP2, but I ended up checking and finding they'd fixed it in SP1.
Even ignoring ICEs, I'd say I probably hit at least one confirmed compiler bug a year minimum when doing regular C++ development.