From a38f9140b5bd7150bf617141e3954e9e55e3d158 Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Sun, 14 Jul 2019 16:33:34 -0600 Subject: [PATCH] bpo-34543: Fix SystemErrors and segfaults with uninitialized Structs --- Lib/test/test_struct.py | 11 ++++++++++ .../2019-07-14-16-32-15.bpo-34543.2Sguv-.rst | 2 ++ Modules/_struct.c | 21 ++++++++++++------- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-07-14-16-32-15.bpo-34543.2Sguv-.rst diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 454082e66d3f86..3210a038eae0ef 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -652,6 +652,17 @@ def test_format_attr(self): s2 = struct.Struct(s.format.encode()) self.assertEqual(s2.format, s.format) + def test_uninitialized_struct(self): + s = struct.Struct.__new__(struct.Struct) + with self.assertRaises(ValueError): + s.format + with self.assertRaises(ValueError): + s.size + for meth in s.iter_unpack, s.pack, s.unpack, s.unpack_from: + self.assertRaises(ValueError, meth, b'0') + self.assertRaises(ValueError, s.pack_into, bytearray(1), 0, b'0') + self.assertRaises(ValueError, s.__sizeof__) + class UnpackIteratorTest(unittest.TestCase): """ diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-07-14-16-32-15.bpo-34543.2Sguv-.rst b/Misc/NEWS.d/next/Core and Builtins/2019-07-14-16-32-15.bpo-34543.2Sguv-.rst new file mode 100644 index 00000000000000..dfd73885706816 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-07-14-16-32-15.bpo-34543.2Sguv-.rst @@ -0,0 +1,2 @@ +Fix :exc:`SystemError`\ s and segfaults with uninitialized +:class:`struct.Struct`\ s. diff --git a/Modules/_struct.c b/Modules/_struct.c index d1c635a316003f..656e1557088a6e 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -270,6 +270,12 @@ get_size_t(PyObject *v, size_t *p) #define RANGE_ERROR(x, f, flag, mask) return _range_error(f, flag) +#define CHECK_INITIALIZED(self) \ + if (self->s_codes == NULL) { \ + PyErr_SetString(PyExc_ValueError, \ + "Struct.__init__() wasn't called"); \ + return NULL; \ + } /* Floating point helpers */ @@ -1533,7 +1539,7 @@ static PyObject * Struct_unpack_impl(PyStructObject *self, Py_buffer *buffer) /*[clinic end generated code: output=873a24faf02e848a input=3113f8e7038b2f6c]*/ { - assert(self->s_codes != NULL); + CHECK_INITIALIZED(self); if (buffer->len != self->s_size) { PyErr_Format(StructError, "unpack requires a buffer of %zd bytes", @@ -1564,8 +1570,7 @@ Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer, Py_ssize_t offset) /*[clinic end generated code: output=57fac875e0977316 input=cafd4851d473c894]*/ { - assert(self->s_codes != NULL); - + CHECK_INITIALIZED(self); if (offset < 0) { if (offset + self->s_size > 0) { PyErr_Format(StructError, @@ -1714,8 +1719,7 @@ Struct_iter_unpack(PyStructObject *self, PyObject *buffer) { unpackiterobject *iter; - assert(self->s_codes != NULL); - + CHECK_INITIALIZED(self); if (self->s_size == 0) { PyErr_Format(StructError, "cannot iteratively unpack with a struct of length 0"); @@ -1851,7 +1855,7 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) /* Validate arguments. */ soself = (PyStructObject *)self; assert(PyStruct_Check(self)); - assert(soself->s_codes != NULL); + CHECK_INITIALIZED(soself); if (nargs != soself->s_len) { PyErr_Format(StructError, @@ -1891,7 +1895,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) /* Validate arguments. +1 is for the first arg as buffer. */ soself = (PyStructObject *)self; assert(PyStruct_Check(self)); - assert(soself->s_codes != NULL); + CHECK_INITIALIZED(soself); if (nargs != (soself->s_len + 2)) { if (nargs == 0) { @@ -1977,6 +1981,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) static PyObject * s_get_format(PyStructObject *self, void *unused) { + CHECK_INITIALIZED(self); return PyUnicode_FromStringAndSize(PyBytes_AS_STRING(self->s_format), PyBytes_GET_SIZE(self->s_format)); } @@ -1984,6 +1989,7 @@ s_get_format(PyStructObject *self, void *unused) static PyObject * s_get_size(PyStructObject *self, void *unused) { + CHECK_INITIALIZED(self); return PyLong_FromSsize_t(self->s_size); } @@ -1995,6 +2001,7 @@ s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; formatcode *code; + CHECK_INITIALIZED(self); size = _PyObject_SIZE(Py_TYPE(self)) + sizeof(formatcode); for (code = self->s_codes; code->fmtdef != NULL; code++)