New submission from Steven G. Johnson <stevenj....@gmail.com>:

In embedded Python, if the embedding code sets a signal handler (e.g. for 
SIGINT), then signal.getsignal(SIGINT) returns None.   However, 
signal.signal(SIGINT, signal.getsignal(SIGINT)) throws a TypeError, even though 
it should logically be a no-op.   This behavior is all implemented in 
Modules/signalmodule.c and seems to have been around since 2.7 at least.

(Background: We observed this in Julia, which embeds Python in order to call 
Python code, where matplotlib code that temporarily set signal(SIGINT, SIG_DFL) 
led to an exception when it tried to restore the original signal handler.  See 
https://github.com/JuliaPy/PyPlot.jl/issues/459)

The C program below exhibits this problem [it sets its own SIGINT handler and 
then starts up Python to execute signal(SIGINT,getsignal)].   Running it 
results in "TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, 
or a callable object"

Recommended changes:

1) if Handlers[signalnum].func == NULL, then signal(signalnum, None) should be 
a no-op, returning None.     This will allow signal(signalnum, 
getsignal(signalnum)) to always succeed (as a no-op).

2) if Handlers[signalnum].func == NULL, then signal(signalnum, SIG_DFL) should 
be a no-op, returning None.  That is, the default signal handler should be the 
foreign signal handler if one is installed.

3) The signal-handling documentation should warn against overriding the signal 
handler for any signalnum where getsignal(signalnum) returns None (i.e. a 
foreign signal handler), since there is no way to restore the original signal 
handler afterwards. Anyway, you should be cautious about overriding signal 
handlers that don't come from Python.   

test code that throws a TypeError (compile and link with libpython):

#include <Python.h>
#include <signal.h>
#include <stdio.h>
void myhandler(int sig) { printf("got signal %d\n", sig); }
int main(void)
{
    signal(SIGINT, myhandler);
    Py_InitializeEx(0);
    PyRun_SimpleString("import signal\n"
                       "old_signal = signal.getsignal(signal.SIGINT)\n"
                       "signal.signal(signal.SIGINT, old_signal)\n"
                       "print(old_signal)\n");
    Py_Finalize();
    return 0;
}

----------
components: Library (Lib)
messages: 360578
nosy: Steven G. Johnson
priority: normal
severity: normal
status: open
title: better handling of foreign signal handlers in signal.signal
type: behavior
versions: Python 2.7, Python 3.5, Python 3.6, Python 3.7, Python 3.8, Python 3.9

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue39438>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to