Can compiler optimization introduce bugs?
Asked Answered
J

22

75

Today I had a discussion with a friend of mine and we debated for a couple of hours about "compiler optimization".

I defended the point that sometimes, a compiler optimization might introduce bugs or at least, undesired behavior.

My friend totally disagreed, saying that "compilers are built by smart people and do smart things" and thus, can never go wrong.

He didn't convince me at all, but I have to admit I lack of real-life examples to strengthen my point.

Who is right here? If I am, do you have any real-life example where a compiler optimization produced a bug in the resulting software? If I'm mistaking, should I stop programming and learn fishing instead?

Jamal answered 27/4, 2010 at 15:1 Comment(10)
It's not common, but it happens. A Google search on codegen bug optimization turns up examples. Of course, compilers also have bugs without optimization enabled, so no, optimization is not the sole feature in the compiler which is defect-free. :)Finalize
"compilers are built by smart people and do smart things" and thus, can never go wrong - ha ha ha! If he believes that, give me his address - I've got a bridge that needs selling.Defalcation
@Neil - is the bridge optimized?Quart
@Quart - Doesn't matter, I'm sure it was built by smart people.Baiss
@Justin - I was about to comment that if they were smart, they'd be designing the bridge and not building it... and then I recalled the end of "Office Space" and realized you're right :)Quart
He obviously never had to deal with compiling C code.Roper
@CraigStuntz: I hope there aren't too many bug optimisations around! ;)Keane
connect.microsoft.com/VisualStudio/feedback/details/573262/… connect.microsoft.com/VisualStudio/feedback/details/766477/… connect.microsoft.com/VisualStudio/feedback/details/411031/… connect.microsoft.com/VisualStudio/feedback/details/676003/…Muscadine
When a programmer tells you that the compiler causes an error, it is a lie in 99% of cases. The compiler is to blame for everything: medium.com/@Code_Analysis/…Jakejakes
Weird question, but very well then, here's your proof: https://mcmap.net/q/17837/-compiler-bug-in-f-4Web
N
44

Compiler optimizations can introduce bugs or undesirable behaviour. That's why you can turn them off.

One example: a compiler can optimize the read/write access to a memory location, doing things like eliminating duplicate reads or duplicate writes, or re-ordering certain operations. If the memory location in question is only used by a single thread and is actually memory, that may be ok. But if the memory location is a hardware device IO register, then re-ordering or eliminating writes may be completely wrong. In this situation you normally have to write code knowing that the compiler might "optimize" it, and thus knowing that the naive approach doesn't work.

Update: As Adam Robinson pointed out in a comment, the scenario I describe above is more of a programming error than an optimizer error. But the point I was trying to illustrate is that some programs, which are otherwise correct, combined with some optimizations, which otherwise work properly, can introduce bugs in the program when they are combined together. In some cases the language specification says "You must do things this way because these kinds of optimizations may occur and your program will fail", in which case it's a bug in the code. But sometimes a compiler has a (usually optional) optimization feature that can generate incorrect code because the compiler is trying too hard to optimize the code or can't detect that the optimization is inappropriate. In this case the programmer must know when it is safe to turn on the optimization in question.

Another example: The linux kernel had a bug where a potentially NULL pointer was being dereferenced before a test for that pointer being null. However, in some cases it was possible to map memory to address zero, thus allowing the dereferencing to succeed. The compiler, upon noticing that the pointer was dereferenced, assumed that it couldn't be NULL, then removed the NULL test later and all the code in that branch. This introduced a security vulnerability into the code, as the function would proceed to use an invalid pointer containing attacker-supplied data. For cases where the pointer was legitimately null and the memory wasn't mapped to address zero, the kernel would still OOPS as before. So prior to optimization the code contained one bug; after it contained two, and one of them allowed a local root exploit.

CERT has a presentation called "Dangerous Optimizations and the Loss of Causality" by Robert C. Seacord which lists a lot of optimizations that introduce (or expose) bugs in programs. It discusses the various kinds of optimizations that are possible, from "doing what the hardware does" to "trap all possible undefined behaviour" to "do anything that's not disallowed".

