From: scs@adam.mit.edu (Steve Summit)
Subject: Re: Life, stderr, and everything (was Re: malloc() as a user...)
Organization: none, at the moment
Date: Thu, 15 Oct 1992 19:28:31 GMT

In several articles, Richard A. O'Keefe and Fergus James
HENDERSON have been discussing the relative merits of calling or
not calling perror after a malloc failure.  Fergus correctly
claims that calling perror might produce meaningful information,
and Richard correctly claims that it is not guaranteed to do so,
and that it might therefore produce misleading information.

Before discussing malloc, let us consider a more straightforward
example: opening files.  Code like:

	if((fd = fopen(filename, "r")) == NULL)
		{
		fprintf(stderr, "%s: can't open %s: %s\n",
				progname, filename, strerror(errno));
		return Error;
		}

[note 1] is, by Richard's arguments and the ANSI C Standard, just
as "dangerous."  ANSI C does not document fopen as being one of
the routines which sets errno; therefore, we cannot prove that
errno will be meaningful after an fopen failure.  However, the
"safer" code:

	if((fd = fopen(filename, "r")) == NULL)
		{
		fprintf(stderr, "%s: can't open %s\n",
					progname, filename);
		return Error;
		}

is, by *my* standards, completely unacceptable.  There are
several different reasons why an fopen could fail, and (under
many systems), errno does distinguish between some of them [note 2].
I insist that code which opens files (or performs other I/O
operations) interpret errno in the case of error, even if there
is a possibility that the information could be inapplicable; most
of the time, it is useful, and often vital.

There's a bit of game theory involved here, as represented in the
following table:

	+----------------+-------------------+----------------+
	| chance that:   | if my code        | if my code     |
	|                | interprets errno: | ignores errno: |
	+----------------+-------------------+----------------+
	| user sees      |                   |                |
	| useful         |        99%        |        0%      |
	| information    |                   |                |
	+----------------+-------------------+----------------+
	| user sees      |                   |                |
	| misleading     |         1%        |        0%      |
	| information    |                   |                |
	+----------------+-------------------+----------------+
	| user sees      |                   |                |
	| no information |         0%        |      100%      |
	+----------------+-------------------+----------------+

Since the last column guarantees disgruntled users, I much prefer
to muck about with the first one [3].  This is, however, very
much a judgement call.  It's possible to be so worried about
that 1% misleading factor (or to be so insistent upon certainty,
for better or worse) that your decision swings to the last
column.  There is also evidently a third possibility: the last
time this subject was discussed, I got mail from someone who
believed strongly that errno should be neither ignored nor
interpreted via perror/strerror but rather printf'ed %d; this
person was most concerned about the (nonzero, to be sure)
probability that the perror text can be misleading for a
particular choice of an errno value for a particular failure
mode of a particular system call.

A lot depends on how precisely defined you think errno values
are, and how you choose to respond to uncertainty.  If you
believe that there is a well-defined list of errno values which
can result from a particular call (which, for a single release of
a single variant of a single operating system, there might be),
you can decide definitively whether those values (and their
associated text messages) always make sense or not.  If you
assume that the errno values might change over time, or that your
code might be ported to other systems, you can either fear that
the evolving errno values might not be reasonable, or hope that
they will be.

One's choice also depends very much on the call which might be
generating the error.  I interpret perror routinely for I/O
calls; my decision to do so is based both on experience (most
systems do end up setting errno appropriately after e.g. fopen,
whether they are required to or not) and on the Posix standard
(which, in IEEE 1003.1-1988 section 8.2.3.11, at least, requires
that "the value returned in errno [after a stdio error] shall be
the one provided for the underlying function", where the
"underlying functions" are the Posix system calls upon which
stdio is built).

It's true that traditional Unix malloc/brk/sbrk implementations
have only one possible errno value: ENOMEM.  But if we think that
one day our code might be ported to some system which does
distinguish more finely among various out-of-memory conditions,
as Fergus has suggested, then interpreting errno after a malloc
failure might be a wise thing to do.

I have not been interpreting errno after malloc failures,
although based on Fergus's arguments, I might begin to do so.
(I note, however, that the Posix standard, at least in section
B1.4.3 of the 1988 version, does *not* give any more assurances
for malloc's implementation and failure modes than does X3.159 .)

In spite of my obvious bias, I am not trying to argue one way or
the other.  There is no one right answer here (i.e. Richard and
Fergus are never going to convince each other); one has to decide
based on a program's expected life history which approach is
preferable.

					Steve Summit
					scs@adam.mit.edu

Note 1.  I use strerror rather than perror so that errno's value
is used immediately, rather than after a call to fprintf (to
print the first part of the message) which could itself corrupt
errno's value.  (This has to do with the infamous "can't send
mail to user frodo: Not a typewriter" buglet.  Fergus's code had
this problem, although I can't criticize him too much, because
most of my code does, too.  If you want error messages which
contain some fixed text and the perror text *and* any other text,
e.g. a filename, you either have to stash errno's value and then
restore it just before calling perror, or else consign perror to
the "useless" category along with gets, and use strerror
instead.)

Note 2.  ENOENT, "No such file or directory", is still ambiguous,
and I occasionally wish that the two situations could be more
easily differentiated.

Note 3.  With apologies to Douglas Adams.