Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Lib/test/test_struct.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -816,6 +816,18 @@ def test_endian_table_init_subinterpreters(self):
results = executor.map(exec, [code] * 5)
self.assertListEqual(list(results), [None] * 5)

def test_operations_on_half_initialized_Struct(self):
S = struct.Struct.__new__(struct.Struct)

spam = array.array('b', b' ')
self.assertRaises(RuntimeError, S.iter_unpack, spam)
self.assertRaises(RuntimeError, S.pack, 1)
self.assertRaises(RuntimeError, S.pack_into, spam, 1)
self.assertRaises(RuntimeError, S.unpack, spam)
self.assertRaises(RuntimeError, S.unpack_from, spam)
self.assertRaises(RuntimeError, getattr, S, 'format')
self.assertEqual(S.size, -1)


class UnpackIteratorTest(unittest.TestCase):
"""
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
Raise :exc:`RuntimeError`'s when user attempts to call methods on
half-initialized :class:`~struct.Struct` objects, For example, created by
``Struct.__new__(Struct)``. Patch by Sergey B Kirpichev.
24 changes: 16 additions & 8 deletions Modules/_struct.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -1698,8 +1698,6 @@ prepare_s(PyStructObject *self)
return -1;
}

self->s_size = size;
self->s_len = len;
codes = PyMem_Malloc((ncodes + 1) * sizeof(formatcode));
if (codes == NULL) {
PyErr_NoMemory();
Expand All@@ -1709,6 +1707,8 @@ prepare_s(PyStructObject *self)
if (self->s_codes != NULL)
PyMem_Free(self->s_codes);
self->s_codes = codes;
self->s_size = size;
self->s_len = len;

s = fmt;
size = 0;
Expand DownExpand Up@@ -1897,6 +1897,14 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom,
return NULL;
}

#define ENSURE_STRUCT_IS_READY(self) \
do { \
if (!(self)->s_codes) { \
PyErr_SetString(PyExc_RuntimeError, \
"Struct object is not initialized"); \
return NULL; \
} \
} while (0);

/*[clinic input]
Struct.unpack
Expand All@@ -1917,7 +1925,7 @@ Struct_unpack_impl(PyStructObject *self, Py_buffer *buffer)
/*[clinic end generated code: output=873a24faf02e848a input=3113f8e7038b2f6c]*/
{
_structmodulestate *state = get_struct_state_structinst(self);
assert(self->s_codes != NULL);
ENSURE_STRUCT_IS_READY(self);
if (buffer->len != self->s_size) {
PyErr_Format(state->StructError,
"unpack requires a buffer of %zd bytes",
Expand DownExpand Up@@ -1949,7 +1957,7 @@ Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer,
/*[clinic end generated code: output=57fac875e0977316 input=cafd4851d473c894]*/
{
_structmodulestate *state = get_struct_state_structinst(self);
assert(self->s_codes != NULL);
ENSURE_STRUCT_IS_READY(self);

if (offset < 0) {
if (offset + self->s_size > 0) {
Expand DownExpand Up@@ -2101,8 +2109,7 @@ Struct_iter_unpack_impl(PyStructObject *self, PyObject *buffer)
{
_structmodulestate *state = get_struct_state_structinst(self);
unpackiterobject *iter;

assert(self->s_codes != NULL);
ENSURE_STRUCT_IS_READY(self);

if (self->s_size == 0) {
PyErr_Format(state->StructError,
Expand DownExpand Up@@ -2242,8 +2249,8 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs)

/* Validate arguments. */
soself = PyStructObject_CAST(self);
ENSURE_STRUCT_IS_READY(soself);
assert(PyStruct_Check(self, state));
assert(soself->s_codes != NULL);
if (nargs != soself->s_len)
{
PyErr_Format(state->StructError,
Expand DownExpand Up@@ -2285,8 +2292,8 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs)

/* Validate arguments. +1 is for the first arg as buffer. */
soself = PyStructObject_CAST(self);
ENSURE_STRUCT_IS_READY(soself);
assert(PyStruct_Check(self, state));
assert(soself->s_codes != NULL);
if (nargs != (soself->s_len + 2))
{
if (nargs == 0) {
Expand DownExpand Up@@ -2373,6 +2380,7 @@ static PyObject *
s_get_format(PyObject *op, void *Py_UNUSED(closure))
{
PyStructObject *self = PyStructObject_CAST(op);
ENSURE_STRUCT_IS_READY(self);
return PyUnicode_FromStringAndSize(PyBytes_AS_STRING(self->s_format),
PyBytes_GET_SIZE(self->s_format));
}
Expand Down
Loading