Some examples of code that's perfectly fine until an aggressively-optimizing compiler gets its hands on it:

  • Checking for overflow

    // fails because the overflow test gets removed
    if (ptr + len < ptr || ptr + len > max) return EINVAL;
    
  • Using overflow artithmetic at all:

    // The compiler optimizes this to an infinite loop
    for (i = 1; i > 0; i += i) ++j;
    
  • Clearing memory of sensitive information:

    // the compiler can remove these "useless writes"
    memset(password_buffer, 0, sizeof(password_buffer));
    

The problem here is that compilers have, for decades, been less aggressive in optimization, and so generations of C programmers learn and understand things like fixed-size twos complement addition and how it overflows. Then the C language standard is amended by compiler developers, and the subtle rules change, despite the hardware not changing. The C language spec is a contract between the developers and compilers, but the terms of the agreement are subject to change over time and not everyone understands every detail, or agrees that the details are even sensible.

This is why most compilers offer flags to turn off (or turn on) optimizations. Is your program written with the understanding that integers might overflow? Then you should turn off overflow optimizations, because they can introduce bugs. Does your program strictly avoid aliasing pointers? Then you can turn on the optimizations that assume pointers are never aliased. Does your program try to clear memory to avoid leaking information? Oh, in that case you're out of luck: you either need to turn off dead-code-removal or you need to know, ahead of time, that your compiler is going to eliminate your "dead" code, and use some work-around for it.

