Gunnar Kudrjavets

Paranoia is a virtue

Having all the assertions turned on in production code? (Part II)

First of all, back to basics. Here's the list of most useful top three books I've ever read about assertions (not mentioning the CRT source code ;-)). I intentionally don't include any books about design by contract (DBC), formal methods, and formal verification.

  1. "Debugging Applications for Microsoft® .NET and Microsoft Windows®" by John Robbins. Open the book on page 85 ("Assert, Assert, Assert, and Assert").
  2. "Writing Solid Code" by Steve Maguire. Open the book on page 13 ("Assert Yourself").
  3. "No Bugs!: Delivering Error-Free Code in C and C++" by David Thielen. Open the book on page 39 ("Assert the World"). This book is pretty interesting in this sense that I picked it up for ca $4 from the used bookstore in Bellevue. It was published in 1992 (I was in 10th grade then ;-)) and offers personally for me kind of cool view how the software development at Microsoft was happening then.

Design issues
Let's see how the development will look like when all the assertions would be enabled in release builds and what problems it'll cause and what questions we would need to answer. One of the first questions I would have is: what should happen when assertion fires? Should we:

  • Show the user detailed cryptic error message á la "NULL != p->Foo->Bar" and present the user with the classical "Abort, Retry, Ignore" choice? I bet this will confuse everyone and make them either complain about software or call support. Also what about non-interactive software like services for example?
  • Don't show user anything technical and use logic similar to Dr. Watson, have a nice dialog explaining to user that some problems happened internally, and can we send the information related to this incident to Microsoft?
  • Log all the instances when assertions fail to NT Event Log (or whenever user specifies?) and provide some actionable information if applicable (what it'll be?).
  • Just terminate the process because internal assumptions are violated and we can't guarantee that software produces correct results?
  • ...

I totally understand the point Niels Ferguson and Bruce Schneier are trying to make - "if internal assumptions are violated in (cryptographic) code then it's no longer safe to continue and it'll be safer just to terminate the current process/operation." For example: let's assume that we have a client and server both written by some financial institution. Server programmer writes an assertion that encryption stream cipher can't be RC2, but doesn't implement specific check in the code because his buddy next door is implementing the client piece of software which never would use RC2." Using the current model where assertions are only enabled in debug builds and somebody will implement a fake client and there's nothing in server code preventing the usage of RC2 we may have introduced a security hole. You can replace “this RC2 thing” with any other assumption you're making, but not writing specific error handler for.

Performance price
Nothing is free. Especially in the server world. The very simplistic model for an assertion is following:

if (SomeLogicalConditionIsViolated)
{
    DisplayMessageToUser();
    AskForDecisionFromUser();
    PerformSomeAction();
}

The typical usages of assertions are for example internal method which validates all its arguments. We're pretty sure that caller honors the contact, but at the same time we're paranoid and we want to make sure that at least in debug builds the violation of the contract is caught immediately.

private bool SomeInternalMethod(String s, Int32 i)
{
    Debug.Assert(null != s, "null != s");
    Debug.Assert(0 < s.Length, "0 < s.Length");
    Debug.Assert(0 < i, "0 < i");

    ...

    return true;
}

Now let's assume for a moment that this is a code in the XML parser and the function is called for every node in parsing tree. Are we still willing to have all this error checking in place and pay the price for these function calls? It gets even better, I've written enough code in my life which performs complex calculations or pointer manipulation and I usually want to make sure that after iteration of the cycle the invariant is correct.

for (Int32 i = 0; i < nNodeCount; ++i)
{
    ...

    Debug.Assert(true == VerifyTreeStructure());
}

Am I still allowed to pay this performance price?

Psychological issues
I don't pretend to be expert in programming or in designing secure software, but I already see a couple of things I don't like:

  • If we would establish an absolute rule that every assertion must be enabled in production code then for every pre-condition, invariant or post-condition the programmer will write he/she will have this set of questions: "Can I afford this performance-wise?", "If this assertion is violated should my application really terminate?" I bet that there'll be number of instances when people just won't use assertions so liberally anymore.
  • Probably after doing it some time we'll be back again on square one after somebody will propose that we should have "release assertions" and "debug assertions" which won't be much different from the situation currently where every decent developer is handling all the cases which may go wrong and writing assertions for validating the contracts. Then somebody eventually will raise the Orwellian question- should all assertions be handled equivalently? Are there some assertions which we should mark as "more important" than others?

These are my thoughts on subject and I'll be very interested to hear somebody else's opinion(s).

P. S. Criticizing kind of feels good; you can just bash everything and not offer any solutions. I think I'll soon start writing unskilled book reviews ;-)

Posted: Apr 28 2004, 10:47 PM by gunnarku | with 11 comment(s)
Filed under:

Comments

thomas woelfer said:

Gunnar,

i think that assertions are part of the development toolset. just like a debugger.

that is, they are there to help detect errors in the program, not to detect errors in user input.

there is a difference between assuming something and knowing something. it is a good thing to assume stuff while debugging/developing and to assure these assumptions are true.

however, in release code, you better _know_ that everything is ok. if conditions are possible that break your code in release, than these conditions must be tested agains with ordinary code and handled with ordinary means (i.e.: exceptions, return codes.).

iow: an assertion that is vital to be inplace in release code is a bad assertion and should be part of the normal program flow. a good assertions is one that helps the programmer to find bugs, but is not needed in release.

WM_MY0.02$
thomas woelfer
# April 29, 2004 5:55 AM

Wes said:

Funny you should be talking about this topic. I'm currently a MS Student and working on solution to help with this problem. Here is a set of assumptions that I'm working with:

1) No recompilation of the client to add/remove checks
2) No recompilation of the component to add/remove checks
3) Have ability to turn on/off checks per class level.

