Skip to content

Commit 519b2ae

Browse files
gh-117021: Fix integer overflow in PyLong_AsPid() on non-Windows 64-bit platforms (GH-117064)
1 parent 8182319 commit 519b2ae

File tree

7 files changed

+74
-2
lines changed

7 files changed

+74
-2
lines changed

Include/Python.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "bytearrayobject.h"
6464
#include "bytesobject.h"
6565
#include "unicodeobject.h"
66+
#include "pyerrors.h"
6667
#include "longobject.h"
6768
#include "cpython/longintrepr.h"
6869
#include "boolobject.h"
@@ -99,7 +100,6 @@
99100
#include "cpython/picklebufobject.h"
100101
#include "cpython/pytime.h"
101102
#include "codecs.h"
102-
#include "pyerrors.h"
103103
#include "pythread.h"
104104
#include "cpython/context.h"
105105
#include "modsupport.h"

Include/longobject.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,24 @@ PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
4040
#if !defined(SIZEOF_PID_T) || SIZEOF_PID_T == SIZEOF_INT
4141
#define _Py_PARSE_PID "i"
4242
#define PyLong_FromPid PyLong_FromLong
43-
#define PyLong_AsPid PyLong_AsLong
43+
# if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
44+
# define PyLong_AsPid PyLong_AsInt
45+
# elif SIZEOF_INT == SIZEOF_LONG
46+
# define PyLong_AsPid PyLong_AsLong
47+
# else
48+
static inline int
49+
PyLong_AsPid(PyObject *obj)
50+
{
51+
int overflow;
52+
long result = PyLong_AsLongAndOverflow(obj, &overflow);
53+
if (overflow || result > INT_MAX || result < INT_MIN) {
54+
PyErr_SetString(PyExc_OverflowError,
55+
"Python int too large to convert to C int");
56+
return -1;
57+
}
58+
return (int)result;
59+
}
60+
# endif
4461
#elif SIZEOF_PID_T == SIZEOF_LONG
4562
#define _Py_PARSE_PID "l"
4663
#define PyLong_FromPid PyLong_FromLong

Lib/test/test_capi/test_long.py

+28
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,34 @@ def test_long_asvoidptr(self):
425425
self.assertRaises(OverflowError, asvoidptr, -2**1000)
426426
# CRASHES asvoidptr(NULL)
427427

428+
def _test_long_aspid(self, aspid):
429+
# Test PyLong_AsPid()
430+
from _testcapi import SIZEOF_PID_T
431+
bits = 8 * SIZEOF_PID_T
432+
PID_T_MIN = -2**(bits-1)
433+
PID_T_MAX = 2**(bits-1) - 1
434+
# round trip (object -> long -> object)
435+
for value in (PID_T_MIN, PID_T_MAX, -1, 0, 1, 1234):
436+
with self.subTest(value=value):
437+
self.assertEqual(aspid(value), value)
438+
439+
self.assertEqual(aspid(IntSubclass(42)), 42)
440+
self.assertEqual(aspid(Index(42)), 42)
441+
self.assertEqual(aspid(MyIndexAndInt()), 10)
442+
443+
self.assertRaises(OverflowError, aspid, PID_T_MIN - 1)
444+
self.assertRaises(OverflowError, aspid, PID_T_MAX + 1)
445+
self.assertRaises(TypeError, aspid, 1.0)
446+
self.assertRaises(TypeError, aspid, b'2')
447+
self.assertRaises(TypeError, aspid, '3')
448+
self.assertRaises(SystemError, aspid, NULL)
449+
450+
def test_long_aspid(self):
451+
self._test_long_aspid(_testcapi.pylong_aspid)
452+
453+
def test_long_aspid_limited(self):
454+
self._test_long_aspid(_testlimitedcapi.pylong_aspid)
455+
428456
def test_long_asnativebytes(self):
429457
import math
430458
from _testcapi import (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix integer overflow in :c:func:`PyLong_AsPid` on non-Windows 64-bit
2+
platforms.

Modules/_testcapi/long.c

+12
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,24 @@ pylong_fromnativebytes(PyObject *module, PyObject *args)
9292
return res;
9393
}
9494

95+
static PyObject *
96+
pylong_aspid(PyObject *module, PyObject *arg)
97+
{
98+
NULLABLE(arg);
99+
pid_t value = PyLong_AsPid(arg);
100+
if (value == -1 && PyErr_Occurred()) {
101+
return NULL;
102+
}
103+
return PyLong_FromPid(value);
104+
}
105+
95106

96107
static PyMethodDef test_methods[] = {
97108
_TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF
98109
{"pylong_fromunicodeobject", pylong_fromunicodeobject, METH_VARARGS},
99110
{"pylong_asnativebytes", pylong_asnativebytes, METH_VARARGS},
100111
{"pylong_fromnativebytes", pylong_fromnativebytes, METH_VARARGS},
112+
{"pylong_aspid", pylong_aspid, METH_O},
101113
{NULL},
102114
};
103115

Modules/_testcapimodule.c

+1
Original file line numberDiff line numberDiff line change
@@ -3975,6 +3975,7 @@ PyInit__testcapi(void)
39753975
PyModule_AddObject(m, "SIZEOF_WCHAR_T", PyLong_FromSsize_t(sizeof(wchar_t)));
39763976
PyModule_AddObject(m, "SIZEOF_VOID_P", PyLong_FromSsize_t(sizeof(void*)));
39773977
PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t)));
3978+
PyModule_AddObject(m, "SIZEOF_PID_T", PyLong_FromSsize_t(sizeof(pid_t)));
39783979
PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version));
39793980
Py_INCREF(&PyInstanceMethod_Type);
39803981
PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);

Modules/_testlimitedcapi/long.c

+12
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,17 @@ pylong_asvoidptr(PyObject *module, PyObject *arg)
746746
return Py_NewRef((PyObject *)value);
747747
}
748748

749+
static PyObject *
750+
pylong_aspid(PyObject *module, PyObject *arg)
751+
{
752+
NULLABLE(arg);
753+
pid_t value = PyLong_AsPid(arg);
754+
if (value == -1 && PyErr_Occurred()) {
755+
return NULL;
756+
}
757+
return PyLong_FromPid(value);
758+
}
759+
749760

750761
static PyMethodDef test_methods[] = {
751762
_TESTLIMITEDCAPI_TEST_LONG_AND_OVERFLOW_METHODDEF
@@ -773,6 +784,7 @@ static PyMethodDef test_methods[] = {
773784
{"pylong_as_size_t", pylong_as_size_t, METH_O},
774785
{"pylong_asdouble", pylong_asdouble, METH_O},
775786
{"pylong_asvoidptr", pylong_asvoidptr, METH_O},
787+
{"pylong_aspid", pylong_aspid, METH_O},
776788
{NULL},
777789
};
778790

0 commit comments

Comments
 (0)