Newport answered 27/4, 2010 at 15:5 Comment(37)
A more common reason to turn off optimizations is that debugging is usually harder with them on.Finalize
Non-volatile reads is a great example of misbehavior caused by compiler (or runtime) optimization, though I'm not sure if that's the sort of thing that one would classify as a "bug", since it's the duty of the developer to account for such things.Signesignet
@Adam Robinson: Agree completely. I've expanded on this point in my answer.Barbecue
Thank you for your answer. I love the "That's why you can turn them off" => Just unobjectionable ! ;)Jamal
The example given is why the "volatile" keyword exists. It's a code error. A bug-free compiler will not introduce bugs even with optimization.Firstfoot
Compiler optimization can bring existing bugs to the surface. Tghey (usually) introduce them - unless there's a compiler bug.Mellins
@Mr. Shiny has given his reason for believing why optimization can be turned off, but this is far from indisputable and I doubt it's explained as such in most compiler documentation. When debugging people typically want machine code that can be easily related to the original code and so would work with builds where optimization is turned off, while QA builds (and the final release) would have optimization turned on. Anyone who, on discovering an issue like the one described by @Mr. Shiny, then "fixes" it by turning optimization off is fixing the wrong thing in my opinion.Perren
Disagree. Optmizations may bring bugs in your code to the surface, and the optimizer itself may be buggy, but "optimization can introduce bugs" is factually wrong and also puts the blame on the wrong target.Mellins
This answer is simply wrong. All compiler optimizations must be fully compliant with with the language's standard. So compiler optimizations never introduce bugs in your code. Instead, they sometimes help you find hidden bugs that YOU have made. Of course, if there is a bug in the compiler itself, then your code might not be compiled correctly. But this doesn't mean that compiler optimizations can introduce bugs. It's an invalid argument,Rung
@HadiBrais You contradict yourself. If your compiler has a bug in an optimizer, then it introduces bugs in your code. I've encountered this many times. Also, here is an example of a compiler optimizing away a null-pointer check incorrectly. Sometimes certain optimizations are wrong for valid code.Enclose
@Mr.ShinyandNew安宇 A particular implementation of an optimizer can introduce bugs if it was buggy (which is obvious and no one disagrees). But compiler optimizations themselves don't introduce bugs because they are defined to be compliant with the the standard. Your answer is wrong because it does not answer the OP's question and has clearly confused many people including the OP.Rung
@HadiBrais did you follow the link I just gave you? GCC optimized away a null pointer check in a situation where null was a valid pointer. How is that not introducing a bug? The optimization may be legal, but it's wrong.Enclose
@Mr.ShinyandNew安宇 You're missing the point again and again. Regarding the example from link you provided, the compiler optimization didn't introduce any bugs. The bug was already there made by the programmer at line struct sock *sk = tun->sk; dereferencing tun without NULL-check. Second, the C++ standard states that NULL is a pointer to no object and cannot be dereferenced. Based on this, the compiler optimized the code, which is perfectly OK and compliant with the standard.Rung
@HadiBrais I'd say you're missing the point. The null pointer can be valid, no matter what the standard claims, as is evidenced by the fact that you can map a page at address zero. Removing the null check was not a valid optimization. There are other examples, such as re-ordering memory accesses that break double-checked locking, because re-ordering those accesses is valid on single-threads (but it's invalid in multi-threaded situations). The compiler doesn't always know the full details of the code. Sometimes its assumptions are wrong.Enclose
@Mr.ShinyandNew安宇 It doesn't matter whether a null pointer can be valid or not. All that matters is that the standard says it's invalid, and the compiler only has to conform to the standard. When a programmer writes code that violates the standard or when he doesn't understand the standard, he or she has to take full responsibility of the consequences. I've read all the "examples" in this thread and they are all invalid for the same reason.Rung
@HadiBrais So your position is that the spec is never wrong or incomplete, that compilers are never buggy, and that reasonable people can't disagree on what "correct" code is? Therefore, optimizations can never introduce bugs or undesirable behaviour. That's a pretty narrow way to look at things. In the world I live in, specs can be wrong or incomplete, optimizations can be valid only under certain conditions that aren't always true, optimizers can be wrong or buggy, etc.Enclose
@Mr.ShinyandNew安宇 Specs can be illogical or vague and compilers can be buggy. I never claimed otherwise. However, a compiler optimization can introduce bugs ONLY when it has bugs that have been triggered. This what I've said twice in my first and second comment. But the examples you've provided and your answer suggest that compiler optimizations can introduce bugs even if they are NOT buggy, which is where you're mistaken as I've explained several times.Rung
@HadiBrais Just because you've claimed something is true several times doesn't make it right. Firstly, the question asked "Can optimizers introduce bugs or undesirable behaviour" and there are several clear reasons why they can. This is indisputable. You are nitpicking about the supposed case where an optimizer is behaving correctly and merely exposing an existing bug (that doesn't exist outside of optimization).Enclose
Consider the fact that the C standard says that pointer overflow is undefined. The compiler takes this to mean that pointers can never overflow, when in reality they can. This means that a programmer who understands the hardware they're dealing with cannot actually check for pointer overflow easily, because the compiler writer can use "undefined behaviour" to introduce ANY code at all into the program. This is technically legal but logically stupid.Enclose
Also consider strict aliasing. If a compiler is assuming strict aliasing, it can optimize things better. strict aliasing isn't always appropriate though. Those optimizations would be "legal" but wrong.Enclose
@Mr.ShinyandNew安宇: It's too bad the authors of C89 were sloppy in their description of aliasing rules. Their intention was to draft rules with which the vast majority of existing code would already be in compliance, and the rules can be interpreted in such a fashion, but it has become fashionable to retroactively reinterpret the rules so to say that constructs which were in widespread use before C89 came on the scene were never legitimate, even if such reinterpretation of the rules would offer no alternative that was anywhere near as efficient.Papillon
What about optimizing out useless writes of zeroes to certain memory location? That can be fine security issue. And is perfect example of perfectly valid optimizer with perfect code and perfect compiler introducing a BUG. So yes, they can do just that.Mckinleymckinney
@Mckinleymckinney That example is in my answer, "Clearing memory of sensitive information".Enclose
I know but the one who was defending optimizations didn't seem to even notice this one example.Mckinleymckinney
@Mckinleymckinney That's also an invalid example because the standard allows the compiler to optimize memory reads and writes when the single-threaded observable behavior doesn't change and there is no undefined behavior. If the programmer misunderstood the language and thought that memset won't be optimized away, then it is the programmer that is at fault, it is the programmer that introduced the bug in the code, not the compiler. The programmer is supposed to use secure functions such as memset_s or SecureZeroMemory, which will not be optimized away...Rung
...This answer essentially says "optimizations can introduce bugs when the programmer misunderstands the language or expect things that are not guaranteed by the language", which makes no sense, and "optimizations can introduce bugs when the compiler has bugs", which is very obvious and is not what the OP question is about. Jon Skeet's answer is the correct answer.Rung
@HadiBrais Look, the fact is that compilers can not always know if the "single-threaded observable behaviour doesn't change". So instead they add hacks like memset_s. That's just weaseling out of their obligations to write usable software that doesn't surprise the user IMO.Enclose
I think my comments are very clear, as well as Jon Skeet's answer. The right thing to do now is to edit your answer to point future readers to Jon Skeet's answer. It's up to you now.Rung
@HadiBrais Sorry, from my perspective the evidence is clear that compiler optimizations have gone too far and too often cause problems by insisting on an interpretation of the rules that makes no sense; this combined with how the rules change over time means new compilers break old code in "legal" ways. I'll go as far as to say that the language specifications are themselves wrong in some cases and compiler writers are sneaking through loopholes that should not exist. The OP asked for "bugs or undesired behaviour" caused by optimizations and the fact is there are many many pitfalls.Enclose
Then the C language standard is amended by compiler developers That's only true if you mean the de-facto undocumented assumptions that developers were assuming when compiling for 2's complement C implementations. Even ISO C89 says that signed overflow is UB; that hasn't changed. What changed is how aggressively compilers take advantage of the assumption that the program contains no UB. This is a real issue that exposes lurking bugs in some code, and makes modern C not close to a "portable assembler" that it would sometimes be nice to have.Jaimeejaimes
You could say that older compilers kind of defined lots of behaviour that ISO C left undefined, and implementations have stopped doing that in more cases. But those were never truly standard behaviours. You do have a point, but please phrase it more accurately.Jaimeejaimes
Every single example in here is broken (assuming the overflow in them is signed overflow). Signed overflow has always been defined by the standard to be undefined behaviour. The compiler has the right to assume that undefined behavior cannot occur (as the standard gives no obligations on what must occur then), so here it is always the code that is broken, not the compiler optimizations.Mohler
@GabrielRavier you're just repeating what everyone who sides on the compiler language standards side of the debate says. "The standard doesn't say the compiler can't eat your dog, so don't complain if it eats your dog". The fact is that in most cases eating my dog is unreasonable, and furthermore, things like overflow are extraordinarily difficult to handle "correctly" without tons of boilerplate code everywhere, whilst being trivially easy to handle if your compiler just lets the cpu handle the overflow the way you're taught 2s complement math works. Languages should not be filled with traps.Enclose
The argument is about whether "optimizations can introduce bugs". I argue that it does not introduce bugs, unless you are not writing C. If your program does not work after optimization, then either there is a bug in the optimizer or there is a bug in your program. If the optimizer conforms to the transformations that the C standard allows, then the bug is in your code. If you argue that the transformations are stupid and should not be done, I'd say that you are not writing C, you are writing "C except the compiler is not allowed to do these transformations", which is not C.Mohler
@GabrielRavier You're arguing that the compiler eating your dog is valid C, because it's not not valid C. That's logically true, but also undesirable behaviour/buggy. It's also pretty clear from the industry usage that most people cannot reliably keep straight all the forbidden things that compilers are aggressively pouncing on. But seriously, look at the overflow case: overflow is SO EASY to handle the wrong way, and SO ANNOYING to handle the right way. Do you test all your integers for possible overflows before adding/subtracting them? Do you even know anyone who does?Enclose
@Mr.ShinyandNew安宇 "You're arguing that the compiler eating your dog is valid C, because it's not not valid C.". I don't really get what you're trying to say here. "the compiler eating your dog" is not valid C as far as I know (except if you prepend it with a bunch of preprocessor defines for every single word of that sentence, but that's besides the point). Also, I'm confused about what "it" designates in that sentence, if it designates "the compiler eating your dog", the sentence is weirdly self-contradictory, otherwise, I don't get what you're talking about and would like some clarification.Mohler
Your argument that the compiler can introduce any behavior it wants when the program does something undefined means the compiler can eat your dog if your program overflows an integer. My position is that it should not do that, and in fact it should respect the de facto standards and conventions of programming, like supporting overflow on 2s complement hardware. That and other "optimizations" that assume more than the programmer intends are constant headaches for all but expert programmers. Just read the presentation from cert in my answer... People are getting this stuff wrong.Enclose
M
35

When a bug goes away by disabling optimizations, most of the time it's still your fault

I am responsible for a commercial app, written mostly in C++ - started with VC5, ported to VC6 early, now successfully ported to VC2008. It grew to over 1 Million lines in the last 10 years.

In that time I could confirm a single code generation bug thast occured when agressive optimizations where enabled.

So why am I complaining? Because in the same time, there were dozens of bugs that made me doubt the compiler - but it turned out to be my insufficient understanding of the C++ standard. The standard makes room for optimizations the compiler may or may not make use of.

Over the years on different forums, I've seen many posts blaming the compiler, ultimately turning out to be bugs in the original code. No doubt many of them obscure bugs that need a detailed understanding of concepts used in the standard, but source code bugs nonetheless.

Why I reply so late: stop blaming the compiler before you have confirmed it's actually the compiler's fault.

Mellins answered 28/4, 2010 at 6:19 Comment(0)
M
16

Compiler (and runtime) optimization can certainly introduce undesired behaviour - but it at least should only happen if you're relying on unspecified behaviour (or indeed making incorrect assumptions about well-specified behaviour).

Now beyond that, of course compilers can have bugs in them. Some of those may be around optimisations, and the implications could be very subtle - indeed they're likely to be, as obvious bugs are more likely to be fixed.

Assuming you include JITs as compilers, I've seen bugs in released versions of both the .NET JIT and the Hotspot JVM (I don't have details at the moment, unfortunately) which were reproducible in particularly odd situations. Whether they were due to particular optimisations or not, I don't know.

Mystery answered 27/4, 2010 at 15:8 Comment(2)
I pointed out a well-known issue in a post below where C++'s optimizer will introduce a bug using the double-checked locking pattern. This is correct behavior as far as the current C++ spec is concerned, it is not a compiler bug, it is well-specified behavior that works perfectly fine with optimizations turned off, but breaks when it is turned on.Uproot
@Jon Skeet: I never downvote (well, hardly ever), but at 172k you even notice? :-)Impedimenta
B
11

To combine the other posts:

  1. Compilers do occasionally have bugs in their code, like most software. The "smart people" argument is completely irrelevant to this, as NASA satellites and other apps built by smart people also have bugs. The coding that does optimization is different coding from that which doesn't, so if the bug happens to be in the optimizer then indeed your optimized code may contain errors while your non-optimized code will not.

  2. As Mr. Shiny and New pointed out, it's possible for code that is naive with regard to concurrency and/or timing issues to run satisfactorily without optimization yet fail with optimization as this may change the timing of execution. You could blame such a problem on the source code, but if it will only manifest when optimized, some people might blame optimization.

Barbecue answered 27/4, 2010 at 15:12 Comment(0)
W
8

Just one example: a few days ago, someone discovered that gcc 4.5 with the option -foptimize-sibling-calls (which is implied by -O2) produces an Emacs executable that segfaults on startup.

This has apparently been fixed since.

Whitford answered 27/4, 2010 at 15:7 Comment(1)
Apparently this was a bug in the compiler. Of course compilers can (do!) have bugs: they're pieces of software. I'm more interested in examples of bugs (undesired/unexpected behavior) in the optimized code that are not caused by compiler bugs.Eskew
S
8

I've never heard of or used a compiler whose directives could not alter the behaviour of a program. Generally this is a good thing, but it does require you to read the manual.

AND I had a recent situation where a compiler directive 'removed' a bug. Of course, the bug is really still there but I have a temporary workaround until I fix the program properly.

Sculley answered 27/4, 2010 at 15:9 Comment(3)
++ Especially in Fortran. We're always running into situations where the Fortran works fine, but only if you use a particular opt level. And running Fortran under an IDE? where the optimizer (even if you didn't ask for it) has felt at liberty to totally scramble the code and shuffle the variables? all in the name of "Optimization"? Gimme a brreak!Impedimenta
@Mike -- I share your pain, my recent situation is a Fortran program I'm porting from one cluster to another 'identical' one. IDE ? surely you mean Emacs :-)Sculley
Sorry I'm stuck in the Windows world. Fortran is a hot potato - MS, DEC, Compaq, now Intel. Did I miss any foster parents? It works under .net, but only if your boss keeps paying for upgrades. Plus GCC, where we have lovely GDB. I was once told, like it or not "Fortran is like Rock 'n Roll, it will Never Die!"Impedimenta
U
7

