Skip to content

Commit c8c0afc

Browse files
GH-78724: Initialize struct.Struct in __new__ (GH-94532)
Closes #75960 Closes #78724
1 parent f5f047a commit c8c0afc

File tree

4 files changed

+49
-41
lines changed

4 files changed

+49
-41
lines changed

Lib/test/test_struct.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,20 @@ def test__struct_types_immutable(self):
700700
with self.assertRaises(TypeError):
701701
cls.x = 1
702702

703+
@support.cpython_only
704+
def test__struct_Struct__new__initialized(self):
705+
# See https://github.com/python/cpython/issues/78724
706+
707+
s = struct.Struct.__new__(struct.Struct, "b")
708+
s.unpack_from(b"abcd")
709+
710+
@support.cpython_only
711+
def test__struct_Struct_subclassing(self):
712+
class Bob(struct.Struct):
713+
pass
714+
715+
s = Bob("b")
716+
s.unpack_from(b"abcd")
703717

704718
def test_issue35714(self):
705719
# Embedded null characters should not be allowed in format strings.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix crash in :class:`struct.Struct` when it was not completely initialized by initializing it in :meth:`~object.__new__``. Patch by Kumar Aditya.

Modules/_struct.c

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,28 +1477,9 @@ prepare_s(PyStructObject *self)
14771477
return -1;
14781478
}
14791479

1480-
static PyObject *
1481-
s_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1482-
{
1483-
PyObject *self;
1484-
1485-
assert(type != NULL);
1486-
allocfunc alloc_func = PyType_GetSlot(type, Py_tp_alloc);
1487-
assert(alloc_func != NULL);
1488-
1489-
self = alloc_func(type, 0);
1490-
if (self != NULL) {
1491-
PyStructObject *s = (PyStructObject*)self;
1492-
s->s_format = Py_NewRef(Py_None);
1493-
s->s_codes = NULL;
1494-
s->s_size = -1;
1495-
s->s_len = -1;
1496-
}
1497-
return self;
1498-
}
1499-
15001480
/*[clinic input]
1501-
Struct.__init__
1481+
@classmethod
1482+
Struct.__new__
15021483
15031484
format: object
15041485
@@ -1510,36 +1491,49 @@ the format string.
15101491
See help(struct) for more on format strings.
15111492
[clinic start generated code]*/
15121493

1513-
static int
1514-
Struct___init___impl(PyStructObject *self, PyObject *format)
1515-
/*[clinic end generated code: output=b8e80862444e92d0 input=192a4575a3dde802]*/
1494+
static PyObject *
1495+
Struct_impl(PyTypeObject *type, PyObject *format)
1496+
/*[clinic end generated code: output=49468b044e334308 input=8b91868eb1df0e28]*/
15161497
{
1517-
int ret = 0;
1498+
allocfunc alloc = PyType_GetSlot(type, Py_tp_alloc);
1499+
assert(alloc != NULL);
1500+
PyStructObject *self = (PyStructObject *)alloc(type, 0);
1501+
1502+
if (self == NULL) {
1503+
return NULL;
1504+
}
15181505

15191506
if (PyUnicode_Check(format)) {
15201507
format = PyUnicode_AsASCIIString(format);
1521-
if (format == NULL)
1522-
return -1;
1508+
if (format == NULL) {
1509+
Py_DECREF(self);
1510+
return NULL;
1511+
}
15231512
}
15241513
else {
15251514
Py_INCREF(format);
15261515
}
15271516

15281517
if (!PyBytes_Check(format)) {
15291518
Py_DECREF(format);
1519+
Py_DECREF(self);
15301520
PyErr_Format(PyExc_TypeError,
15311521
"Struct() argument 1 must be a str or bytes object, "
15321522
"not %.200s",
15331523
_PyType_Name(Py_TYPE(format)));
1534-
return -1;
1524+
return NULL;
15351525
}
15361526

1537-
Py_SETREF(self->s_format, format);
1527+
self->s_format = format;
15381528

1539-
ret = prepare_s(self);
1540-
return ret;
1529+
if (prepare_s(self) < 0) {
1530+
Py_DECREF(self);
1531+
return NULL;
1532+
}
1533+
return (PyObject *)self;
15411534
}
15421535

1536+
15431537
static int
15441538
s_clear(PyStructObject *s)
15451539
{
@@ -2144,9 +2138,8 @@ static PyType_Slot PyStructType_slots[] = {
21442138
{Py_tp_methods, s_methods},
21452139
{Py_tp_members, s_members},
21462140
{Py_tp_getset, s_getsetlist},
2147-
{Py_tp_init, Struct___init__},
2141+
{Py_tp_new, Struct},
21482142
{Py_tp_alloc, PyType_GenericAlloc},
2149-
{Py_tp_new, s_new},
21502143
{Py_tp_free, PyObject_GC_Del},
21512144
{0, 0},
21522145
};

Modules/clinic/_struct.c.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)