pitfalls of signals

M

Mantorok Redgormor

Should I just avoid them?
I have heard many bad things about them
1) if you set a signal handler, you can't really ignore the signal and
continue with normal program execution, because after that undefined
behavior is invoked.

2) if you have a signal handler set for say SIG_INT and you continue
to reset the handler after you received the signal, to continue normal
program execution, and the signal is received twice or something you
end up invoking undefined behavior and re-entry of a signal handler
function causing major problems

what are some other things i should be aware of for signals?

and what should i do about points 1 and 2?

there really is no alternative to a portable function like signal but
signal itself seems to be a hazardous piece of crap
 
D

Dave Vandervies

Should I just avoid them?
I have heard many bad things about them
1) if you set a signal handler, you can't really ignore the signal and
continue with normal program execution, because after that undefined
behavior is invoked.

This is not universally true and, in the cases where it is true, is a
red herring.

If you have a signal handler that was invoked as a result of your program
calling raise(), then the signal is handled in a well-defined manner and
you can continue your program exactly the same way as if you had just
called the signal handler directly (unless you call raise() or abort()
in the signal handler; in that case you've invoked undefined behavior
before the normal program execution continues (N869 7.14.1.1#4)).

If a signal handler is invoked asynchronously because of an external event
unrelated to a computational exception, then normal program execution
continues after the handler returns, without invoking undefined behavior
(unless you've invoked undefined behavior in the handler by calling a
library function other than the ones you're specifically permitted to
call) (N869 7.14.1.1#3).

If a signal handler is invoked because of a computational exception, the
program has already invoked undefined behavior (f'rexample, by dividing
by zero or dereferencing a bad pointer) (N869 7.14.1.1#3); the signal
handler is your chance to clean up some things and terminate somewhat less
ungracefully (which, unless you can do it without calling any library
functions, invokes more undefined behavior), or possibly fix the cause
of the error (the way to do that will be completely system-specific),
also invoking undefined behavior.

So the only way undefined behavior can be invoked by a signal handler
ignoring the cause of the signal and returning (allowing the program to
continue) is if the signal was raised because something in the program
already invoked undefined behavior.

2) if you have a signal handler set for say SIG_INT and you continue
to reset the handler after you received the signal, to continue normal
program execution, and the signal is received twice or something you
end up invoking undefined behavior and re-entry of a signal handler
function causing major problems

I'm not quite sure what you're trying to say here, but if you're worried
about the signal handler getting re-invoked because a signal is raised
before the handler finishes, I don't think that's a problem.
Implementations are allowed to do one of two things to deal with this:
-Temporarily block a set of signals that includes the one the handler
is dealing with until the handler finishes. In this case the signal
handler cannot be re-entered as a result of another signal being
received, so there is no problem.
-Reset the handler for that signal to SIG_DFL before invoking the handler.
In this case, the user-defined handler will not be re-entered unless
the handler reinstates itself for that signal. If the handler does
things that shouldn't be done in overlapping calls, then just don't
reinstate the signal until those things are complete. Since a signal
handler is explicitly permitted to reinstate itself (N869 7.14.1.1#5),
the implementation is responsible for making sure that nothing invokes
undefined behavior by stepping on its toes after it's done so.

what are some other things i should be aware of for signals?

The standard specification of signal handling (section 7.14 in N869 (and
I assume C99 as well), or its equivalent in C90), plus the platform's
specification of signal handling for every platform you're supporting.

and what should i do about points 1 and 2?

Understand them well enough to know better than to worry about them.

there really is no alternative to a portable function like signal but
signal itself seems to be a hazardous piece of crap

The portable parts aren't dangerous, and the dangerous parts aren't
portable, so I don't see a problem here.

signal itself really isn't as portable as it looks; all it does is provide
a portable way to hook into system-specific behavior (like computational
exceptions and external interruptions) or know that the implementation
doesn't support it.

It's perfectly valid for signal() to always return SIG_ERR, which will
make it pretty much useless for anything you wanted to do with it.


dave
 
M

Mantorok Redgormor

This is not universally true and, in the cases where it is true, is a
red herring.

If you have a signal handler that was invoked as a result of your program
calling raise(), then the signal is handled in a well-defined manner and
you can continue your program exactly the same way as if you had just
called the signal handler directly (unless you call raise() or abort()
in the signal handler; in that case you've invoked undefined behavior
before the normal program execution continues (N869 7.14.1.1#4)).

If a signal handler is invoked asynchronously because of an external event
unrelated to a computational exception, then normal program execution
continues after the handler returns, without invoking undefined behavior
(unless you've invoked undefined behavior in the handler by calling a
library function other than the ones you're specifically permitted to
call) (N869 7.14.1.1#3).

If a signal handler is invoked because of a computational exception, the
program has already invoked undefined behavior (f'rexample, by dividing
by zero or dereferencing a bad pointer) (N869 7.14.1.1#3); the signal
handler is your chance to clean up some things and terminate somewhat less
ungracefully (which, unless you can do it without calling any library
functions, invokes more undefined behavior), or possibly fix the cause
of the error (the way to do that will be completely system-specific),
also invoking undefined behavior.

So the only way undefined behavior can be invoked by a signal handler
ignoring the cause of the signal and returning (allowing the program to
continue) is if the signal was raised because something in the program
already invoked undefined behavior.



I'm not quite sure what you're trying to say here, but if you're worried
about the signal handler getting re-invoked because a signal is raised
before the handler finishes, I don't think that's a problem.
Implementations are allowed to do one of two things to deal with this:
-Temporarily block a set of signals that includes the one the handler
is dealing with until the handler finishes. In this case the signal
handler cannot be re-entered as a result of another signal being
received, so there is no problem.
-Reset the handler for that signal to SIG_DFL before invoking the handler.
In this case, the user-defined handler will not be re-entered unless
the handler reinstates itself for that signal. If the handler does
things that shouldn't be done in overlapping calls, then just don't
reinstate the signal until those things are complete. Since a signal
handler is explicitly permitted to reinstate itself (N869 7.14.1.1#5),
the implementation is responsible for making sure that nothing invokes
undefined behavior by stepping on its toes after it's done so.

Well this explains it: http://razor.bindview.com/publish/papers/signals.html

The standard specification of signal handling (section 7.14 in N869 (and
I assume C99 as well), or its equivalent in C90), plus the platform's
specification of signal handling for every platform you're supporting.



Understand them well enough to know better than to worry about them.



The portable parts aren't dangerous, and the dangerous parts aren't
portable, so I don't see a problem here.

signal itself really isn't as portable as it looks; all it does is provide
a portable way to hook into system-specific behavior (like computational
exceptions and external interruptions) or know that the implementation
doesn't support it.

It's perfectly valid for signal() to always return SIG_ERR, which will
make it pretty much useless for anything you wanted to do with it.


dave

- nethlek
 
D

Dave Vandervies

(e-mail address removed) (Dave Vandervies) wrote in message


This looks pretty unix-specific to me, so comp.unix.programmer would
probably be a better place to discuss specific problems related to it
than comp.lang.c .

It seems to me, though, that all of the problems noted there are caused
by asynchronous signal handlers doing things that are specifically stated
to cause undefined behavior if done in an asynchronous signal handler,
so saying that signals are unsafe because of this is a lot like saying
that dynamic memory allocation is unsafe because using a pointer that's
been freed invokes undefined behavior. The correct solution is to be
aware of the restrictions that need to be observed and to be careful
(or to use constructs that are harder to do dangerous things with if
you're unwilling or unable to do so).


dave
 
V

Villy Kruse

I'm not quite sure what you're trying to say here, but if you're worried
about the signal handler getting re-invoked because a signal is raised
before the handler finishes, I don't think that's a problem.
Implementations are allowed to do one of two things to deal with this:
-Temporarily block a set of signals that includes the one the handler
is dealing with until the handler finishes. In this case the signal
handler cannot be re-entered as a result of another signal being
received, so there is no problem.
-Reset the handler for that signal to SIG_DFL before invoking the handler.
In this case, the user-defined handler will not be re-entered unless
the handler reinstates itself for that signal. If the handler does
things that shouldn't be done in overlapping calls, then just don't
reinstate the signal until those things are complete. Since a signal
handler is explicitly permitted to reinstate itself (N869 7.14.1.1#5),
the implementation is responsible for making sure that nothing invokes
undefined behavior by stepping on its toes after it's done so.


The end result will be quite different. When a new signal arrives while
the handler is set to SIG_DFL the result can be quite catastrofic for
the process, considering the normal action of SIG_DFL is to terminate
the process.


Villy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top