Yes. A good example is the double-checked locking pattern. In C++ there is no way to safely implement double-checked locking because the compiler can re-order instructions in ways that make sense in a single-threaded system but not in a multi-threaded one. A full discussion can be found at http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Uproot answered 27/4, 2010 at 15:11 Comment(3)
As you seem to indicate, that is a shortcoming of C++ not a problem with optimizing compilers. It's a problem that exists even without optimization.Firstfoot
Not at all. With no optimization double-checked locking is fine. It's a painful type of bug to find because it will work fine in a debug build. It's only because the optimizer is allowed to make logical changes that are equivalent in a single-threaded system that there is a problem. You could claim that it is an issue with what is allowed in C++ by the optimizer, but it is still an area where compiling with optimization turned on can cause issues.Uproot
This is why C11 / C++11 introduced a thread-aware memory model, and std::atomic. Pre-C++11 lockless atomics and roll-your-own locking were always highly dependent on a lot of assumptions about how compilers worked (and often needed inline-asm) and abuse of volatile.Jaimeejaimes
S
6

Is it likely? Not in a major product, but it's certainly possible. Compiler optimizations are generated code; no matter where code comes from (you write it or something generates it), it can contain errors.

Signesignet answered 27/4, 2010 at 15:6 Comment(0)
S
6

