diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2023-11-27 08:25:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-27 08:25:06 (GMT) |
commit | 42df73652dba4937489e34a92dbf184a184c2d93 (patch) | |
tree | 850ff04e3ed9ed107c12f290e3151d9911584c93 | |
parent | d7a788332666eabade922bf5d976df8c362ecb14 (diff) | |
download | cpython-42df73652dba4937489e34a92dbf184a184c2d93.zip cpython-42df73652dba4937489e34a92dbf184a184c2d93.tar.gz cpython-42df73652dba4937489e34a92dbf184a184c2d93.tar.bz2 |
[3.12] gh-112358: Fix Python 3.12 regression with subclassing struct.Struct (GH-112424) (#112426)
* [3.12] gh-112358: Fix Python 3.12 regression with subclassing struct.Struct. (GH-112424)
Revert commit c8c0afc7137ab9f22bf59d591084948ca967c97c (PR GH-94532),
which moved `struct.Struct` initialisation from `Struct.__init__` to `Struct.__new__`.
This caused issues with code in the wild that subclasses `struct.Struct`..
(cherry picked from commit 9fe60340d7e8dc22b3aec205c557bc69a1b2d18c)
Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
* Remove unrelated test
-rw-r--r-- | Lib/test/test_struct.py | 24 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst | 2 | ||||
-rw-r--r-- | Modules/_struct.c | 59 | ||||
-rw-r--r-- | Modules/clinic/_struct.c.h | 16 |
4 files changed, 53 insertions, 48 deletions
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 6b1f22f..8d4b13a 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -700,20 +700,6 @@ class StructTest(unittest.TestCase): with self.assertRaises(TypeError): cls.x = 1 - @support.cpython_only - def test__struct_Struct__new__initialized(self): - # See https://github.com/python/cpython/issues/78724 - - s = struct.Struct.__new__(struct.Struct, "b") - s.unpack_from(b"abcd") - - @support.cpython_only - def test__struct_Struct_subclassing(self): - class Bob(struct.Struct): - pass - - s = Bob("b") - s.unpack_from(b"abcd") def test_issue35714(self): # Embedded null characters should not be allowed in format strings. @@ -774,6 +760,16 @@ class StructTest(unittest.TestCase): test_error_propagation('N') test_error_propagation('n') + def test_struct_subclass_instantiation(self): + # Regression test for https://github.com/python/cpython/issues/112358 + class MyStruct(struct.Struct): + def __init__(self): + super().__init__('>h') + + my_struct = MyStruct() + self.assertEqual(my_struct.pack(12345), b'\x30\x39') + + class UnpackIteratorTest(unittest.TestCase): """ Tests for iterative unpacking (struct.Struct.iter_unpack). diff --git a/Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst b/Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst new file mode 100644 index 0000000..e473ded --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst @@ -0,0 +1,2 @@ +Revert change to :class:`struct.Struct` initialization that broke some cases +of subclassing. diff --git a/Modules/_struct.c b/Modules/_struct.c index 4f9478b..55efc0c 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1550,9 +1550,28 @@ prepare_s(PyStructObject *self) return -1; } +static PyObject * +s_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *self; + + assert(type != NULL); + allocfunc alloc_func = PyType_GetSlot(type, Py_tp_alloc); + assert(alloc_func != NULL); + + self = alloc_func(type, 0); + if (self != NULL) { + PyStructObject *s = (PyStructObject*)self; + s->s_format = Py_NewRef(Py_None); + s->s_codes = NULL; + s->s_size = -1; + s->s_len = -1; + } + return self; +} + /*[clinic input] -@classmethod -Struct.__new__ +Struct.__init__ format: object @@ -1564,24 +1583,16 @@ the format string. See help(struct) for more on format strings. [clinic start generated code]*/ -static PyObject * -Struct_impl(PyTypeObject *type, PyObject *format) -/*[clinic end generated code: output=49468b044e334308 input=8b91868eb1df0e28]*/ +static int +Struct___init___impl(PyStructObject *self, PyObject *format) +/*[clinic end generated code: output=b8e80862444e92d0 input=192a4575a3dde802]*/ { - allocfunc alloc = PyType_GetSlot(type, Py_tp_alloc); - assert(alloc != NULL); - PyStructObject *self = (PyStructObject *)alloc(type, 0); - - if (self == NULL) { - return NULL; - } + int ret = 0; if (PyUnicode_Check(format)) { format = PyUnicode_AsASCIIString(format); - if (format == NULL) { - Py_DECREF(self); - return NULL; - } + if (format == NULL) + return -1; } else { Py_INCREF(format); @@ -1589,24 +1600,19 @@ Struct_impl(PyTypeObject *type, PyObject *format) if (!PyBytes_Check(format)) { Py_DECREF(format); - Py_DECREF(self); PyErr_Format(PyExc_TypeError, "Struct() argument 1 must be a str or bytes object, " "not %.200s", _PyType_Name(Py_TYPE(format))); - return NULL; + return -1; } - self->s_format = format; + Py_SETREF(self->s_format, format); - if (prepare_s(self) < 0) { - Py_DECREF(self); - return NULL; - } - return (PyObject *)self; + ret = prepare_s(self); + return ret; } - static int s_clear(PyStructObject *s) { @@ -2202,8 +2208,9 @@ static PyType_Slot PyStructType_slots[] = { {Py_tp_methods, s_methods}, {Py_tp_members, s_members}, {Py_tp_getset, s_getsetlist}, - {Py_tp_new, Struct}, + {Py_tp_init, Struct___init__}, {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, s_new}, {Py_tp_free, PyObject_GC_Del}, {0, 0}, }; diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index c3cf179..b21d9ff 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -8,7 +8,7 @@ preserve #endif -PyDoc_STRVAR(Struct__doc__, +PyDoc_STRVAR(Struct___init____doc__, "Struct(format)\n" "--\n" "\n" @@ -19,13 +19,13 @@ PyDoc_STRVAR(Struct__doc__, "\n" "See help(struct) for more on format strings."); -static PyObject * -Struct_impl(PyTypeObject *type, PyObject *format); +static int +Struct___init___impl(PyStructObject *self, PyObject *format); -static PyObject * -Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs) +static int +Struct___init__(PyObject *self, PyObject *args, PyObject *kwargs) { - PyObject *return_value = NULL; + int return_value = -1; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 @@ -61,7 +61,7 @@ Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto exit; } format = fastargs[0]; - return_value = Struct_impl(type, format); + return_value = Struct___init___impl((PyStructObject *)self, format); exit: return return_value; @@ -451,4 +451,4 @@ exit: return return_value; } -/*[clinic end generated code: output=f3d6e06f80368998 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=eca7df0e75f8919d input=a9049054013a1b77]*/ |