From c10b288f345aaef66d2c844924b9a576f9ea4f8b Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Sun, 11 Mar 2018 02:58:52 +0800 Subject: [PATCH] bpo-30249: Improve struct.unpack_from() error messages (GH-6059) --- Doc/library/struct.rst | 6 ++-- Lib/test/test_struct.py | 34 +++++++++++++++--- .../2018-03-11-00-20-26.bpo-30249.KSkgLB.rst | 2 ++ Modules/_struct.c | 35 +++++++++++++++---- Modules/clinic/_struct.c.h | 5 +-- 5 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-03-11-00-20-26.bpo-30249.KSkgLB.rst diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 2d0866c7e09..d6a3cb721e8 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -74,8 +74,8 @@ The module defines the following exception and functions: Unpack from *buffer* starting at position *offset*, according to the format 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 - the size required by the format, as reflected by :func:`calcsize`. + item. The buffer's size in bytes, starting at position *offset*, must be at + least the size required by the format, as reflected by :func:`calcsize`. .. function:: iter_unpack(format, buffer) @@ -428,7 +428,7 @@ The :mod:`struct` module also defines the following type: .. method:: unpack_from(buffer, offset=0) 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`. diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 8fd56c91cb7..454082e66d3 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -579,14 +579,22 @@ class StructTest(unittest.TestCase): self.check_sizeof('0c', 0) def test_boundary_error_message(self): - regex = ( + regex1 = ( r'pack_into requires a buffer of at least 6 ' r'bytes for packing 1 bytes at offset 5 ' 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) + 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): byte_list = bytearray(10) with self.assertRaisesRegex( @@ -599,16 +607,34 @@ class StructTest(unittest.TestCase): 'offset -11 out of range for 10-byte buffer'): struct.pack_into('s_codes != NULL); - if (offset < 0) + if (offset < 0) { + if (offset + self->s_size > 0) { + PyErr_Format(StructError, + "not enough data to unpack %zd bytes at offset %zd", + 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 (offset < 0 || buffer->len - offset < self->s_size) { + } + + if ((buffer->len - offset) < self->s_size) { PyErr_Format(StructError, - "unpack_from requires a buffer of at least %zd bytes", - self->s_size); + "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 s_unpack_internal(self, (char*)buffer->buf + offset); diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index 6e43215b737..2ecadfb1de9 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -79,7 +79,8 @@ PyDoc_STRVAR(Struct_unpack_from__doc__, "\n" "Values are unpacked according to the format string Struct.format.\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" "See help(struct) for more on format strings."); @@ -302,4 +303,4 @@ exit: return return_value; } -/*[clinic end generated code: output=9119f213a951e4cc input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d79b009652ae0b89 input=a9049054013a1b77]*/