The current approach that we are thinking of is simply creating a wrapper class that has all the checks (pre/post/invariant conditions) and use a factory method to determine at runtime whether or not to use the wrapper class with checks or not.

I have been looking at all kinds of potential solutions (like wrappers, aspects, etc) but no clear cut winner has emerged yet.

In fact I would really like to get some feedback from the .Net community on this because currently I’m the only one in my research group that is working on .Net, everyone else is working on Java.

Wes
# April 29, 2004 10:18 AM

Gunnar Kudrjavets [MSFT] said:

Wes,

IF you'll blog about what you're doing THEN I'll definitely subscribe ;-) And I'm sure that plenty of other people also.
# April 29, 2004 11:21 AM

B.Y. said:

"Writing Solid Code" is not mentioned often enough. "Debugging the Development Process" is very good too.

# April 29, 2004 12:35 PM

Wes said:

Gunnar,

I plan on blogging about this to get ideas and to improve my research. However right now the semester is coming to an end and I have projects due and finals coming up so not much time for blogging (I'm sure you know how that goes).

Most of my research is going to happen next year (year 2 of my MS) so I will blog about it to get feedback. I will do some work on this over the summer but I’m also going to be interning at Microsoft, so I don’t know how much time I will have to work on it.

If you are in Redmond, maybe I can meet up with you sometime over the summer so I can get your views.

Thanks,
Wes
# April 29, 2004 2:20 PM

Chris S said:

# May 3, 2004 2:03 PM

Gunnar Kudrjavets [MSFT] said:

Thanks for the link! MustUseWikiBeforeWritingBlogEntry.
# May 3, 2004 2:06 PM

TrackBack said:

Staffan Malmgren's Blog
# May 17, 2004 7:38 PM

Balaji said:

Gunnar
In your example for checking the invariant

Debug.Assert(true == VerifyTreeStructure());

why use assert when for example, a tree structure can become invalid because of some factors even in release build and if we dont check it with a piece of code somewhere, there we may run into unexpected results / runtime errors. So that is the context for my question

1. How do we know when to use asserts or when to write normal if condition based checks so that the checks actually exists in release mode too.

2. Should be even consider using asserts for precondition, postcondition checks as these checks should be done even in release mode and hence has to be in release build too. I think we will be better off with conditional checking/throwing exceptions than using asserts. Or in Debug mode use asserts, release mode use conditional checking and throw exceptions?

3. We should not be carried away by using asserts everywhere and assuming that the code will run safe in release mode because so many factors influence the realtime release run of a piece of code.

Any thoughts?..

Thanks




# May 21, 2004 3:50 PM

Gunnar Kudrjavets [MSFT] said:

Balaji,

Lots of opinion, but the answer will require longer post and I’m currently getting my bags ready for the vacation (leaving tomorrow early morning). I’ll be back on June 1st and then I’ll publish my thoughts.
# May 21, 2004 5:41 PM

TrackBack said:

# July 12, 2004 8:22 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)