From 45836250b8196025bac18ed791b670b49b083d2a Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 3 Jul 2022 14:13:32 +0000 Subject: [PATCH 1/7] initialize Struct in __new__ --- Lib/test/test_struct.py | 6 +++++ Modules/_struct.c | 54 +++++++++++++++----------------------- Modules/clinic/_struct.c.h | 16 +++++------ 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index ab738770546c0b..e5f930ead3f303 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -700,6 +700,12 @@ def test__struct_types_immutable(self): 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") def test_issue35714(self): # Embedded null characters should not be allowed in format strings. diff --git a/Modules/_struct.c b/Modules/_struct.c index 9d66568a282662..3587fa160b1322 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1433,28 +1433,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 @@ -1466,16 +1447,21 @@ 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; + PyStructObject *self = (PyStructObject *)type->tp_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); @@ -1483,17 +1469,20 @@ 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) { + return NULL; + } + return (PyObject *)self; } static int @@ -2100,9 +2089,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 39b8ccb5ca49b8..d4c2618961d980 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -2,7 +2,7 @@ preserve [clinic start generated code]*/ -PyDoc_STRVAR(Struct___init____doc__, +PyDoc_STRVAR(Struct__doc__, "Struct(format)\n" "--\n" "\n" @@ -13,13 +13,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; static const char * const _keywords[] = {"format", NULL}; static _PyArg_Parser _parser = {NULL, _keywords, "Struct", 0}; PyObject *argsbuf[1]; @@ -32,7 +32,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; @@ -376,4 +376,4 @@ iter_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -/*[clinic end generated code: output=2065c9b007be631c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f2fb11258c927c88 input=a9049054013a1b77]*/ From a02627334fd723c55692b222e6e3a1fc4a6cf5f1 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 3 Jul 2022 16:17:26 +0000 Subject: [PATCH 2/7] fix ref leaks --- Modules/_struct.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_struct.c b/Modules/_struct.c index 3587fa160b1322..144df7c52108ce 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1480,6 +1480,7 @@ Struct_impl(PyTypeObject *type, PyObject *format) self->s_format = format; if (prepare_s(self) < 0) { + Py_DECREF(self); return NULL; } return (PyObject *)self; From f23671cdd36f4b7da1e94dc1c472eb650540802c Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 3 Jul 2022 16:19:19 +0000 Subject: [PATCH 3/7] use PyType_GetSlot --- Modules/_struct.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index 144df7c52108ce..4d3a753f177bcb 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1451,7 +1451,10 @@ static PyObject * Struct_impl(PyTypeObject *type, PyObject *format) /*[clinic end generated code: output=49468b044e334308 input=8b91868eb1df0e28]*/ { - PyStructObject *self = (PyStructObject *)type->tp_alloc(type, 0); + allocfunc alloc = PyType_GetSlot(type, Py_tp_alloc); + assert(alloc != NULL); + PyStructObject *self = (PyStructObject *)alloc(type, 0); + if (self == NULL) { return NULL; } From d44201f2ed4890739b797449d3fb9d6796ebb76a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 3 Jul 2022 16:26:36 +0000 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst 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 00000000000000..0bb0bf86c08442 --- /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 uninitialized by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya. From a74cdbb9b51c4b5106e0d46f6b7ec216e5979474 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 3 Jul 2022 16:28:31 +0000 Subject: [PATCH 5/7] fix typo --- .../next/Library/2022-07-03-16-26-35.gh-issue-78724.XNiJzf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 0bb0bf86c08442..9621e4d3f83daf 100644 --- 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 @@ -1 +1 @@ -Fix crash in :class:`struct.Struct` when it was not completely uninitialized by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya. +Fix crash in :class:`struct.Struct` when it was not completely initialized by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya. From 1306df32a5d60ea2531367f796f621f95ee92f5b Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Wed, 6 Jul 2022 09:36:57 +0000 Subject: [PATCH 6/7] backwards compatibility --- Lib/test/test_struct.py | 9 +++++++++ Modules/_struct.c | 39 ++++++++++++++++++++++++++++++++++++++ Modules/clinic/_struct.c.h | 27 +++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index e5f930ead3f303..552583bab7bca6 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -707,6 +707,15 @@ def test__struct_Struct__new__initialized(self): 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): + def __init__(self, format): + super().__init__(format) + + s = Bob("b") + s.unpack_from(b"abcd") + def test_issue35714(self): # Embedded null characters should not be allowed in format strings. for s in '\0', '2\0i', b'\0': diff --git a/Modules/_struct.c b/Modules/_struct.c index 4d3a753f177bcb..be1b7d12d2b163 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1489,6 +1489,44 @@ Struct_impl(PyTypeObject *type, PyObject *format) return (PyObject *)self; } +/*[clinic input] +Struct.__init__ + + format: object + +[clinic start generated code]*/ + +static int +Struct___init___impl(PyStructObject *self, PyObject *format) +/*[clinic end generated code: output=b8e80862444e92d0 input=6c10faf9b8d53954]*/ +{ + if (PyUnicode_Check(format)) { + format = PyUnicode_AsASCIIString(format); + if (format == NULL) { + return -1; + } + } + else { + Py_INCREF(format); + } + + if (!PyBytes_Check(format)) { + Py_DECREF(format); + PyErr_Format(PyExc_TypeError, + "Struct() argument 1 must be a str or bytes object, " + "not %.200s", + _PyType_Name(Py_TYPE(format))); + return -1; + } + + Py_SETREF(self->s_format, format); + + if (prepare_s(self) < 0) { + return -1; + } + return 0; +} + static int s_clear(PyStructObject *s) { @@ -2094,6 +2132,7 @@ static PyType_Slot PyStructType_slots[] = { {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_free, PyObject_GC_Del}, {0, 0}, diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index d4c2618961d980..3395d996df1af3 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -38,6 +38,31 @@ Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs) return return_value; } +static int +Struct___init___impl(PyStructObject *self, PyObject *format); + +static int +Struct___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"format", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "Struct", 0}; + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *format; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + format = fastargs[0]; + return_value = Struct___init___impl((PyStructObject *)self, format); + +exit: + return return_value; +} + PyDoc_STRVAR(Struct_unpack__doc__, "unpack($self, buffer, /)\n" "--\n" @@ -376,4 +401,4 @@ iter_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -/*[clinic end generated code: output=f2fb11258c927c88 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=edd5562fce3cef84 input=a9049054013a1b77]*/ From d7ce7d8d7bb399c4468a8e5f36d569a25dd263a6 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sat, 17 Sep 2022 12:02:28 +0000 Subject: [PATCH 7/7] remove __init__ --- Lib/test/test_struct.py | 3 +-- Modules/_struct.c | 38 ----------------------------- Modules/clinic/_struct.c.h | 50 +------------------------------------- 3 files changed, 2 insertions(+), 89 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 552583bab7bca6..b0f11af1a7892e 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -710,8 +710,7 @@ def test__struct_Struct__new__initialized(self): @support.cpython_only def test__struct_Struct_subclassing(self): class Bob(struct.Struct): - def __init__(self, format): - super().__init__(format) + pass s = Bob("b") s.unpack_from(b"abcd") diff --git a/Modules/_struct.c b/Modules/_struct.c index be1b7d12d2b163..36141d0d420593 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1489,43 +1489,6 @@ Struct_impl(PyTypeObject *type, PyObject *format) return (PyObject *)self; } -/*[clinic input] -Struct.__init__ - - format: object - -[clinic start generated code]*/ - -static int -Struct___init___impl(PyStructObject *self, PyObject *format) -/*[clinic end generated code: output=b8e80862444e92d0 input=6c10faf9b8d53954]*/ -{ - if (PyUnicode_Check(format)) { - format = PyUnicode_AsASCIIString(format); - if (format == NULL) { - return -1; - } - } - else { - Py_INCREF(format); - } - - if (!PyBytes_Check(format)) { - Py_DECREF(format); - PyErr_Format(PyExc_TypeError, - "Struct() argument 1 must be a str or bytes object, " - "not %.200s", - _PyType_Name(Py_TYPE(format))); - return -1; - } - - Py_SETREF(self->s_format, format); - - if (prepare_s(self) < 0) { - return -1; - } - return 0; -} static int s_clear(PyStructObject *s) @@ -2132,7 +2095,6 @@ static PyType_Slot PyStructType_slots[] = { {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_free, PyObject_GC_Del}, {0, 0}, diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index 0d719e0fc5db8e..c3cf179ed4c040 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -67,54 +67,6 @@ Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs) return return_value; } -static int -Struct___init___impl(PyStructObject *self, PyObject *format); - -static int -Struct___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(format), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"format", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "Struct", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject * const *fastargs; - Py_ssize_t nargs = PyTuple_GET_SIZE(args); - PyObject *format; - - fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); - if (!fastargs) { - goto exit; - } - format = fastargs[0]; - return_value = Struct___init___impl((PyStructObject *)self, format); - -exit: - return return_value; -} - PyDoc_STRVAR(Struct_unpack__doc__, "unpack($self, buffer, /)\n" "--\n" @@ -499,4 +451,4 @@ iter_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -/*[clinic end generated code: output=2671fa9afbe28780 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f3d6e06f80368998 input=a9049054013a1b77]*/