diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index ab738770546..b0f11af1a78 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -700,6 +700,20 @@ 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. diff --git a/Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst b/Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst new file mode 100644 index 00000000000..9621e4d3f83 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst @@ -0,0 +1 @@ +Fix crash in :class:`struct.Struct` when it was not completely initialized by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya. diff --git a/Modules/_struct.c b/Modules/_struct.c index 09f52a98148..f9bac34c1e3 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1477,28 +1477,9 @@ 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] -Struct.__init__ +@classmethod +Struct.__new__ format: object @@ -1510,16 +1491,24 @@ the format string. See help(struct) for more on format strings. [clinic start generated code]*/ -static int -Struct___init___impl(PyStructObject *self, PyObject *format) -/*[clinic end generated code: output=b8e80862444e92d0 input=192a4575a3dde802]*/ +static PyObject * +Struct_impl(PyTypeObject *type, PyObject *format) +/*[clinic end generated code: output=49468b044e334308 input=8b91868eb1df0e28]*/ { - int ret = 0; + allocfunc alloc = PyType_GetSlot(type, Py_tp_alloc); + assert(alloc != NULL); + PyStructObject *self = (PyStructObject *)alloc(type, 0); + + if (self == NULL) { + return NULL; + } if (PyUnicode_Check(format)) { format = PyUnicode_AsASCIIString(format); - if (format == NULL) - return -1; + if (format == NULL) { + Py_DECREF(self); + return NULL; + } } else { Py_INCREF(format); @@ -1527,19 +1516,24 @@ Struct___init___impl(PyStructObject *self, 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 -1; + return NULL; } - Py_SETREF(self->s_format, format); + self->s_format = format; - ret = prepare_s(self); - return ret; + if (prepare_s(self) < 0) { + Py_DECREF(self); + return NULL; + } + return (PyObject *)self; } + static int s_clear(PyStructObject *s) { @@ -2144,9 +2138,8 @@ static PyType_Slot PyStructType_slots[] = { {Py_tp_methods, s_methods}, {Py_tp_members, s_members}, {Py_tp_getset, s_getsetlist}, - {Py_tp_init, Struct___init__}, + {Py_tp_new, Struct}, {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 b21d9ff2924..c3cf179ed4c 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -8,7 +8,7 @@ preserve #endif -PyDoc_STRVAR(Struct___init____doc__, +PyDoc_STRVAR(Struct__doc__, "Struct(format)\n" "--\n" "\n" @@ -19,13 +19,13 @@ PyDoc_STRVAR(Struct___init____doc__, "\n" "See help(struct) for more on format strings."); -static int -Struct___init___impl(PyStructObject *self, PyObject *format); +static PyObject * +Struct_impl(PyTypeObject *type, PyObject *format); -static int -Struct___init__(PyObject *self, PyObject *args, PyObject *kwargs) +static PyObject * +Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - int return_value = -1; + PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 @@ -61,7 +61,7 @@ Struct___init__(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } format = fastargs[0]; - return_value = Struct___init___impl((PyStructObject *)self, format); + return_value = Struct_impl(type, format); exit: return return_value; @@ -451,4 +451,4 @@ exit: return return_value; } -/*[clinic end generated code: output=eca7df0e75f8919d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f3d6e06f80368998 input=a9049054013a1b77]*/