I encountered this a few times with a newer compiler building old code. The old code would work but relied on undefined behavior in some cases, like improperly defined / cast operator overload. It would work in VS2003 or VS2005 debug build, but in release it would crash.

Opening up the assembly generated it was clear that the compiler had just removed 80% of the functionality of the function in question. Rewriting the code to not use undefined behavior cleared it up.

More obvious example: VS2008 vs GCC

Declared:

Function foo( const type & tp ); 

Called:

foo( foo2() );

where foo2() returns an object of class type;

Tends to crash in GCC because the object isn't allocated on the stack in this case, but VS does some optimization to get around this and it will probably work.

Sanguinary answered 27/4, 2010 at 15:13 Comment(0)
S
5

Aliasing can cause problems with certain optimizations, which is why compilers have an option to disable those optimizations. From Wikipedia:

To enable such optimizations in a predictable manner, the ISO standard for the C programming language (including its newer C99 edition) specifies that it is illegal (with some exceptions) for pointers of different types to reference the same memory location. This rule, known as "strict aliasing", allows impressive increases in performance[citation needed], but has been known to break some otherwise valid code. Several software projects intentionally violate this portion of the C99 standard. For example, Python 2.x did so to implement reference counting,[1] and required changes to the basic object structs in Python 3 to enable this optimisation. The Linux kernel does this because strict aliasing causes problems with optimization of inlined code.[2] In such cases, when compiled with gcc, the option -fno-strict-aliasing is invoked to prevent unwanted or invalid optimizations that could produce incorrect code.

