6

I'm reading some internal documentation for code developed to the MISRA C guidelines, and I see that in compiler flags section of the documentation there is a note to compile with optimisation off (-O0). I'm new to safety-critical development, so in my mind turning off optimisation is overly-pessimistic and modern compilers will produce valid code with moderate optimisation, and anyway a decent test suite will catch compiler flaws.

Are there good arguments for disabling optimisation? Perhaps because of this disabling, the code is riddled with left- and right-shifts replacing divisions and other micro-optimisations that I believe we should leave to the compiler to deal with.

  • 2
    What is your application? My answer mostly relates to commercial aerospace, which often uses MISRA as a coding standard. – Jace Browning Dec 24 '14 at 8:11
  • I'm new to safety-critical development, so in my mind turning off optimisation is overly-pessimistic and modern compilers will produce valid code with moderate optimisation, and anyway a decent test suite will catch compiler flaws. Testing can't prove the absence of bugs, and safety can't be left to chance. Unless there's proof the optimizations are actually correct, it makes sense to avoid them. – Doval Dec 24 '14 at 12:38
  • 1
    One question you should be asking is whether or not the object code actually needs to be optimized. If it runs acceptably with the optimization turned off, then there's no reason to turn it on. Lots of compilers have thorough test suites, and we still find bugs in them. – Blrfl Dec 24 '14 at 13:45
  • The product is vehicle camera-related, and the code does need to be optimised, as it is one of the objectives we have. – Ken Y-N Dec 25 '14 at 0:09
  • @KenY-N can you clarify what you mean by "the code does need to be optimised"? – Jace Browning Dec 25 '14 at 16:16
12

I agree with you that it's overly pessimistic, but some (potentially historical) reasons:

  • DO-178C Level A code requires Source Code to Object Code Traceability, which is much harder to prove manually with optimized code (and qualified compilers are very expensive)
  • optimised code is harder to debug, which might prohibit scripted debugging opportunities
  • there could be more compiler bugs during optimization
  • 6
    Regarding third point: in the last couple of years alone I already filed a couple of optimization bugs to compiler vendors, and that's just me. Searching for 'gcc optimization bug' etc also reveals the problem is most definitely real. – stijn Dec 24 '14 at 8:18
  • 3
    Also, consider the real cost of not optimising the code is a bit extra on the hardware budget. It's just not worth the additional risk to save a few bucks on hardware. – James Snell Dec 24 '14 at 10:10
3

It's not just compiler bugs you have to worry about. Some "perfectly valid" (ie. conforming to the letter of the language spec) compiler optimizations produce quite unexpected behavior. See Finding Undefined Behavior Bugs by Finding Dead Code.

The point is that these problems are real, and they’re nasty because the problem can only be seen by looking at the compiler’s output. Compilers are getting smarter all the time, causing code that previously worked to break. A sufficiently advanced compiler is indistinguishable from an adversary.

  • 3
    Arguably the problem there is that the code has undefined behavior. Although the optimizations can produce surprising results in those cases, such code is unacceptable for safety-critical applications even if they're turned off. – Doval Dec 24 '14 at 13:50
  • But sometimes the "optimization" makes the effect of your undefined behavior much worse. And other times you know exactly what the behavior should be, only the compiler is taking advantage of the spec saying it should be "undefined" to do bad things. (because any behavior doesn't contradict a part of the spec that says "undefined"). Eg. assuming arithmetic doesn't wrap even on architectures where it does (and the programmer knows it does and relies on it): kb.cert.org/vuls/id/162289 – Hugh Allen Dec 24 '14 at 14:04
  • 3
    Eg. assuming arithmetic doesn't wrap even on architectures where it does (and the programmer knows it does and relies on it). It doesn't matter that the hardware supports signed arithmetic overflow. You're writing C, not assembly, so the only behavior that counts is what the C standard says. Even if the compiler guarantees that a particular undefined behavior will be handled a certain way, you're going to have trouble if you ever switch compilers. More importantly you're going to get warnings from static analysis tools (which you should be using) and you're going to start ignoring them. – Doval Dec 24 '14 at 14:40
  • 2
    An interesting, yet moot answer. Simply don't rely on UB. End of story. Still scared of UB? Simply don't use a language with UB. End of story. – Thomas Eding Dec 24 '14 at 17:37
  • 1
    The GCC developers still do not understand that there's a massive difference between "technically allowed according to a literal reading of the C specs" and "sane in practice". The issue with GCC and signed integer overflow is that the C specs are bad (signed integer overflow should've been implementation defined from the beginning, and most implementations should've done wrapping to mirror the behaviour for unsigned integers and/or the target machine). "Undefined (by the spec) behaviour" does not exclude "defined by the implementation as wrapping". – Brendan Dec 25 '14 at 8:17
2

If the optimiser for your chipset/platform is not known to be reliable, then you need to ask yourself what would be the side effect of incorrect code being deployed to your embedded device:

  • A Set Top Box may crash and need the user to restart.

  • A hospital life-support system, might cause loss of life.

While comprehensive system tests will help to catch known scenarios, it's the unknown scenarios that will likely catch you out.

Given this, it seems like there may be some premature optimisation going on in the code base - have you performance-profiled the code to determine that code with all the shift operators is the primary cause of performance problems? Are you using the best algorithm for the job?

  • The compiler we seem to be using (I haven't got a copy yet!) is an EOLed tool, so I suppose its optimisation won't be up to the gcc or clang, etc, level. I mentioned the shifts just because they stand out in the code, and expressions like lUL << 5UL (yes, that is real code!) make me double-take. – Ken Y-N Dec 25 '14 at 0:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.