-
-
Notifications
You must be signed in to change notification settings - Fork 32.9k
bpo-15988: make various overflow messages more consistent and helpful #668
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
bpo-15988: make various overflow messages more consistent and helpful #668
Conversation
…i added to csv, as the inconsistent message in csv was already fixed, and so my patch isn't related to it anymore
…oryio, and optimized an if in seterror
…fix my socket tests
…Arg_* funcs in mmapmodule.c
… remove redundant code in _PyLong_AsInt
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 a great patch! Thanks Oren.
I made the first turn of reviewing. In general LGTM, but I left a number of comments. I think some changes could be extracted to separate issues. Some OverflowErrors could be avoided at all. I didn't tested all changes. I am not sure that reraising OverflowError with new error messages is appropriate in all cases. In some cases current error message looks not obviously worse.
} | ||
if (shiftby < 0) { | ||
PyErr_SetString(PyExc_ValueError, "negative shift count"); | ||
PyErr_SetString(PyExc_ValueError, "shift count can't be negative"); |
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 better to raise the same ValueError for all negative values, even if they don't fit in Py_ssize_t.
This changes the behavior so maybe it worths the separate issue (or be resolved as a part of bpo-29816).
/* PyLong_Check(b) is true, so it must be that | ||
PyLong_AsSsize_t raised an OverflowError. */ | ||
assert(PyErr_ExceptionMatches(PyExc_OverflowError)); | ||
PyErr_SetString(PyExc_OverflowError, |
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.
See bpo-29816. Right shift can be changed to never raise an OverflowError.
if (i < 0) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"can't convert negative value to unsigned int"); | ||
"can't convert negative Python int to C " |
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 ValueError is more appropriate here.
if (i < 0) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"can't convert negative value to size_t"); | ||
"can't convert negative Python int to C size_t"); |
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 ValueError is more appropriate here.
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.
if (overflow || result > INT_MAX || result < INT_MIN) { | ||
/* XXX: could be cute and give a different | ||
message for overflow == -1 */ | ||
if (overflow == 1 || result > INT_MAX) { |
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.
In common case overflow == 0 and INT_MIN <= result <= INT_MAX. Checking three false conditions in overflow || result > INT_MAX || result < INT_MIN
is faster than checking four false conditions in overflow == 1 || result > INT_MAX
and overflow == -1 || result < INT_MIN
(and comparing with zero can be faster than comparing with non-zero). It is better to keep the current check and adds more checks only for qualifying exception message.
}; | ||
|
||
if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__", | ||
if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:timedelta.__new__", |
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 change looks unrelated to this issue. After converting this module to Argument Clinic it will be outdated.
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 agree. I changed it only because I changed other similar *_new functions in Modules/_datetimemodule.c, and this :__new__
seemed like a mistake that I should correct while I am there.
(anyway, I will remove this change.)
break; | ||
case 1: | ||
if (!PyArg_ParseTuple(args,"i;n", &n)) | ||
if (!PyArg_ParseTuple(args, "i:getstr", &n)) { |
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 change looks unrelated to this issue. It will be outdated after converting the module to Argument Clinic.
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.
why is it not related to this issue?
do you mean it is more related to bpo-29833?
Anyway, should I remove this change and all other similar changes I made to format arguments of PyArg_ParseTuple in _cursesmodule.c?
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 doesn't directly related to error messages in case of integer overflow. Remove all similar changes. They will be made by bpo-20171.
if (overflow) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"The '_length_' attribute is too large"); | ||
"The '_length_' attribute does not fit in C long"); |
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.
Negative length is not valid. Raise ValueError in that case.
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.
all right. I would also add a test_bad_length
test to Lib/ctypes/test/test_arrays.py.
by the way, according to https://docs.python.org/3.7/library/ctypes.html#ctypes.Array._length_,
_length_
must be positive (ISTM that it makes sense, as an array of length 0 is useless), but currently no error is raised in case _length_ == 0
.
do you think this is OK?
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.
on second thought, this changes the behavior from raising OverflowError for small negative _length_
to raising ValueError.
should I open another sub-issue of bpo-29833 for that?
or maybe should I just raise OverflowError with a better 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.
I don't know whether the length 0 is acceptable. Yes, since changing OverflowError to ValueError changes the behavior, this worths a sub-issue.
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.
if (leaf_size == (unsigned long) -1 && PyErr_Occurred()) { | ||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"leaf_size must be between 0 and 2**32-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.
This error message and error message at line 169 should be same.
It may be worth to raise ValueError for negative leaf_size. Are there other restrictions for upper limit? Since this is specific to BLAKE2b it is worth to open a separate issue about this.
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.
so do you suggest to remove the changes in py_blake2b_new_impl
and py_blake2s_new_impl
, and patch these functions as part of the issue of replacing OverflowError with ValueError for negative values?
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 don't well known with this part of code and suggest to open a separate issue for changes in this file.
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.
|
||
@cpython_only | ||
def test_mode_t_converter(self): | ||
from _testcapi import USHRT_MAX |
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 needed only on Windows. It is worth to split the test on two parts: the general one and the Windows-specific one.
must use the next size up that is signed ('h') and manually do | ||
the overflow checking */ | ||
if (!PyArg_Parse(v, "h;array item must be integer", &x)) | ||
if (!PyArg_Parse(v, "h:array('b').__setitem__", &x)) { |
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 is enough to keep OverflowError raised in PyArg_Parse(). It should be good enough. No change is needed.
if ((unsigned long) self->code[i] != value) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"regular expression code size limit exceeded"); | ||
"regular expression code out of range"); |
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.
One option is to add Py_DECREF(self);
and return NULL;
here.
Other option is to left just break
and rewrite the condition after the loop:
if (i < n || PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_OverflowError)) {
PyErr_SetString(PyExc_OverflowError, ...);
}
if (PyErr_Occurred()) {
Py_DECREF(self);
return NULL;
}
Third option is to add a label before PyErr_SetString(PyExc_OverflowError, ...);
and jump to it from here. This looks the simplest option.
else if (x < -128) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"signed char is less than minimum"); | ||
"array item too small to convert to C char"); |
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.
Make it consistent with error messages raised by PyArg_Parse()
.
if (map_size < 0) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"memory mapped length must be postiive"); | ||
"memory mapped length must be positive"); |
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.
But check that 0 is actually accepted as the length. That there is not a bug in the condition.
|
||
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, | ||
&fileno, &map_size, | ||
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL:mmap.__new__", |
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.
At best, it would be the same message.
@orenmn, could you please merge with master and resolve conflicts? This will help further reviewing this giant PR. Some issues may be already solved, perhaps in slightly different way. |
I still have some small issues that i wish to take care of before diving into this one, but i hope to get to it sometime soon. |
This PR is currently irrelevant, as explained in https://bugs.python.org/issue15988#msg303192 |
To try and help move older pull requests forward, we are going through and backfilling 'awaiting' labels on pull requests that are lacking the label. Based on the current reviews, the best we can tell in an automated fashion is that a core developer requested changes to be made to this pull request. If/when the requested changes have been made, please leave a comment that says, |
Based on @orenmn's last message and the merge conflicts, I'm going to close this pull request. I believe @serhiy-storchaka was suggesting for this to be split into smaller pull requests that would be easier to review. If that's not the case, feel free to re-open this PR. |
according to http://bugs.python.org/issue15988:
(I ran the test module, and on my Windows 10, the same tests failed with
and without my patches. However, on my Ubuntu 16.04 VM, none of the tests
failed.)