Silverstein answered 27/4, 2010 at 17:14 Comment(0)
S
4

Yes, compiler optimizations can be dangerous. Usually hard real-time software projects forbids optimizations for this very reason. Anyway, do you know of any software with no bugs?

Aggressive optimizations may cache or even do strange assumptions with your variables. The problem is not only with the stability of your code, but also they can fool your debugger. I have seen several times a debugger failing to represent the memory contents because some optimizations retained a variable value within the registers of the micro

The very same thing can happen to your code. The optimization puts a variable into a register and do not write to the variable until it has finished. Now imagine how different things can be if your code has pointers to variables in your stack and it has several threads

Spondee answered 27/4, 2010 at 15:14 Comment(6)
I have written a few bug-free programs in the past. "Hello world" and such. :PEskew
I write safety-critical hard real-time software, and I always build with max optimization. If there is a compiler bug I want to find it early, not wait until we're out of CPU time AND calendar time and have someone say "-O3" can help, and then ship buggy code because we didn't get enough testing. If you don't trust your tools, don't use them.Firstfoot
@Martinho Fernandes: Yeap, there's even a saying: Is it possible to write a completely bug-free program? Yes, but it will be useless.Irradiation
@Firstfoot I have seen DO-178b certified projects, some of those DAL-A level where the design board forbids any type of compiler optimization. Even threads are usually forbidden. I have made some research on compilers and met many people who agrees that C++ and Java languages have very serious flaws in their design (hence you dont seem them in DAL-A software), although people try to live with it or ignore them. I have very few tools I trust and most of the stress of my work is because I am forced to use buggy libraries and/or toolsSpondee
@Francisco - We use C in automotive stuff, not C++ or Java. Mass produced products are not subject to DO-178b whatever that is. We are subject to lawyers which is probably worse. Agreed that threads are bad. Certified compilers are not generally available for our targets, and I have seen GCC used to build code for airbag controllers with much success. I've seen compiler bugs, processor bugs, and hardware design issues. Building code at O3 is the least of my worries.Firstfoot
@phkahler: It's like you say, you have to trust your tools or find others to replace them. I happen to know that compilers and optimkizers are written by some very smart people (not me though :()and with front-, middle- and back-ends maintained by separate teams code and optimizer quality should increase. As to the question of optimizer rules: it's easier to write optimizers according to generalized rules and produce what some might call bugs (volatile example) than trying to specify every single exception to the rules and risk bloated code that is difficult to maintain. +1Mazdaism
A
3

