Skip to content

Commit d54cfb1

Browse files
bpo-33441: Make the sigset_t converter available in other modules. (GH-6720)
* Expose the sigset_t converter via private API _Py_Sigset_Converter(). * Use Argument Clinic for parsing sigset_t in signalmodule.c. * Raise ValueError instead OverflowError for integers out of the C long range. Based on patch by Pablo Galindo Salgado.
1 parent a3f19c3 commit d54cfb1

File tree

5 files changed

+142
-105
lines changed

5 files changed

+142
-105
lines changed

Lib/test/test_signal.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,10 @@ def test_pthread_sigmask_arguments(self):
943943
self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
944944
with self.assertRaises(ValueError):
945945
signal.pthread_sigmask(signal.SIG_BLOCK, [signal.NSIG])
946+
with self.assertRaises(ValueError):
947+
signal.pthread_sigmask(signal.SIG_BLOCK, [0])
948+
with self.assertRaises(ValueError):
949+
signal.pthread_sigmask(signal.SIG_BLOCK, [1<<1000])
946950

947951
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
948952
'need signal.pthread_sigmask()')

Modules/clinic/signalmodule.c.h

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -278,17 +278,17 @@ PyDoc_STRVAR(signal_pthread_sigmask__doc__,
278278
{"pthread_sigmask", (PyCFunction)signal_pthread_sigmask, METH_FASTCALL, signal_pthread_sigmask__doc__},
279279

280280
static PyObject *
281-
signal_pthread_sigmask_impl(PyObject *module, int how, PyObject *mask);
281+
signal_pthread_sigmask_impl(PyObject *module, int how, sigset_t mask);
282282

283283
static PyObject *
284284
signal_pthread_sigmask(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
285285
{
286286
PyObject *return_value = NULL;
287287
int how;
288-
PyObject *mask;
288+
sigset_t mask;
289289

290-
if (!_PyArg_ParseStack(args, nargs, "iO:pthread_sigmask",
291-
&how, &mask)) {
290+
if (!_PyArg_ParseStack(args, nargs, "iO&:pthread_sigmask",
291+
&how, _Py_Sigset_Converter, &mask)) {
292292
goto exit;
293293
}
294294
return_value = signal_pthread_sigmask_impl(module, how, mask);
@@ -339,6 +339,24 @@ PyDoc_STRVAR(signal_sigwait__doc__,
339339
#define SIGNAL_SIGWAIT_METHODDEF \
340340
{"sigwait", (PyCFunction)signal_sigwait, METH_O, signal_sigwait__doc__},
341341

342+
static PyObject *
343+
signal_sigwait_impl(PyObject *module, sigset_t sigset);
344+
345+
static PyObject *
346+
signal_sigwait(PyObject *module, PyObject *arg)
347+
{
348+
PyObject *return_value = NULL;
349+
sigset_t sigset;
350+
351+
if (!PyArg_Parse(arg, "O&:sigwait", _Py_Sigset_Converter, &sigset)) {
352+
goto exit;
353+
}
354+
return_value = signal_sigwait_impl(module, sigset);
355+
356+
exit:
357+
return return_value;
358+
}
359+
342360
#endif /* defined(HAVE_SIGWAIT) */
343361

344362
#if (defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS))
@@ -379,6 +397,24 @@ PyDoc_STRVAR(signal_sigwaitinfo__doc__,
379397
#define SIGNAL_SIGWAITINFO_METHODDEF \
380398
{"sigwaitinfo", (PyCFunction)signal_sigwaitinfo, METH_O, signal_sigwaitinfo__doc__},
381399

400+
static PyObject *
401+
signal_sigwaitinfo_impl(PyObject *module, sigset_t sigset);
402+
403+
static PyObject *
404+
signal_sigwaitinfo(PyObject *module, PyObject *arg)
405+
{
406+
PyObject *return_value = NULL;
407+
sigset_t sigset;
408+
409+
if (!PyArg_Parse(arg, "O&:sigwaitinfo", _Py_Sigset_Converter, &sigset)) {
410+
goto exit;
411+
}
412+
return_value = signal_sigwaitinfo_impl(module, sigset);
413+
414+
exit:
415+
return return_value;
416+
}
417+
382418
#endif /* defined(HAVE_SIGWAITINFO) */
383419

384420
#if defined(HAVE_SIGTIMEDWAIT)
@@ -395,19 +431,18 @@ PyDoc_STRVAR(signal_sigtimedwait__doc__,
395431
{"sigtimedwait", (PyCFunction)signal_sigtimedwait, METH_FASTCALL, signal_sigtimedwait__doc__},
396432

397433
static PyObject *
398-
signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
434+
signal_sigtimedwait_impl(PyObject *module, sigset_t sigset,
399435
PyObject *timeout_obj);
400436

401437
static PyObject *
402438
signal_sigtimedwait(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
403439
{
404440
PyObject *return_value = NULL;
405-
PyObject *sigset;
441+
sigset_t sigset;
406442
PyObject *timeout_obj;
407443

408-
if (!_PyArg_UnpackStack(args, nargs, "sigtimedwait",
409-
2, 2,
410-
&sigset, &timeout_obj)) {
444+
if (!_PyArg_ParseStack(args, nargs, "O&O:sigtimedwait",
445+
_Py_Sigset_Converter, &sigset, &timeout_obj)) {
411446
goto exit;
412447
}
413448
return_value = signal_sigtimedwait_impl(module, sigset, timeout_obj);
@@ -499,4 +534,4 @@ signal_pthread_kill(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
499534
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
500535
#define SIGNAL_PTHREAD_KILL_METHODDEF
501536
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
502-
/*[clinic end generated code: output=f35d79e0cfee3f1b input=a9049054013a1b77]*/
537+
/*[clinic end generated code: output=549f0efdc7405834 input=a9049054013a1b77]*/

Modules/posixmodule.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,65 @@ PyLong_FromPy_off_t(Py_off_t offset)
12671267
#endif
12681268
}
12691269

1270+
#ifdef HAVE_SIGSET_T
1271+
/* Convert an iterable of integers to a sigset.
1272+
Return 1 on success, return 0 and raise an exception on error. */
1273+
int
1274+
_Py_Sigset_Converter(PyObject *obj, void *addr)
1275+
{
1276+
sigset_t *mask = (sigset_t *)addr;
1277+
PyObject *iterator, *item;
1278+
long signum;
1279+
int overflow;
1280+
1281+
if (sigemptyset(mask)) {
1282+
/* Probably only if mask == NULL. */
1283+
PyErr_SetFromErrno(PyExc_OSError);
1284+
return 0;
1285+
}
1286+
1287+
iterator = PyObject_GetIter(obj);
1288+
if (iterator == NULL) {
1289+
return 0;
1290+
}
1291+
1292+
while ((item = PyIter_Next(iterator)) != NULL) {
1293+
signum = PyLong_AsLongAndOverflow(item, &overflow);
1294+
Py_DECREF(item);
1295+
if (signum <= 0 || signum >= NSIG) {
1296+
if (overflow || signum != -1 || !PyErr_Occurred()) {
1297+
PyErr_Format(PyExc_ValueError,
1298+
"signal number %ld out of range", signum);
1299+
}
1300+
goto error;
1301+
}
1302+
if (sigaddset(mask, (int)signum)) {
1303+
if (errno != EINVAL) {
1304+
/* Probably impossible */
1305+
PyErr_SetFromErrno(PyExc_OSError);
1306+
goto error;
1307+
}
1308+
/* For backwards compatibility, allow idioms such as
1309+
* `range(1, NSIG)` but warn about invalid signal numbers
1310+
*/
1311+
const char msg[] =
1312+
"invalid signal number %ld, please use valid_signals()";
1313+
if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1, msg, signum)) {
1314+
goto error;
1315+
}
1316+
}
1317+
}
1318+
if (!PyErr_Occurred()) {
1319+
Py_DECREF(iterator);
1320+
return 1;
1321+
}
1322+
1323+
error:
1324+
Py_DECREF(iterator);
1325+
return 0;
1326+
}
1327+
#endif /* HAVE_SIGSET_T */
1328+
12701329
#ifdef MS_WINDOWS
12711330

12721331
static int

Modules/posixmodule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,17 @@ PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t);
1717
PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, void *);
1818
PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, void *);
1919
#endif /* MS_WINDOWS */
20+
21+
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
22+
defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
23+
# define HAVE_SIGSET_T
2024
#endif
2125

26+
#ifdef HAVE_SIGSET_T
27+
PyAPI_FUNC(int) _Py_Sigset_Converter(PyObject *, void *);
28+
#endif /* HAVE_SIGSET_T */
29+
#endif /* Py_LIMITED_API */
30+
2231
#ifdef __cplusplus
2332
}
2433
#endif

0 commit comments

Comments
 (0)