Richard Harter's World
Site map
March 2008
Comp. Sci.
email

Handling storage allocation failure in C

One of the issues when programming in C is to choose a strategy for dealing with allocation failures, e.g., what to do when malloc returns 0? One approach, perhaps one that is all too common, is to simply ignore the possibility of failure. This works (and avoids a lot of code writing) if the occasional strange crash isn't important. A more responsible strategy is to check each malloc return for validity and write error response code in each case.

Writing "check for errors and writing response code" for each call to malloc is, of course, a viable strategy. However there are issues to be considered. Three such are (a) the unreliability of "fixup" code, (b) the non-uniformity of error response, and (c) code littering.

  1. Unreliability: The code in these "failure to allocate" clauses isn't easy to test properly, and, in the absence of an allocator wrapper, isn't easy to test at all. This may not matter if the only action is to write a message to stderr and call exit, but it definitely is an issue for more elaborate responses such as request size retries and alternate algorithms.

    In my view, reliable programs (and if we are not interested in reliable programs why bother to test at all) are developed and maintained with test harnesses that test the alternatives.

  2. Non-uniformity: Since each "failure to allocate" test clause is individually written there is no guaranteed uniformity of response to error conditions.

    When I develop software in C my preference is to include an error management module tailored to the program. I find that using a "good" error management module means that it is easier to get meaningful responses when errors happen. Obviously this is not a universal solution. (li) Code littering: These little "failure to allocate" tests litter the code, i.e., they break into the readable flow of action of functions with tangential tests. Granted, this is not a major issue; none-the-less such littering makes code harder to read to some degree and requires more code writing.

All of that said, what is one to do? My suggestion is to use a wrapper for malloc for almost all storage allocation requests. The "failure to allocate" test and the subsequent error response (e.g., write an error message and call exit) is in one place rather than being scattered as multiple copies throughout the code.

But what, the skeptic says, should we do when we want to do something special such as retrying with a smaller size or using an alternative less memory intensive algorithm? One answer is simple and obvious; don't use the wrapper in these special cases. A better answer is to have a second entry into the wrapper package that does return 0 on a failure to allocate, the point being that the wrapper can have a back door to force failure, a feature very useful in a test harness. We all test our code in test harnesses, don't we?

Some have argued that a wrapper that terminates the program when there is an error is a "crash and burn" strategy that can lead to a large loss of results, i.e., losing files, data, or calculations. This is pretty much of a strawman. Programs can crash at any time for reasons beyond the control of the program; if preserving results is critical, there are well known strategies such as checkpointing and journaling. More than that using wrappers and an error management package is not a "crash and burn" strategy, it is a "black box" strategy, i.e., a strategy that is oriented towards preserving critical information when there is a crash.


This page was last updated March 1, 2008.

Richard Harter's World
Site map
March 2008
Comp. Sci.
email