It's theoretically possible, sure. But if you don't trust the tools to do what they are supposed to do, why use them? But right away, anyone arguing from the position of

"compilers are built by smart people and do smart things" and thus, can never go wrong.

is making a foolish argument.

So, until you have reason to believe that a compiler is doing so, why posture about it?

Ahrens answered 27/4, 2010 at 15:3 Comment(3)
It's more like an intuition. I trust the tool, but I'm sure compiler optimization can sometimes do things you wouldn't except. I just can't give an example. Maybe i'm wrong, and there is no such examples.Jamal
Well there are examples (provided above and in comments), but it seems like a silly argument (especially your friends "supporting argument") until it becomes a real issue. But you are indeed correct, it is absolutely possible.Ahrens
An ability to examine compiler output when code isn't behaving as expected is often useful. In some cases, such examination leads to the discovery of a weird corner case in the C spec which means code isn't actually guaranteed to work as expected. In other cases, it leads to the discovery of genuine compiler bugs [e.g. using a special-purpose CPU register to hold a variable, but then using it for its dedicated purpose without saving it first].Papillon
L
3

It can happen. It has even affected Linux.

Livery answered 27/4, 2010 at 15:13 Comment(0)
F
3

I certainly agree that it's silly to say the because compilers are written by "smart people" that they are therefore infallible. Smart people designed the Hindenberg and the Tacoma Narrows Bridge, too. Even if it's true that compiler-writers are among the smartest programmers out there, it's also true that compilers are among the most complex programs out there. Of course they have bugs.

On the other hand, experience tells us that the reliability of commercial compilers is very high. I've had many many times that someone told me that the reason why is program doesn't work MUST be because of a bug in the compiler because he has checked it very carefully and he is sure that it is 100% correct ... and then we find that in fact the program has an error and not the compiler. I'm trying to think of times that I've personally run across something that I was truly sure was an error in the compiler, and I can only recall one example.

So in general: Trust your compiler. But are they ever wrong? Sure.

Fare answered 27/4, 2010 at 17:2 Comment(0)
S
2

As I recall, early Delphi 1 had a bug where the results of Min and Max were reversed. There was also an obscure bug with some floating point values only when the floating point value was used within a dll. Admittedly, it has been more than a decade, so my memory may be a bit fuzzy.

Snooperscope answered 27/4, 2010 at 21:4 Comment(0)
C
2

I have had a problem in .NET 3.5 if you build with optimization, add another variable to a method which is named similarly to an existing variable of the same type in the same scope then one of the two (new or old variable) will not be valid at runtime and all references to the invalid variable are replaced with references to the other.

So, for example, if I have abcd of MyCustomClass type and I have abdc of MyCustomClass type and I set abcd.a=5 and abdc.a=7 then both variables will have property a=7. To fix the issue both variables should be removed, the program compiled (hopefully without errors) then they should be re-added.

I think I have run into this problem a few times with .NET 4.0 and C# when doing Silverlight applications also. At my last job we ran into the problem quite often in C++. It might have been because the compilations took 15 minutes so we would only build the libraries we needed, but sometimes the optimized code was exactly the same as the previous build even though new code had been added and no build errors had been reported.

Yes, code optimizers are built by smart people. They are also very complicated so having bugs is common. I suggest fully testing any optimized release of a large product. Usually limited use products are not worth a full release, but they should still be generally tested to make sure they perform their common tasks correctly.

