Asserting failure -

Asserting failure


Debugging is hard. We need to seed our code with constructs that find bugs automatically.

C compilers offer a very power debugging construct in the assert() macro. Yet it's quite rare to find the use of assertions in firmware.

First, a refresher: if assert's argument is TRUE, nothing happens. If FALSE, the macro's default behavior is to print out an error message which includes the source filename and line number. That's not particularly useful for many embedded systems, but it's trivial to recode assert to take some other action, like to log the error and stop, or flash an LED.

The macro is disabled when DEBUG is set FALSE, so in production assert() uses no resources.

Why use this construct? Assert causes the system to fail immediately when a fault is detected. Contrast that with the normal behavior of a C function: something goes wrong (e.g., a divide by zero, a pointer out of range) and the function returns, pushing garbage data up the call change. Function after function manipulates the results, turning one person's garbage into the mother of all landfills, until the system decides it's time to push a swimming pool of morphine into the patient's arm.

Failing immediately makes it much easier to track the cause of problems. The cause is generally right at hand, not the result of something that happened millions of cycles ago.

In “Assessing the Relationship between Software Assertions and Code Quality: An Empirical Investigation,” the authors showed a stunning correlation between assertion density and quality code. “Investigating the Use of Analysis Contracts to Support Fault Isolation in Object Oriented Code” goes even further: it demonstrates that bugs caught by assertions are often orders of magnitude cheaper to find and fix than those detected by conventional debugging.

Better code. Produced cheaper. All for no out-of-pocket costs.

Assert does burn some CPU cycles and memory, and so may not be appropriate in resource-constrained embedded systems, but with the proliferation of 32 bit MCUs most of these concerns go away. Consider this snippet:

assert sqrt(b*b – 4*a*c)>=0;
result= (-b + sqrt(b*b – 4*a*c))/(2*a);

That sure looks computationally expensive, but GCC evaluates the duplicated discriminant only once.

Some companies keep assertions active no matter how DEBUG is set, but define assert() to take different actions: immediate shutdown when DEBUG is TRUE, or send an email (or something similar) to the developers when the switch is FALSE.

The macro has a serious flaw, though. It will take any argument, even one with an assignment or a function call. The code will likely behave differently with different settings of DEBUG. One solution is to redefine assert as follows:

#define assert_e(a) ((void)(a), assert(a))
//lint -emacro(730, assert_e)

The second line is a lint directive for PC-lint . Use assert_e() instead of assert(), and PC-lint will toss out errors whenever the assertion argument has a side effect.

Here's a case from just a few weeks ago where a sanity check, or an assertion, would have prevented this “we sure are some dumb programmers” message from appearing:

Click on image to enlarge.

Or how about Sunday's weather:

Click on image to enlarge.

What do you think? Do you routinely use assertions?

Jack G. Ganssle is a lecturer and consultant on embedded developmentissues. He conducts seminars on embedded systems and helps companieswith their embedded challenges, and works as an expert witness onembedded issues. Contact him at . His website is

14 thoughts on “Asserting failure

  1. OK, I'll bite….

    Many/most modern CPUs and compilers provide various traps that will catch those out of bounds pointers and divide by zeros and trigger various exceptions. These can be trapped and a backtrace (or whatever) generated. This does not need a

    Log in to Reply
  2. It seems to me that this last comment represents a very common and deeply flawed misconception about programming in general.

    In programming digital computers we (programmers) either are in control of the machine or we aren't. There is no really middle gro

    Log in to Reply
  3. Standard C uses the macro NDEBUG, not DEBUG, to disable assert(). NDEBUG does not need to evaluate to TRUE or FALSE, it simply needs to be defined or undefined.

    Log in to Reply
  4. I few years ago I became an assert() convert. I’m not sure how I went all those years without it.

    Most testing code gets postponed until ‘the end’ of the project which is too late to be useful. But asserts are so easy I put them everywhere during the de

    Log in to Reply
  5. Now what happens if that temperature of 222 degrees comes from a remote sensor that way? The page will just end up in a redraw loop which might bring down the server. Asserts should never be used as guards on data entering the system or on what is going to

    Log in to Reply
  6. I disagree entirely with your statement that we are either in control or we are not.

    We might program digital CPUs but we interact with an analogue world which makes the whole system analogue.

    For example, a mechanical element can be sticking, or we mig

    Log in to Reply
  7. It seems to me that these two comments again show another deeply flawed misconception about assertions, which is constantly confusing exceptional conditions with software bugs. I've actually written about this tendency in my article from 2003 “An Exception

    Log in to Reply
  8. Did nobody see the bug in the assert example?
    It should say:
    assert (b*b – 4*a*c) is nonnegative;
    The statement as originally written may call sqrt() with a negative number, which you are trying to avoid in the first place.

    In general, C functions should

    Log in to Reply
  9. I don't think you are disagreeing with me at all in your last post here.

    What I said:

    “asserts are more useful is in checking for algorithmic consistency” and “There are times when it should be used (discovering algorithmic errors during debug), but the

    Log in to Reply
  10. You say.

    “The macro is disabled when DEBUG is set FALSE, so in production assert() uses no resources.”

    If used this way, Asserts are useful only for development/unit testing but when the project passed on to the test team, all the Asserts must be disa

    Log in to Reply
  11. Disabling assertions in the production code may still be the beaten path approach, but it seems to me that one of the main purposes of Jack's article is to THINK about it for a minute.

    The often quoted opinion in this matters comes from C.A.R. Hoare, who

    Log in to Reply
  12. Yes, please do add asserts to your code.
    We added asserts to a VoIP product. All case statements with “This should never happen” comments had an assert.
    Use the __func__ macro if you have it available.
    Our code wrote the assert, and stack trace to a scra

    Log in to Reply
  13. “I use asserts mainly to make sure I have setup and walking my data structures correctly:nntypedef structn{nuint16_t type; // TYPE_FOO = 0xBEEFn//etcn} FOO_t;nnvoid bar( FOO_t *foo )n{nassert( foo ); // non-NULLnassert( foo (deref) type =

    Log in to Reply
  14. “I started using them recently they are quite useful. Sometimes you need to modify badly designed code, or code that exceeded its life time. When more than one programmer is working on the code, they may not know all the hidden assumptions. For example, si

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.