gh-145743: Fix inconsistency after calling Struct.__init__() with invalid format (GH-145744)

Only set the format attribute after successful (re-)initialization.
This commit is contained in:
Serhiy Storchaka 2026-03-10 18:29:23 +02:00 committed by GitHub
parent bf4017b161
commit 3f33bf83e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 16 deletions

View file

@ -584,8 +584,24 @@ def test_Struct_reinitialization(self):
# Issue 9422: there was a memory leak when reinitializing a
# Struct instance. This test can be used to detect the leak
# when running with regrtest -L.
s = struct.Struct('i')
s.__init__('ii')
s = struct.Struct('>h')
s.__init__('>hh')
self.assertEqual(s.format, '>hh')
packed = b'\x00\x01\x00\x02'
self.assertEqual(s.pack(1, 2), packed)
self.assertEqual(s.unpack(packed), (1, 2))
with self.assertRaises(UnicodeEncodeError):
s.__init__('\udc00')
self.assertEqual(s.format, '>hh')
self.assertEqual(s.pack(1, 2), packed)
self.assertEqual(s.unpack(packed), (1, 2))
with self.assertRaises(struct.error):
s.__init__('$')
self.assertEqual(s.format, '>hh')
self.assertEqual(s.pack(1, 2), packed)
self.assertEqual(s.unpack(packed), (1, 2))
def check_sizeof(self, format_str, number_of_codes):
# The size of 'PyStructObject'

View file

@ -1620,11 +1620,11 @@ align(Py_ssize_t size, char c, const formatdef *e)
/* calculate the size of a format string */
static int
prepare_s(PyStructObject *self)
prepare_s(PyStructObject *self, PyObject *format)
{
const formatdef *f;
const formatdef *e;
formatcode *codes;
formatcode *codes, *codes0;
const char *s;
const char *fmt;
@ -1634,8 +1634,8 @@ prepare_s(PyStructObject *self)
_structmodulestate *state = get_struct_state_structinst(self);
fmt = PyBytes_AS_STRING(self->s_format);
if (strlen(fmt) != (size_t)PyBytes_GET_SIZE(self->s_format)) {
fmt = PyBytes_AS_STRING(format);
if (strlen(fmt) != (size_t)PyBytes_GET_SIZE(format)) {
PyErr_SetString(state->StructError,
"embedded null character");
return -1;
@ -1711,13 +1711,7 @@ prepare_s(PyStructObject *self)
PyErr_NoMemory();
return -1;
}
/* Free any s_codes value left over from a previous initialization. */
if (self->s_codes != NULL)
PyMem_Free(self->s_codes);
self->s_codes = codes;
self->s_size = size;
self->s_len = len;
codes0 = codes;
s = fmt;
size = 0;
while ((c = *s++) != '\0') {
@ -1757,6 +1751,14 @@ prepare_s(PyStructObject *self)
codes->size = 0;
codes->repeat = 0;
/* Free any s_codes value left over from a previous initialization. */
if (self->s_codes != NULL)
PyMem_Free(self->s_codes);
self->s_codes = codes0;
self->s_size = size;
self->s_len = len;
Py_XSETREF(self->s_format, Py_NewRef(format));
return 0;
overflow:
@ -1820,9 +1822,8 @@ Struct___init___impl(PyStructObject *self, PyObject *format)
return -1;
}
Py_SETREF(self->s_format, format);
ret = prepare_s(self);
ret = prepare_s(self, format);
Py_DECREF(format);
return ret;
}