bpo-29649: Improve struct.pack_into() boundary error messages (#424) · python/cpython@f78b119 (original) (raw)
3 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -578,6 +578,26 @@ def test__sizeof__(self): | ||
578 | 578 | self.check_sizeof('0s', 1) |
579 | 579 | self.check_sizeof('0c', 0) |
580 | 580 | |
581 | +def test_boundary_error_message(self): | |
582 | +regex = ( | |
583 | +r'pack_into requires a buffer of at least 6 ' | |
584 | +r'bytes for packing 1 bytes at offset 5 ' | |
585 | +r'\(actual buffer size is 1\)' | |
586 | + ) | |
587 | +with self.assertRaisesRegex(struct.error, regex): | |
588 | +struct.pack_into('b', bytearray(1), 5, 1) | |
589 | + | |
590 | +def test_boundary_error_message_with_negative_offset(self): | |
591 | +byte_list = bytearray(10) | |
592 | +with self.assertRaisesRegex( | |
593 | +struct.error, | |
594 | +r'no space to pack 4 bytes at offset -2'): | |
595 | +struct.pack_into('<I', byte_list, -2, 123) | |
596 | + | |
597 | +with self.assertRaisesRegex( | |
598 | +struct.error, | |
599 | +'offset -11 out of range for 10-byte buffer'): | |
600 | +struct.pack_into('<B', byte_list, -11, 123) | |
581 | 601 | |
582 | 602 | class UnpackIteratorTest(unittest.TestCase): |
583 | 603 | """ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -303,6 +303,9 @@ Extension Modules | ||
303 | 303 | Library |
304 | 304 | ------- |
305 | 305 | |
306 | +- bpo-29649: Improve struct.pack_into() exception messages for problems | |
307 | + with the buffer size and offset. Patch by Andrew Nester. | |
308 | + | |
306 | 309 | - bpo-29654: Support If-Modified-Since HTTP header (browser cache). Patch |
307 | 310 | by Pierre Quentel. |
308 | 311 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1931,14 +1931,40 @@ s_pack_into(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames | ||
1931 | 1931 | } |
1932 | 1932 | |
1933 | 1933 | /* Support negative offsets. */ |
1934 | -if (offset < 0) | |
1934 | +if (offset < 0) { | |
1935 | +/* Check that negative offset is low enough to fit data */ | |
1936 | +if (offset + soself->s_size > 0) { | |
1937 | +PyErr_Format(StructError, | |
1938 | +"no space to pack %zd bytes at offset %zd", | |
1939 | +soself->s_size, | |
1940 | +offset); | |
1941 | +PyBuffer_Release(&buffer); | |
1942 | +return NULL; | |
1943 | + } | |
1944 | + | |
1945 | +/* Check that negative offset is not crossing buffer boundary */ | |
1946 | +if (offset + buffer.len < 0) { | |
1947 | +PyErr_Format(StructError, | |
1948 | +"offset %zd out of range for %zd-byte buffer", | |
1949 | +offset, | |
1950 | +buffer.len); | |
1951 | +PyBuffer_Release(&buffer); | |
1952 | +return NULL; | |
1953 | + } | |
1954 | + | |
1935 | 1955 | offset += buffer.len; |
1956 | + } | |
1936 | 1957 | |
1937 | 1958 | /* Check boundaries */ |
1938 | -if (offset < 0 | | |
1959 | +if ((buffer.len - offset) < soself->s_size) { | |
1939 | 1960 | PyErr_Format(StructError, |
1940 | -"pack_into requires a buffer of at least %zd bytes", | |
1941 | -soself->s_size); | |
1961 | +"pack_into requires a buffer of at least %zd bytes for " | |
1962 | +"packing %zd bytes at offset %zd " | |
1963 | +"(actual buffer size is %zd)", | |
1964 | +soself->s_size + offset, | |
1965 | +soself->s_size, | |
1966 | +offset, | |
1967 | +buffer.len); | |
1942 | 1968 | PyBuffer_Release(&buffer); |
1943 | 1969 | return NULL; |
1944 | 1970 | } |