From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe)
Newsgroups: comp.lang.c
Subject: Re: Life, stderr, and everything (was Re: malloc() as a user...)
Date: 15 Oct 92 08:19:04 GMT
Organization: Comp Sci, RMIT, Melbourne, Australia

In article <9228916.10105@mulga.cs.mu.OZ.AU>, fjh@munta.cs.mu.OZ.AU
(Fergus James HENDERSON) continues an argument he and I seem to be
having about the merits of using perror() after a failed call to
malloc().

> That's why I say malloc() _may_ set errno, not that malloc() _will_ set errno.
> Certainly it may not.
> But if it does, then you _should_ call perror() to pass that information
> on to the user.

This completely misses the point.
The point is that C programmers on UNIX systems (and others)
have *no* *way* *to* *know* whether malloc() sets errno or not
other than reading the source code of their particular runtime library.

In my case, in order to get some facts to continue the argument
fruitfully, I disassembled malloc(), and determined that the only
system function for which there is a visible call is "sbrk()."
This was a little bit tricky because we have never had an instruction
set manual for the machine in question and the local supplier
representative of the chip manufacturer, despite having promised to
locate one for me, has never come up with the goods.  (I hope someone
from NatSemi is reading this.)
_Now_ I know that _in this release_ if malloc() sets errno at all
that it will have been set by sbrk().

But what does that tell me?  _In this release_ of the operating system
(a BSD variant) sbrk() has only one documented errno value: ENOMEM.
The hardware vendor has a System V.3 variant as well; sbrk() in that
system can report two errno values.  The V.3 variant is supposed to be
able to run binaries compiled and linked on the BSD variant; I wonder
whether they have two interfaces for sbrk(), or one?  In the latter case
my code could get an errno value that wasn't in the documentation.
For the record, the "other" errno value is EAGAIN, which is not
what you might call informative.  It certainly wouldn't tell Joe Luser
anything useful.  In fact, just to prove my point, here's what would
be produced if I called perror after a failed call to malloc() in the
System V.3 variant:

	No more processes

Do you *really* want to claim that I "_should_ call perror to pass"
THAT (mis)"information on to the user"?


> However, a _good_ implementation of malloc() _will_ set errno.
> I would guess that most current implementations of malloc() do set errno,
> although they might only have one error value, in which case it wouldn't
> really provide much information.

If there is only one error value, it is not useful to call perror.
(Its text is designed for the cognoscenti, not hoi polloi.)
For example, ENOMEM is glossed by perror as "Not enough space".
Is that swap space, per-process virtual memory, file space, or what?

If there are several possible error values, it _still_ may not be useful
to call perror.  UNIX errno values are "overloaded"; one number may be
used to mean several different things depending on which system call
reports it.  perror() doesn't know which system call reported the error,
so for overloaded error numbers you *often* get inappropriate text.

> You omitted the code I posted from your reply.
> If you read it carefully, you will see that I DON'T rely on malloc() setting
> errno: first I clear errno, then I call malloc(), and then IF AND ONLY IF
> errno is non-zero, I call perror().

Why don't you read the code carefully yourself?  You _do_ rely on malloc()
setting errno to something which perror() will gloss correctly (IF it
sets it), and that is demonstrably not the case on at least one version
of UNIX System V Release 3.

It is not documented that malloc() sets errno at all.
It is not documented that malloc() sets errno *meaningfully*.
For example,
	void *malloc(size_t size) { errno = E2BIG; return (void*)0; }
would be fully consistent with the available documentation.

 That way, if malloc() _does_ set errno,
> then you get a message like
> 	a.out: Unable to allocate enough memory: out of swap space.

Unfortunately, you may get
	a.out: Unable to allocate enough memory: No more processes.
I am not making this up.

There are many excellent things in Fergus Henderson's code.  His use of
"program", for example, deserves imitation.  But please, people, I am not
making it up, I am not exaggerating, when I say "you *CANNOT* trust errno
EXCEPT when the documentation EXPLICITLY says you can", and when I advise
you _not_ to rely on perror() for error messages sent to users.

My heart is pure:  I love UNIX and hate VMS just as I should.
But in comparison with VMS status codes, UNIX errno values are _shocking_.