mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-30249: Improve struct.unpack_from() error messages (GH-6059)
This commit is contained in:
parent
67ee07795b
commit
c10b288f34
5 changed files with 67 additions and 15 deletions
|
@ -74,8 +74,8 @@ The module defines the following exception and functions:
|
||||||
|
|
||||||
Unpack from *buffer* starting at position *offset*, according to the format
|
Unpack from *buffer* starting at position *offset*, according to the format
|
||||||
string *format*. The result is a tuple even if it contains exactly one
|
string *format*. The result is a tuple even if it contains exactly one
|
||||||
item. The buffer's size in bytes, minus *offset*, must be at least
|
item. The buffer's size in bytes, starting at position *offset*, must be at
|
||||||
the size required by the format, as reflected by :func:`calcsize`.
|
least the size required by the format, as reflected by :func:`calcsize`.
|
||||||
|
|
||||||
|
|
||||||
.. function:: iter_unpack(format, buffer)
|
.. function:: iter_unpack(format, buffer)
|
||||||
|
@ -428,7 +428,7 @@ The :mod:`struct` module also defines the following type:
|
||||||
.. method:: unpack_from(buffer, offset=0)
|
.. method:: unpack_from(buffer, offset=0)
|
||||||
|
|
||||||
Identical to the :func:`unpack_from` function, using the compiled format.
|
Identical to the :func:`unpack_from` function, using the compiled format.
|
||||||
The buffer's size in bytes, minus *offset*, must be at least
|
The buffer's size in bytes, starting at position *offset*, must be at least
|
||||||
:attr:`size`.
|
:attr:`size`.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -579,14 +579,22 @@ class StructTest(unittest.TestCase):
|
||||||
self.check_sizeof('0c', 0)
|
self.check_sizeof('0c', 0)
|
||||||
|
|
||||||
def test_boundary_error_message(self):
|
def test_boundary_error_message(self):
|
||||||
regex = (
|
regex1 = (
|
||||||
r'pack_into requires a buffer of at least 6 '
|
r'pack_into requires a buffer of at least 6 '
|
||||||
r'bytes for packing 1 bytes at offset 5 '
|
r'bytes for packing 1 bytes at offset 5 '
|
||||||
r'\(actual buffer size is 1\)'
|
r'\(actual buffer size is 1\)'
|
||||||
)
|
)
|
||||||
with self.assertRaisesRegex(struct.error, regex):
|
with self.assertRaisesRegex(struct.error, regex1):
|
||||||
struct.pack_into('b', bytearray(1), 5, 1)
|
struct.pack_into('b', bytearray(1), 5, 1)
|
||||||
|
|
||||||
|
regex2 = (
|
||||||
|
r'unpack_from requires a buffer of at least 6 '
|
||||||
|
r'bytes for unpacking 1 bytes at offset 5 '
|
||||||
|
r'\(actual buffer size is 1\)'
|
||||||
|
)
|
||||||
|
with self.assertRaisesRegex(struct.error, regex2):
|
||||||
|
struct.unpack_from('b', bytearray(1), 5)
|
||||||
|
|
||||||
def test_boundary_error_message_with_negative_offset(self):
|
def test_boundary_error_message_with_negative_offset(self):
|
||||||
byte_list = bytearray(10)
|
byte_list = bytearray(10)
|
||||||
with self.assertRaisesRegex(
|
with self.assertRaisesRegex(
|
||||||
|
@ -599,16 +607,34 @@ class StructTest(unittest.TestCase):
|
||||||
'offset -11 out of range for 10-byte buffer'):
|
'offset -11 out of range for 10-byte buffer'):
|
||||||
struct.pack_into('<B', byte_list, -11, 123)
|
struct.pack_into('<B', byte_list, -11, 123)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
struct.error,
|
||||||
|
r'not enough data to unpack 4 bytes at offset -2'):
|
||||||
|
struct.unpack_from('<I', byte_list, -2)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
struct.error,
|
||||||
|
"offset -11 out of range for 10-byte buffer"):
|
||||||
|
struct.unpack_from('<B', byte_list, -11)
|
||||||
|
|
||||||
def test_boundary_error_message_with_large_offset(self):
|
def test_boundary_error_message_with_large_offset(self):
|
||||||
# Test overflows cause by large offset and value size (issue 30245)
|
# Test overflows cause by large offset and value size (issue 30245)
|
||||||
regex = (
|
regex1 = (
|
||||||
r'pack_into requires a buffer of at least ' + str(sys.maxsize + 4) +
|
r'pack_into requires a buffer of at least ' + str(sys.maxsize + 4) +
|
||||||
r' bytes for packing 4 bytes at offset ' + str(sys.maxsize) +
|
r' bytes for packing 4 bytes at offset ' + str(sys.maxsize) +
|
||||||
r' \(actual buffer size is 10\)'
|
r' \(actual buffer size is 10\)'
|
||||||
)
|
)
|
||||||
with self.assertRaisesRegex(struct.error, regex):
|
with self.assertRaisesRegex(struct.error, regex1):
|
||||||
struct.pack_into('<I', bytearray(10), sys.maxsize, 1)
|
struct.pack_into('<I', bytearray(10), sys.maxsize, 1)
|
||||||
|
|
||||||
|
regex2 = (
|
||||||
|
r'unpack_from requires a buffer of at least ' + str(sys.maxsize + 4) +
|
||||||
|
r' bytes for unpacking 4 bytes at offset ' + str(sys.maxsize) +
|
||||||
|
r' \(actual buffer size is 10\)'
|
||||||
|
)
|
||||||
|
with self.assertRaisesRegex(struct.error, regex2):
|
||||||
|
struct.unpack_from('<I', bytearray(10), sys.maxsize)
|
||||||
|
|
||||||
def test_issue29802(self):
|
def test_issue29802(self):
|
||||||
# When the second argument of struct.unpack() was of wrong type
|
# When the second argument of struct.unpack() was of wrong type
|
||||||
# the Struct object was decrefed twice and the reference to
|
# the Struct object was decrefed twice and the reference to
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve struct.unpack_from() exception messages for problems with the buffer
|
||||||
|
size and offset.
|
|
@ -1553,7 +1553,8 @@ Return a tuple containing unpacked values.
|
||||||
|
|
||||||
Values are unpacked according to the format string Struct.format.
|
Values are unpacked according to the format string Struct.format.
|
||||||
|
|
||||||
The buffer's size in bytes, minus offset, must be at least Struct.size.
|
The buffer's size in bytes, starting at position offset, must be
|
||||||
|
at least Struct.size.
|
||||||
|
|
||||||
See help(struct) for more on format strings.
|
See help(struct) for more on format strings.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
@ -1561,16 +1562,38 @@ See help(struct) for more on format strings.
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer,
|
Struct_unpack_from_impl(PyStructObject *self, Py_buffer *buffer,
|
||||||
Py_ssize_t offset)
|
Py_ssize_t offset)
|
||||||
/*[clinic end generated code: output=57fac875e0977316 input=97ade52422f8962f]*/
|
/*[clinic end generated code: output=57fac875e0977316 input=cafd4851d473c894]*/
|
||||||
{
|
{
|
||||||
assert(self->s_codes != NULL);
|
assert(self->s_codes != NULL);
|
||||||
|
|
||||||
if (offset < 0)
|
if (offset < 0) {
|
||||||
offset += buffer->len;
|
if (offset + self->s_size > 0) {
|
||||||
if (offset < 0 || buffer->len - offset < self->s_size) {
|
|
||||||
PyErr_Format(StructError,
|
PyErr_Format(StructError,
|
||||||
"unpack_from requires a buffer of at least %zd bytes",
|
"not enough data to unpack %zd bytes at offset %zd",
|
||||||
self->s_size);
|
self->s_size,
|
||||||
|
offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + buffer->len < 0) {
|
||||||
|
PyErr_Format(StructError,
|
||||||
|
"offset %zd out of range for %zd-byte buffer",
|
||||||
|
offset,
|
||||||
|
buffer->len);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
offset += buffer->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buffer->len - offset) < self->s_size) {
|
||||||
|
PyErr_Format(StructError,
|
||||||
|
"unpack_from requires a buffer of at least %zu bytes for "
|
||||||
|
"unpacking %zd bytes at offset %zd "
|
||||||
|
"(actual buffer size is %zd)",
|
||||||
|
(size_t)self->s_size + (size_t)offset,
|
||||||
|
self->s_size,
|
||||||
|
offset,
|
||||||
|
buffer->len);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return s_unpack_internal(self, (char*)buffer->buf + offset);
|
return s_unpack_internal(self, (char*)buffer->buf + offset);
|
||||||
|
|
|
@ -79,7 +79,8 @@ PyDoc_STRVAR(Struct_unpack_from__doc__,
|
||||||
"\n"
|
"\n"
|
||||||
"Values are unpacked according to the format string Struct.format.\n"
|
"Values are unpacked according to the format string Struct.format.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The buffer\'s size in bytes, minus offset, must be at least Struct.size.\n"
|
"The buffer\'s size in bytes, starting at position offset, must be\n"
|
||||||
|
"at least Struct.size.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"See help(struct) for more on format strings.");
|
"See help(struct) for more on format strings.");
|
||||||
|
|
||||||
|
@ -302,4 +303,4 @@ exit:
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=9119f213a951e4cc input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=d79b009652ae0b89 input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue