[New-bugs-announce] [issue39438] better handling of foreign signal handlers in signal.signal

Steven G. Johnson report at bugs.python.org
Thu Jan 23 15:28:37 EST 2020


New submission from Steven G. Johnson <stevenj.mit at 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 <report at bugs.python.org>
<https://bugs.python.org/issue39438>
_______________________________________


More information about the New-bugs-announce mailing list