-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-29649: struct.pack_into check boundary error message didn't respect offset #424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@andrewnester, thanks for your PR! By analyzing the history of the files in this pull request, we identified @Haypo, @mdickinson, @Yhg1s, @serhiy-storchaka and @benjaminp to be potential reviewers. |
Lib/test/test_struct.py
Outdated
@@ -578,6 +578,14 @@ def test__sizeof__(self): | |||
self.check_sizeof('0s', 1) | |||
self.check_sizeof('0c', 0) | |||
|
|||
def test_boundary_error_message(self): | |||
import ctypes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest moving this import module level and use the following pattern:
try:
import ctypes
except ImportError:
ctypes = None
then add
@unittest.skipUnless(ctypes, 'requires ctypes')
def test_boundary_error_message(self):
...
Lib/test/test_struct.py
Outdated
byte_list = ctypes.create_string_buffer(1) | ||
try: | ||
struct.pack_into('b', byte_list, 5, 1) | ||
except struct.error as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using assertRaises
would be better:
with self.assertRaises(struct.error) as cm:
struct.pack_into('b', byte_list, 5, 1)
self.assertEqual(str(cm.exception), '...')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or assertRaisesRegex()
if we want to be more lenient to error message.
Misc/NEWS
Outdated
@@ -9,6 +9,7 @@ What's New in Python 3.7.0 alpha 1? | |||
|
|||
Core and Builtins | |||
----------------- | |||
- bpo-29649: struct.pack_into check boundary error message didn't respect offset. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be moved to "Library" section. And please add an empty line after the section header.
Lib/test/test_struct.py
Outdated
@@ -578,6 +578,14 @@ def test__sizeof__(self): | |||
self.check_sizeof('0s', 1) | |||
self.check_sizeof('0c', 0) | |||
|
|||
def test_boundary_error_message(self): | |||
import ctypes | |||
byte_list = ctypes.create_string_buffer(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using ctypes
looks unnecessary here. Why not use bytearray
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serhiy-storchaka absolutely agree, thanks!
Lib/test/test_struct.py
Outdated
byte_list = ctypes.create_string_buffer(1) | ||
try: | ||
struct.pack_into('b', byte_list, 5, 1) | ||
except struct.error as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or assertRaisesRegex()
if we want to be more lenient to error message.
Lib/test/test_struct.py
Outdated
def test_boundary_error_message(self): | ||
byte_list = bytearray(1) | ||
with self.assertRaisesRegex(struct.error, | ||
'pack_into requires a buffer of at least 6 bytes for packing 1 bytes at offset 5'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too long line.
Misc/NEWS
Outdated
@@ -261,6 +261,7 @@ Library | |||
|
|||
- bpo-29623: Allow use of path-like object as a single argument in | |||
ConfigParser.read(). Patch by David Ellis. | |||
- bpo-29649: struct.pack_into check boundary error message didn't respect offset. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entry should be added at the start of corresponding section. Separate it with empty lines from other text.
Add ()
after struct.pack_into
. Add "Patch by ".
Modules/_struct.c
Outdated
@@ -1937,8 +1937,8 @@ s_pack_into(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames | |||
/* Check boundaries */ | |||
if (offset < 0 || (buffer.len - offset) < soself->s_size) { | |||
PyErr_Format(StructError, | |||
"pack_into requires a buffer of at least %zd bytes", | |||
soself->s_size); | |||
"pack_into requires a buffer of at least %zd bytes for packing %zd bytes at offset %zd)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too long lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also address my comment on the tracker.
Misc/NEWS
Outdated
@@ -259,6 +259,9 @@ Extension Modules | |||
Library | |||
------- | |||
|
|||
- bpo-29649: struct.pack_into() check boundary error message | |||
didn't respect offset. Patch by Andrew Nester. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use two spaces after sentence ending period.
Thanks @serhiy-storchaka ! I've just added changes you requested + new error messages based on your comment from tracker. Thanks a lot! |
Modules/_struct.c
Outdated
@@ -1930,15 +1930,40 @@ s_pack_into(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames | |||
return NULL; | |||
} | |||
|
|||
/* Check that negative offset is low enough to fit data */ | |||
if (offset < 0 && offset + soself->s_size > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think three following if
's can be merged into one if (offset < 0)
. This will speed up common case of non-negative offset
.
Modules/_struct.c
Outdated
/* Check that negative offset is low enough to fit data */ | ||
if (offset < 0 && offset + soself->s_size > 0) { | ||
PyErr_Format(StructError, | ||
"pack_into requires negative offset not higher than %zd " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just repeats the same number two times (but with different signs). It would be more helpful to output an actual value of offset
.
Modules/_struct.c
Outdated
soself->s_size); | ||
"pack_into requires a buffer of at least %zd bytes for " | ||
"packing %zd bytes at offset %zd", | ||
soself->s_size + (offset > 0 ? offset : 0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be more helpful to output an actual size of the buffer rather of soself->s_size + offset
. The user can add two reported numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serhiy-storchaka I would like to leave required size indicated explicitly but will add actual buffer size to this error message. Thanks!
thanks @serhiy-storchaka for review, I just made couple of additional changes you requested. |
@serhiy-storchaka @berkerpeksag any updates on this? |
"not higher/lower than some negative value" doesn't look pretty clear. I afraid it can cause confusion. I prefer to output the offset and the size of the buffer or data. Something like
Maybe other developers can suggest better wording. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewnester’s current proposals are
1: pack_into requires a buffer of at least R bytes for packing P bytes at offset O (actual buffer size is B)
2: pack_into requires negative offset not higher than H (actual offset is O)
3: pack_into requires negative offset not lower than L (actual offset is O)
I agree the negative offset ones are awkward. My suggestions:
2: No space to pack 11 bytes at offset −10
3: Offset −11 out of range for 10-byte buffer
Lib/test/test_struct.py
Outdated
struct.error, | ||
'pack_into requires a buffer of at least 6 ' | ||
'bytes for packing 1 bytes at offset 5 ' | ||
'\(actual buffer size is 1\)'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be good to use a raw string here: r'\(. . .\)'
thanks @vadmium @serhiy-storchaka |
Lib/test/test_struct.py
Outdated
struct.error, | ||
r'pack_into requires a buffer of at least 6 ' | ||
'bytes for packing 1 bytes at offset 5 ' | ||
'\(actual buffer size is 1\)'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I am wrong (I haven’t caught up with Python after the Git Hub changeover), but I think you need to make the final part of the string a raw string:
>>> (r'pack_into requires a buffer of at least 6 '
... 'bytes for packing 1 bytes at offset 5 '
... '\(actual buffer size is 1\)')
<stdin>:3: DeprecationWarning: invalid escape sequence \(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vadmium Thanks! you're right, I updated my PR.
Lib/test/test_struct.py
Outdated
@@ -578,6 +578,26 @@ def test__sizeof__(self): | |||
self.check_sizeof('0s', 1) | |||
self.check_sizeof('0c', 0) | |||
|
|||
def test_boundary_error_message(self): | |||
byte_list = bytearray(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need byte_list
? Can't we just pass bytearray(1)
to pack_into()
?
Lib/test/test_struct.py
Outdated
byte_list = bytearray(1) | ||
with self.assertRaisesRegex( | ||
struct.error, | ||
'pack_into requires a buffer of at least 6 ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a style nit, but I find this style is a bit ugly. I prefer something like this:
regex = (
r'multi'
r'line'
r'regex'
)
with self.assertRaisesRegex(struct.error, regex):
...
Modules/_struct.c
Outdated
/* Check that negative offset is low enough to fit data */ | ||
if (offset + soself->s_size > 0) { | ||
PyErr_Format(StructError, | ||
"No space to pack %zd bytes at offset %zd", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I admit that we are pretty inconsistent with the styles of our exception messages, but I think these two should start with lowercase letters.
Misc/NEWS
Outdated
@@ -322,7 +325,7 @@ Library | |||
Now using them emits a deprecation warning. | |||
|
|||
- bpo-27863: Fixed multiple crashes in ElementTree caused by race conditions | |||
and wrong types. | |||
and wrong types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an unrelated change to me.
Misc/NEWS
Outdated
@@ -303,6 +303,9 @@ Extension Modules | |||
Library | |||
------- | |||
|
|||
- bpo-29649: struct.pack_into() check boundary error message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps something like "Exception message of struct.pack_into() now respects [...]" might be better. It's 4am here so perhaps @vadmium can come up with a better wording :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s 1 p.m. here! Maybe something like “Improve ‘struct.pack_into’ exception messages for problems with the buffer size and offset”.
@berkerpeksag @vadmium thanks for the review, seems reasonable. All changes done. Could you please review it again? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! I will let Serhiy do the merging since he knows this part of CPython better than myself.
Bumps [celery](https://github.com/celery/celery) from 5.0.4 to 5.0.5. - [Release notes](https://github.com/celery/celery/releases) - [Changelog](https://github.com/celery/celery/blob/master/Changelog.rst) - [Commits](celery/celery@v5.0.4...v5.0.5) Signed-off-by: dependabot-preview[bot] <support@dependabot.com> Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Fix for https://bugs.python.org/issue29649