Question: signal and program termination

Doug Gwyn gwyn at smoke.brl.mil
Thu Jan 31 07:14:32 AEST 1991


In article <87792 at tut.cis.ohio-state.edu> <meranda at iguana.cis.ohio-state.edu> writes:
>   occur by calling exit() within a handler?  Clearly, any cleanup
>   functions set up by atexit() would have to be called.  However, if
>   some data was left in an undefined state because of the signal,
>   then couldn't these exit functions completely fail?

Sure; your code could easily have a bug like that.

Note that it is quite difficult to write RELIABLE programs that consist
of "concurrent" (or at least, asynchronous) communicating processes.
This reliability issue is why I invariably recommend that the ONLY thing
you do in a signal handler be to set a flag (of type sig_atomic_t),
possibly alter the signal state via a call to signal(), and then resume
execution, with the actual exception handling logic performed at one or
more appropriate points within your main application code (where you
know that the data structures are consistent).  Otherwise, you have to
lock out signals during "critical regions" etc. throughout the
application, which is tedious and error-prone.

>   What happens if the handler
>   for SIGABRT is set to SIG_IGN and later abort() is called?

The abort() implementation must in effect reset the state to SIG_DFL
unless there is a signal handler function established already, before
performing the raise(SIGABRT).  SIG_IGN is not honored by abort().

>   what happens if a user supplied handler is installed for SIGABRT...
>   Since abort() is not permitted to return, what would happen if
>   the handler decided to call exit(), longjmp(), or even worse
>   abort() again, rather than strictly returning?

abort() never returns to the point at which it was invoked (I would say
"never returns a value", except as a void function it doesn't have a
value to return anyway).  If the signal handler returns, abort() then
terminates the process.  Otherwise, it is possible for the program to
continue by e.g. a longjmp() from the signal handler.  If the signal
handler invokes exit(), the normal semantics for exit() apply.  If the
signal handler invokes abort(), then the semantics for abort() are
recursively invoked.  Indeed, it is possible to produce a loop this
way (presumably a stack overflow would eventually occur).

>3) I would assume that signal handlers are permitted to raise other
>   signals.  Say, if the default action for SIGINT's handler was to
>   terminate the program, would it be more appropriate to raise
>   SIGABRT or SIGTERM -- or should it just call exit() and suffer the
>   same problems mentioned in question 1?

In the usual case that a SIGINT would be externally (asynchronously)
generated, the standard says that the only standard function you may
call in a strictly conforming signal handler would be signal(SIGINT,).
In the case of a synchronous signal generated by raise() or abort(),
you may safely use all the standard library functions, including raise().

As I mentioned previously, I don't recommend that an asynchronously
invoked signal handler attempt to do much more than set a flag.

>   computational exception.  Among the ANSI defined signals, which
>   ones do indicate a computational exception?

SIGFPE.  I would also expect that many implementations will choose to
define the "computational exceptions" to include SIGILL and SIGSEGV,
in order to be allowed to have undefined behavior if the signal handler
attempts to return in those cases.



More information about the Comp.std.c mailing list