bin/78304: Signal handler abuse in comsat(8)
bde at zeta.org.au
Thu Mar 3 03:50:20 GMT 2005
The following reply was made to PR bin/78304; it has been noted by GNATS.
From: Bruce Evans <bde at zeta.org.au>
To: Gavin Atkinson <gavin.atkinson at ury.york.ac.uk>
Cc: FreeBSD-gnats-submit at freebsd.org
Subject: Re: bin/78304: Signal handler abuse in comsat(8)
Date: Thu, 3 Mar 2005 14:41:52 +1100 (EST)
On Wed, 2 Mar 2005, Gavin Atkinson wrote:
> I've been inspired by the talk given by Henning Brauer given at
> the UKUUG Winter 2005 on writing safe signal handlers, and have set about
> fixing some of them in the FreeBSD source tree.
In case you fix lots of these...
> while the main routine is already in the memory allocator. This latter
> signal has been fixed to simply set a flag, which is now polled and acted
> upon in the main loop.
... note that simply setting a flag is usually simply wrong, since FreeBSD
has restartable syscalls, restarting syscalls after a signal is the
default for signal(2), and most applications and libraries don't handle
changing the default using siginterrupt(3) or not setting the default
using sigaction(2) (!SA_RESTART). Restarting syscalls can result in the
poll in the main loop never being reached, since a syscall can wait forever.
Examples of utilities whose signal handling bugs have been moved by simply
setting a flag:
- ping(8). ping's fixes are not so simple but don't quite work. The
resolver library sometimes hangs, and SIGINT to abort ping doesn't work
because the resolver library restarts. In this case, the relevant
syscall is select() or kevent() so it isn't automatically restarted,
and callers of these syscalls must actually do something about EINTR,
but the resolver library doesn't know what to do and always restarts.
- top(1). top was changed to simply set a flag. It now hangs in a
read() from a terminal in some contexts. It then appears to ignore
SIGINT, but when you enter something the read completes, control
returns to the level that polls the flag, and the SIGINT actually
terminates the program.
Fixing this in large programs is hard, but comsat seems to be simple
enough to fix or to verify that there is no problem. Fixing a large
program seems to require never using automatic restarts for syscalls
and then fixing all the bugs exposed by this, perhaps starting with
the one in stdio (there is a PR about at least 1).
More information about the freebsd-bugs