From d3840503b0f590ee574fbdf3c96626ff8b3c45f6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Nov 2024 08:23:17 +0200 Subject: [PATCH] gh-126303: Fix pickling and copying of os.sched_param objects (GH-126336) --- Include/internal/pycore_typeobject.h | 1 + Lib/test/test_posix.py | 21 +++++++++++++++++++ ...-11-02-19-20-44.gh-issue-126303.yVvyWB.rst | 1 + Modules/posixmodule.c | 17 +++++++++++++++ Objects/typeobject.c | 6 ++++++ 5 files changed, 46 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-11-02-19-20-44.gh-issue-126303.yVvyWB.rst diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 118bc98b35d5e3..e72592b8e98ef8 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -243,6 +243,7 @@ extern PyObject* _PyType_GetFullyQualifiedName(PyTypeObject *type, char sep); // self->tp_flags = (self->tp_flags & ~mask) | flags; extern void _PyType_SetFlags(PyTypeObject *self, unsigned long mask, unsigned long flags); +extern int _PyType_AddMethod(PyTypeObject *, PyMethodDef *); // Like _PyType_SetFlags(), but apply the operation to self and any of its // subclasses without Py_TPFLAGS_IMMUTABLETYPE set. diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 35016b83a477fc..ef9d617f66feec 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -6,12 +6,14 @@ from test.support import warnings_helper from test.support.script_helper import assert_python_ok +import copy import errno import sys import signal import time import os import platform +import pickle import stat import tempfile import unittest @@ -1317,6 +1319,25 @@ def test_get_and_set_scheduler_and_param(self): param = posix.sched_param(sched_priority=-large) self.assertRaises(OverflowError, posix.sched_setparam, 0, param) + @requires_sched + def test_sched_param(self): + param = posix.sched_param(1) + for proto in range(pickle.HIGHEST_PROTOCOL+1): + newparam = pickle.loads(pickle.dumps(param, proto)) + self.assertEqual(newparam, param) + newparam = copy.copy(param) + self.assertIsNot(newparam, param) + self.assertEqual(newparam, param) + newparam = copy.deepcopy(param) + self.assertIsNot(newparam, param) + self.assertEqual(newparam, param) + newparam = copy.replace(param) + self.assertIsNot(newparam, param) + self.assertEqual(newparam, param) + newparam = copy.replace(param, sched_priority=0) + self.assertNotEqual(newparam, param) + self.assertEqual(newparam.sched_priority, 0) + @unittest.skipUnless(hasattr(posix, "sched_rr_get_interval"), "no function") def test_sched_rr_get_interval(self): try: diff --git a/Misc/NEWS.d/next/Library/2024-11-02-19-20-44.gh-issue-126303.yVvyWB.rst b/Misc/NEWS.d/next/Library/2024-11-02-19-20-44.gh-issue-126303.yVvyWB.rst new file mode 100644 index 00000000000000..0072c97338c251 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-02-19-20-44.gh-issue-126303.yVvyWB.rst @@ -0,0 +1 @@ +Fix pickling and copying of :class:`os.sched_param` objects. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index bb5077cc7f0f09..1ce2baecb8a964 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -24,6 +24,7 @@ #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_signal.h" // Py_NSIG #include "pycore_time.h" // _PyLong_FromTime_t() +#include "pycore_typeobject.h" // _PyType_AddMethod() #ifdef HAVE_UNISTD_H # include // symlink() @@ -8210,6 +8211,16 @@ os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority) return res; } +static PyObject * +os_sched_param_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return Py_BuildValue("(O(N))", Py_TYPE(self), PyStructSequence_GetItem(self, 0)); +} + +static PyMethodDef os_sched_param_reduce_method = { + "__reduce__", (PyCFunction)os_sched_param_reduce, METH_NOARGS|METH_COEXIST, NULL, +}; + PyDoc_VAR(os_sched_param__doc__); static PyStructSequence_Field sched_param_fields[] = { @@ -18033,6 +18044,12 @@ posixmodule_exec(PyObject *m) return -1; } ((PyTypeObject *)state->SchedParamType)->tp_new = os_sched_param; + if (_PyType_AddMethod((PyTypeObject *)state->SchedParamType, + &os_sched_param_reduce_method) < 0) + { + return -1; + } + PyType_Modified((PyTypeObject *)state->SchedParamType); #endif /* initialize TerminalSize_info */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 40225313a8a33b..88db29e14b0d44 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7656,6 +7656,12 @@ type_add_method(PyTypeObject *type, PyMethodDef *meth) return 0; } +int +_PyType_AddMethod(PyTypeObject *type, PyMethodDef *meth) +{ + return type_add_method(type, meth); +} + /* Add the methods from tp_methods to the __dict__ in a type object */ static int