]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117021: Fix integer overflow in PyLong_AsPid() on non-Windows 64-bit platforms...
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 20 Mar 2024 13:39:53 +0000 (15:39 +0200)
committerGitHub <noreply@github.com>
Wed, 20 Mar 2024 13:39:53 +0000 (15:39 +0200)
Include/Python.h
Include/longobject.h
Lib/test/test_capi/test_long.py
Misc/NEWS.d/next/C API/2024-03-20-13-13-22.gh-issue-117021.0Q5jBx.rst [new file with mode: 0644]
Modules/_testcapi/long.c
Modules/_testcapimodule.c
Modules/_testlimitedcapi/long.c

index 01fc45137a17bbced8188f12d8dca24986002f44..ca38a98d8c4eca06f6090bc898bd06bac819c51f 100644 (file)
@@ -63,6 +63,7 @@
 #include "bytearrayobject.h"
 #include "bytesobject.h"
 #include "unicodeobject.h"
+#include "pyerrors.h"
 #include "longobject.h"
 #include "cpython/longintrepr.h"
 #include "boolobject.h"
 #include "cpython/picklebufobject.h"
 #include "cpython/pytime.h"
 #include "codecs.h"
-#include "pyerrors.h"
 #include "pythread.h"
 #include "cpython/context.h"
 #include "modsupport.h"
index 51005efff636fac7b938ff356431749faba92ebb..19104cd9d1bef9708e7d5e17bfc11dc5bab254bf 100644 (file)
@@ -40,7 +40,24 @@ PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
 #if !defined(SIZEOF_PID_T) || SIZEOF_PID_T == SIZEOF_INT
 #define _Py_PARSE_PID "i"
 #define PyLong_FromPid PyLong_FromLong
-#define PyLong_AsPid PyLong_AsLong
+# if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
+#   define PyLong_AsPid PyLong_AsInt
+# elif SIZEOF_INT == SIZEOF_LONG
+#   define PyLong_AsPid PyLong_AsLong
+# else
+static inline int
+PyLong_AsPid(PyObject *obj)
+{
+    int overflow;
+    long result = PyLong_AsLongAndOverflow(obj, &overflow);
+    if (overflow || result > INT_MAX || result < INT_MIN) {
+        PyErr_SetString(PyExc_OverflowError,
+                        "Python int too large to convert to C int");
+        return -1;
+    }
+    return (int)result;
+}
+# endif
 #elif SIZEOF_PID_T == SIZEOF_LONG
 #define _Py_PARSE_PID "l"
 #define PyLong_FromPid PyLong_FromLong
index 4ac6ea6b725ff145774b912f8da07265d55ae495..d2140154d811b4d777ef78ddabe259c8e5fb8906 100644 (file)
@@ -425,6 +425,34 @@ class LongTests(unittest.TestCase):
         self.assertRaises(OverflowError, asvoidptr, -2**1000)
         # CRASHES asvoidptr(NULL)
 