Congenial answered 30/4, 2012 at 17:40 Comment(0)
A
2

Compiler optimization can reveal (or activate) dormant (or hidden) bugs in your code. There may be a bug in your C++ code that you don't know of, that you just don't see it. In that case, it is a hidden or dormant bug, because that branch of the code is not executed [enough number of times].

The likelihood of a bug in your code is much bigger (thousands of times more) than a bug in the compiler's code: Because the compilers are tested extensively. By TDD plus practically by all people who have use them since their release!). So it is virtually unlikely that a bug is discovered by you and not discovered by literally hundreds of thousands of times it is used by other people.

A dormant bug or hidden bug is just a bug that is not revealed itself to the programmer yet. People who can claim that their C++ code does not have (hidden) bugs are very rare. It requires C++ knowledge (very few can claim for that) and extensive testing of the code. It is not just about the programmer, but about the code itself (the style of development). Being bug-prone is in the character of the code (how rigorously it is tested) or/and the programmer (how disciplined is in test and how well knows C++ and programming).

Security+Concurrency bugs: This is even worse if we include concurrency and security as bugs. But after all, these 'are' bugs. Writing a code that is in the first place bug-free in terms of concurrency and security is almost impossible. That's why there is always already a bug in the code, which can be revealed (or forgotten) in compiler optimization.

Ader answered 3/6, 2016 at 12:0 Comment(0)
K
1

More, and more aggressive optimizations could be enabled if the program you compile has a good testing suite. Then it is possible to run that suite and be somewhat more sure the program operates correctly. Also, you can prepare your own tests that match closely that do you plan to do in production.

It is also true that any large program may have (and probably indeed has) some bugs independently on which switches do you use to compile it.

Kitchenmaid answered 8/7, 2013 at 6:52 Comment(0)
C
1

I work on a large engineering application, and every now and then we see release only crashes and other problems reported by clients. Our code has 37 files (out of around 6000) where we have this at the top of the file, to turn off optimization to fix such crashes:

#pragma optimize( "", off)

(We use Microsoft Visual C++ native, 2015, but it is true for just about any compiler, except maybe Intel Fortran 2016 update 2 where we have not yet turned of any optimizations.)

If you search through the Microsoft Visual Studio feedback site you can find some optimization bugs there as well. We occasionally log some of ours (if you can reproduce it easily enough with a small section of code and you are willing to take the time) and they do get fixed, but sadly others get introduced again. smiles

Compilers are programs written by people, and any big program has bugs, trust me on that. The compiler optimization options most certainly has bugs and turning on optimization can certainly introduce bugs in your program.

Counteroffensive answered 13/11, 2018 at 15:57 Comment(0)
F
0

Everything that you can possibly imagine doing with or to a program will introduce bugs.

Fare answered 27/4, 2010 at 17:14 Comment(2)
Personally I do not think ereOn wanted a joke answer. Still, maybe you could change "will" to "can" so your answer is at least partially correct/reasonable?Congenial
@Congenial My answer was whimsical, but I think accurate. Do compiler optimizations sometimes introduce bugs? Yes. To say no, that's absolutely impossible would mean that compiler writers are infallible programming gods, which is of course false. Do compiler optimizations OFTEN introduce bugs? No. They're usually well tested. But of course we'd have to say which compiler.Fare
C
0

Because of exhaustive testing and the relative simplicity of actual C++ code (C++ has under 100 keywords / operators) compiler bugs are relatively rare. Bad programming style often is the only thing encounters them. And usually the compiler will crash or produce an internal compiler error instead. The only exception to this rule is GCC. GCC, especially older versions, had a lot of experimental optimizations enabled in O3 and sometimes even the other O levels. GCC also targets so many backends that this leaves more room for bugs in their intermediate representation.

Copyhold answered 30/4, 2012 at 17:26 Comment(0)
F
-2

I had a problem with .net 4 yesterday with something that looks like...

double x=0.4;
if(x<0.5) { below5(); } else { above5(); }

And it would call above5(); But if I actually use x somewhere, it would call below5();

double x=0.4;
if(x<0.5) { below5(); } else { System.Console.Write(x); above5(); }

Not the exact same code but similar.

Flashgun answered 30/4, 2016 at 3:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.