Index Home About Blog
From: torek@elf.bsdi.com (Chris Torek)
Newsgroups: comp.lang.c
Subject: Re: scanf() weirdness, take 2
Date: 9 Feb 1997 14:56:04 -0800

In article <5divp1$mea@elf.bsdi.com> I wrote (rather briefly) that:
>>... errno is allowed to be set, and apparently to ERANGE, even on
>>non-errors [from strtol]

In article <y87mkhkfzu.fsf@qcd.lanl.gov> Tanmoy Bhattacharya
<tanmoy@qcd.lanl.gov> wrote:
>Can you give a reference?

Well, no need anymore; you already did. :-)

>I found in 7.1.3 ...

(and 7.10.1.5 (ISO numbering), wording that implies that strtol()
itself will not change errno arbitrarily, but is only allowed to set
it to ERANGE on error).

>The only relevant problem that I see is in 6.1.2.4, where it is not
>even clear that errno continues to refer to the same object throughout
>the life of the program. ...

This was the `really ugly' situation I was thinking of.

>I usually discard such ugly possibilities in c.l.c because it is
>likely that the standard was just loosely worded and, in all
>likelihood, this was not an intended reading of that section.

I agree that this is at least beyond the intent of the Standard
(which is why I said `a sufficiently perverse implementation'),
and would not normally bring it up here.  There is, however, another
situation in which errno gets set, usually *not* to ERANGE, `during'
a call to strtol(), in real programs that are not strictly conformant
ANSI/ISO C programs.  In particular, programs that catch signals
and do more than simply set a flag may end up setting errno at
`unpredictable' times.  Consider the (not strictly conforming) code
fragment:

	void catch(int sig) {
		if (interrupted == 0) {
			interrupted = 1;
		} else if (double_interrupt == 0) {
			fprintf(stderr, "\n[interrupt -- one more to kill]\n");
			double_interrupt = 1;
		} else {
			/* interrupted twice; jump to top level */
			longjmp(toplevel, INTERRUPTED);
		}
	}

This kind of code might sit inside an interpreter.  A single user
`abort' sets a flag (of type sig_atomic_t) that the interpreter
checks `often'.  For stubborn cases (perhaps the interpreter calls
compiled code that may fail to check the interrupt flag), you can
bang on abort three times and get a longjmp() back to the command
loop, possibly leaving the internals a bit messed up, but at least
back to where you can inspect the system's state.

Now, at the two-interrupt point, this particular code prints to
stderr, and many actual implementations have a side effect of
setting errno to ENOTTY on some (the `first for the stream') calls
to fprintf().  The overall effect in this case can be (and, in
practise, has been) to cause errno to get `mysteriously' set,
apparently `during' the operation of a function like strtol().

Again, this is not strictly conforming code, but because this kind
of `false errno' does occur in practise, I find the suspenders-and-
belt approach (of checking errno only if the function's return value
suggests an error) to be safer.

(If you *are* building a non-conformant system that does `real work'
in a signal handler, you can try saving and restoring errno.  In
general, this works fairly well, and prevents this kind of problem.
It might be nice if the C runtime environment for Unix-like systems
saved errno in the signal trampoline code, so that you did not have
to; that too would prevent this kind of error.)
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA	Domain:	torek@bsdi.com	+1 510 234 3167
Antispam notice: unsolicited commercial email will be handled at
	my consulting rate of $200/hr.

Index Home About Blog