A Discipline of Error Handling (1992)

In the UNIX world, exception handling mechanisms for eror handling are often discussed, but seldom applied. This paper describes a disciplined approach to error handling thar was refined over a !-year perioO during the development of a medium-large (200K line) toolkit written in C under UNIX We describe both a portable exception handing system, written in C, and a methodology for using it which encompasses coding style, doCumentation, and testing issues. Introduction There is more to good enor handling than simThe C language, as defined by Kemighan and O,]I t:.:g:.gt or lihrary support for raising and catch' Richey and by it.-Nst c standara, i. t.tiri'*rak i1_g i:eptions. .-In this-paPer'.I will explain what on ero, handing. The only standara,rror n*aniE :11t:^ar-e,.describe the desi8n issues in representing facilities providea .rc ttrr global variabfr .ttio ana andreporting errors, and discuss how our error han' the convention thar certain iunctions (such as ..ff., l$q^]fltotch affects coding style, documentation etc.) return a distinguished value whea they fail, posano iesimg' sibly setting enno. Two Kinds of Errors This is not a very good basis for eror handling. It isn't good for application programmers, because explicitly checking the return values of functions that might fail, and propagating the enor, is a lot of work, and clutters up code. Even conscientious programmers have been known to write programs that fail to check the return value of every call to printf. As a result, there are a non-trivial number of C programs in existence which fail to properly report error conditions [Danvin 85]. The standard approach to error handling isn,t good for library implernentors, either. One pioblem is that the existing set of effor numbers is not extensible; thus, you can't use the standard functions perrorQ, strerrorQ, etc., with locally defined error codes. Another problem is that a single integer (ermo) does not really contain enough information to completely describe an eror. Usually there is additional contextual information (such as the naiire of the file that couldn't be opened, the number of bytes that were successfully written before an error occurred, the line number on which the error was detected, etc.) that needs to be associated with an error. We faced these problems when we set out to build the EMS image processing toolkit in 1989. We were building a large library of fiinctions for building image processing applications, and we wanted our library to support the construction of robust applications. We wanted our library to support good eror handling. So we defined a comprehensive approach to good error handling, and wrote a small library of functions to support our eror handling discipline. EMS distinguishes two kinds of errors that can be detected by library functions: faults and failures. A fault condition is the failure of an assertion or sanity check. By definition, a fault always indicates the presence of a bug in a program. Faults checking is not part of the contract between the function and its caller, and faults are reported by aborting the program. Some kinds of fault checking (e.g., comprehensive data structure integrity checks) are expensive to perform, but are useful during debugging. Because client code is not allowed to depend on the existence of fault checks, expensive fault checks can be conditionally compiled based on a DEBUG option, without affecting the correctness of any progam. A failure is an abnormal but anticipated condition such as resource exhaustion, permission denied, or a syntax error, which prevents the function from carrying out its job. Failures differ from faults in that failure reports are part of the contract between the function and its caller. Failures are reported by reporting an effor back to the caller. An out of memory condition that causes mallocQ to return NULL is a simple example of a failure. Sometimes it is difficult to decide if a particular condition (e.g., an illegal argument valuef should be classified as a fault or a failure. Mv rule of thumb is that it should be possible, using the library, to write programs that never generate fault conditions under any circumstances. Suppose that the exceptional condition is the detection of a syntax error in an input file, or in a character string that might have originated from outside of the program. In this case, the condition should be classified as a failure, rather than as a fault. If it were classified as Summer '92 USENIX June 8-June 12,lgg2 San Antonlo, TX 123 A Disclpllne of Error Handling a fault, then a program written to avoid generating faults is obliged to scan the input beforehand to ensure the absence of syntax errors.