Exception Handling

by Neil Fraser, January 2005

Most programming languages allow one to catch execution errors and gracefully recover from them.  This is an extremely useful ability which if used properly can improve reliability and simplify programming.  Unfortunately this ability can also be abused, leading to less reliable software and more complicated maintenance.  This paper looks at both sides of the issue.

Examples of exception handling in various languages:


1. Problems with Exception Handling

"Do or do not; there is no try." -- Yoda

Exception handlers can be a dangerous tool.  They are capable of causing errors which are extremely difficult to debug.

Hides Unrelated Errors
The joke programming language INTERCAL has a statement called "COME FROM".  It is a parody of the infamous "GOTO" statement; except worse.  Add "COME FROM 20" to your program, and whenever your execution reaches line 20 it will jump to the "COME FROM" line, wherever that may be.  There is nothing on line 20 which indicates that program flow will be yanked away like this.

Just like COME FROM, exception handling can also produce unexpected and non-linear flow.  A program may be executing normally, then suddenly program flow jumps several levels up the call stack and resumes somewhere else.  An exception handler which was added to deal with a particular event (say, a divide by zero), sometimes ends up suppressing all similar events within a large area.  It can be very difficult to debug a program where the root cause of a bug is inadvertently being squelched by someone else's exception handler.

No Thought
Recently I was investigating why an e-commerce application frequently generated unpredictable results.  It turns out that the contractor who wrote it got in the habit of fixing bugs by simply wrapping the offending code in an error trap.  Sure enough, the program crashes went away.  But the underlying bugs were all still there.  Many of them were trivial enough that hiding the error worked fine (nobody cares if the tax calculation on a zero dollar transaction fails).  But many others were serious (large items were being dispatched to addresses on the wrong continent).  Eventually I ripped out all the error traps, exposed the previously hidden errors, then fixed the actual bugs.

Exception handling is often used as the lazy way out of a problem.  Not sure exactly why something is failing intermittently?  Don't bother investigating, just trap the error and keep going.  If it's important, someone else can fix it properly later.

Hanging Resources
Here is a fairly typical exception handler:
try {
    file_open(filename)
    file_write(filename, data)
    file_close(filename)
} catch (FILE_ERROR) {
    print("Sorry, can't save.")
}
Now look what happens if the file is read-only: file_open() executes fine, file_write() fails, execution jumps to the error message, then the program continues to run.  Everything is fine except that one file handle has been left open.  If this code is in a loop or is in a long-running application one starts to leak file handles.  Eventually the operating system runs out of file handles and random applications running on the same computer start to crash.

The problem with relying on exception handlers is that code is being stressed in ways that it may not have been designed for.  A function might normally be very careful to deallocate all the memory which it requested, but if execution jumps out half way through the function due to invalid inputs, one is left with a memory leak.  A function might increment a global reference counter then explode (and be caught) while creating the invalid item, thus leaving the data out of synch.  Unless a function has been designated as being "exception-safe", it is wiser to check the inputs before calling the function rather than wrap the function in an exception handler.

CPU Time
When would you prefer to know that the grocery store is closed: before you leave the house or when you pull into their empty parking lot?  Sometimes a program will call a function which does a lot of work and has a high probability of failing.  In these cases it would be more efficient to check your inputs for obvious signs of failure first.  There is no point in letting the poor computer thrash away on a problem which is doomed to failure.  If you think the grocery store is likely to be shut, phone ahead first.

2. Benefits of Exception Handling

"I'll try anything once." -- Darwin Award Winner

Exception handlers can be a valuable tool.  They are capable of increasing reliability and simplifying code.

Reliability
Your plane is flying normally until a large goose gets ingested by one of the engines.  The sensors in the engine produces data which the computer has never seen before.  This combination never happened during testing.  A freak divide by zero happens.  In a case like this one would hope that the entire program was enclosed in an exception handler (or similar mechanism) which catches any and every error.  Sure there may be memory leaks and data corruption, but that is probably better than an application crash.

Before shipping an important program, it is often wise to enable a global exception handler that suppresses any unknown errors and lets the application attempt to continue to running when something does go wrong.  Such a handler should log the error and alert the user that now would be a really good time to save any data and restart.  However, this global handler should not be active during project development or testing.  Otherwise it just serves to hide errors from the very people who are supposed to fix them.

Rare Events
When saving a file to disk, what could go wrong?  Invalid file name, directory not found, file read-only, directory read-only, quota overflow, no available file handles, disk full, disk I/O error, disk not in drive, bullet through the controller card, etc.  Checking each possible error condition in advance of every file operation would be ludicrous.

This is exactly what exception handling is designed for.  First check for the obvious things like an empty file name, then attempt to save the file and trap any errors.  Exception handling allows one to keep the code simple, yet still deal reasonably well with unexpected events.

Risky Calls
Your programming is perfect.  You never make mistakes.  But your co-workers are another matter.  Before calling Scary Simon's Spellchecker, you might want to wrap the call in an exception handler.  When Simon's code crashes (as you know it will), you don't want your application to go down in flames too.

Exception handlers are reasonably good at providing isolation between an application and 3rd party code.  This is especially wise if the 3rd party code might be updated at a later date, or might exist in various versions on the end users' computers.

Quick Hacks
Two spreadsheets need to be merged, then the result exported to XML.  That is a good job for a quick and dirty script.  However the script keeps crashing because of the occasional high-ascii garbage character at the end of lines.  Wrap the offending code in an exception handler and forget about it.  In this case the 'correct' course of action would have been to only filter out those specific characters and not risk eating ‘smart-quotes’ or £ symbols.  But given that this is a one-time script and there are no such characters in the current data, an exception handler gets the job done quickly.

Unfortunately many programmers pick up the habit of using exception handlers in quick and dirty situations like this, then continue using them in the same way when they migrate to writing more substantial code.


3. Concluding Thoughts

Exception handling is an important tool for programmers.  But it can be, and often is, used inappropriately.  "GOTO" was once a valuable tool, but we abused it and as a result it was taken away from us.  If programmers continue to abuse exception handlers in the same way, exception handling will acquire a bad name and it will eventually be taken away.  I find it helpful to think of an exception handler as an ejection seat: use it to save yourself in an emergency, but do not use it for routine issues.  Think twice before using an exception handler.

Further Reading

Exception Handling: A False Sense of Security
Tom Cargill argues that exceptions are too dangerous to use in C++.
Exception-Safety in Generic Components
David Abrahams argues that Tom Cargill is overly paranoid.
Exceptions and error handling, C++ FAQ Lite
Marshall Cline provides some warnings and suggestions about C++.
Best Practices for Exception Handling
Gunjan Doshi offers some sound advice on Java exceptions.
Does Java need Checked Exceptions?
Bruce Eckel suggests that checked exceptions encourage bad programming.
-------------------------------------
Last modified: 7 January 2005