+    def _test_long_aspid(self, aspid):
+        # Test PyLong_AsPid()
+        from _testcapi import SIZEOF_PID_T
+        bits = 8 * SIZEOF_PID_T
+        PID_T_MIN = -2**(bits-1)
+        PID_T_MAX = 2**(bits-1) - 1
+        # round trip (object -> long -> object)
+        for value in (PID_T_MIN, PID_T_MAX, -1, 0, 1, 1234):
+            with self.subTest(value=value):
+                self.assertEqual(aspid(value), value)
+
+        self.assertEqual(aspid(IntSubclass(42)), 42)
+        self.assertEqual(aspid(Index(42)), 42)
+        self.assertEqual(aspid(MyIndexAndInt()), 10)
+
+        self.assertRaises(OverflowError, aspid, PID_T_MIN - 1)
+        self.assertRaises(OverflowError, aspid, PID_T_MAX + 1)
+        self.assertRaises(TypeError, aspid, 1.0)
+        self.assertRaises(TypeError, aspid, b'2')
+        self.assertRaises(TypeError, aspid, '3')
+        self.assertRaises(SystemError, aspid, NULL)
+
+    def test_long_aspid(self):
+        self._test_long_aspid(_testcapi.pylong_aspid)
+
+    def test_long_aspid_limited(self):
+        self._test_long_aspid(_testlimitedcapi.pylong_aspid)
+
     def test_long_asnativebytes(self):
         import math
         from _testcapi import (
diff --git a/Misc/NEWS.d/next/C API/2024-03-20-13-13-22.gh-issue-117021.0Q5jBx.rst b/Misc/NEWS.d/next/C API/2024-03-20-13-13-22.gh-issue-117021.0Q5jBx.rst
new file mode 100644 (file)
index 0000000..2f93e1e
--- /dev/null
@@ -0,0 +1,2 @@
+Fix integer overflow in :c:func:`PyLong_AsPid` on non-Windows 64-bit
+platforms.
index 8e4e1f2246f7257a3eff75b6b3e2b2b392d7eee1..28dca01bee09a07201394082a2f8350743d7a0bb 100644 (file)
@@ -92,12 +92,24 @@ pylong_fromnativebytes(PyObject *module, PyObject *args)
     return res;
 }
 
+static PyObject *
+pylong_aspid(PyObject *module, PyObject *arg)
+{
+    NULLABLE(arg);
+    pid_t value = PyLong_AsPid(arg);
+    if (value == -1 && PyErr_Occurred()) {
+        return NULL;
+    }
+    return PyLong_FromPid(value);
+}
+
 
 static PyMethodDef test_methods[] = {
     _TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF
     {"pylong_fromunicodeobject",    pylong_fromunicodeobject,   METH_VARARGS},
     {"pylong_asnativebytes",        pylong_asnativebytes,       METH_VARARGS},
     {"pylong_fromnativebytes",      pylong_fromnativebytes,     METH_VARARGS},
+    {"pylong_aspid",                pylong_aspid,               METH_O},
     {NULL},
 };
 
index 9621c654a7713f651f432fbe8b0e76884319c8e5..b73085bb8f67ce1340433fda1271d0abd7f53df5 100644 (file)
@@ -3975,6 +3975,7 @@ PyInit__testcapi(void)
     PyModule_AddObject(m, "SIZEOF_WCHAR_T", PyLong_FromSsize_t(sizeof(wchar_t)));
     PyModule_AddObject(m, "SIZEOF_VOID_P", PyLong_FromSsize_t(sizeof(void*)));
     PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t)));
+    PyModule_AddObject(m, "SIZEOF_PID_T", PyLong_FromSsize_t(sizeof(pid_t)));
     PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version));
     Py_INCREF(&PyInstanceMethod_Type);
     PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
index 16d41b1d4b16dc96d08963703d277439453cd0d4..5953009b6ef9b7872109c2c38ad937a31d9b2a94 100644 (file)
@@ -746,6 +746,17 @@ pylong_asvoidptr(PyObject *module, PyObject *arg)
     return Py_NewRef((PyObject *)value);
 }
 
+static PyObject *
+pylong_aspid(PyObject *module, PyObject *arg)
+{
+    NULLABLE(arg);
+    pid_t value = PyLong_AsPid(arg);
+    if (value == -1 && PyErr_Occurred()) {
+        return NULL;
+    }
+    return PyLong_FromPid(value);
+}
+
 
 static PyMethodDef test_methods[] = {
     _TESTLIMITEDCAPI_TEST_LONG_AND_OVERFLOW_METHODDEF
@@ -773,6 +784,7 @@ static PyMethodDef test_methods[] = {
     {"pylong_as_size_t",            pylong_as_size_t,           METH_O},
     {"pylong_asdouble",             pylong_asdouble,            METH_O},
     {"pylong_asvoidptr",            pylong_asvoidptr,           METH_O},
+    {"pylong_aspid",                pylong_aspid,               METH_O},
     {NULL},
 };