This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2016年09月28日 10:09 by Oren Milman, last changed 2022年04月11日 14:58 by admin. This issue is now closed.
| Files | ||||
|---|---|---|---|---|
| File name | Uploaded | Description | Edit | |
| patchedCPythonTestOutput_ver1.txt | Oren Milman, 2016年09月28日 10:09 | test output of CPython with my patches (tested on my PC) - ver1 | ||
| CPythonTestOutput.txt | Oren Milman, 2016年09月28日 10:11 | test output of CPython without my patches (tested on my PC) | ||
| issue28298_ver1.diff | Oren Milman, 2016年09月28日 10:11 | proposed patches diff file - ver1 | review | |
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 570 | merged | Oren Milman, 2017年03月08日 23:40 | |
| PR 579 | merged | Oren Milman, 2017年03月09日 13:33 | |
| PR 588 | merged | Oren Milman, 2017年03月09日 18:51 | |
| PR 703 | larry, 2017年03月17日 21:00 | ||
| Messages (13) | |||
|---|---|---|---|
| msg277604 - (view) | Author: Oren Milman (Oren Milman) * | Date: 2016年09月28日 10:09 | |
------------ current state ------------
On my Windows 10, on a 32-bit Python, The following runs fine:
import array
array.array('L').append(2 ** 32 - 1)
However, in the following, an OverflowError('Python int too large to convert to C long') is raised on the last line:
import array
class LikeInt:
def __init__(self, intVal):
self.intVal = intVal
def __int__(self):
return self.intVal
array.array('L').append(LikeInt(2 ** 32 - 1))
The reason for this behavior is the implementation of the function LL_setitem (in Modules/arraymodule.c) (edited brutally for brevity):
LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
unsigned long x;
if (PyLong_Check(v)) {
x = PyLong_AsUnsignedLong(v);
}
else {
long y;
PyArg_Parse(v, "l;array item must be integer", &y);
x = (unsigned long)y;
}
(ap->ob_item)[i] = x;
}
The problem is that PyArg_Parse is used to convert a Python int into a C long. So PyArg_Parse fails when it is given a Python int which is in range(LONG_MAX + 1, ULONG_MAX + 1), even though such Python int can be stored in a C unsigned long.
It is quite the same for array('I') and array('Q') (i.e. in II_setitem and in QQ_setitem, respectively).
With regard to relevant changes made in the past, PyArg_Parse was always used (in case '!PyLong_Check(v)'), since adding the original versions of:
* II_setitem and LL_setitem (back then, they were called I_setitem and L_setitem, respectively), in changeset 4875 (https://hg.python.org/cpython/rev/911040e1bb11)
* QQ_setitem, in changeset 72430 (https://hg.python.org/cpython/rev/15659e0e2b2e)
------------ proposed changes ------------
1. In Modules/arraymodule.c, change the implementation of LL_setitem (and likewise, of II_setitem and QQ_setitem) roughly to the following:
LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
unsigned long x;
if (!PyLong_Check(v)) {
v = _PyLong_FromNbInt(v);
}
x = PyLong_AsUnsignedLong(v);
(ap->ob_item)[i] = x;
}
2. In Lib/test/test_array.py, add tests:
* to verify the bug is fixed, i.e. test the bounds of setting int-like objects to items in an integers array
* to verify float objects can't be set to items in an integers array (as is already the behavior, but there aren't any tests for it)
3. While we are in Lib/test/test_array.py, remove any checks whether 'long long' is available, as it must be available, since changeset 103105 (https://hg.python.org/cpython/rev/9206a86f7321).
Note that issue #12974 (opened in 2011) proposes deprecating the ability to set int-like objects to items in an integers array. (I am not sure how that affects my patch, but I guess it should be noted.)
------------ diff ------------
The proposed patches diff file is attached.
(Note that the I didn't propose to change the perplexing error message 'unsigned int is greater than maximum' in II_setitem, as there are many such messages in the codebase, and I am working on a patch for them as part of issue #15988.)
------------ tests ------------
I ran 'python_d.exe -m test -j3' (on my 64-bit Windows 10) with and without the patches, and got quite the same output. (That also means my new tests in test_array passed.)
The outputs of both runs are attached.
|
|||
| msg277685 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2016年09月29日 08:10 | |
One comment here: it's not the presence of `__int__` that makes a type integer-like; it's the presence of `__index__`. (Decimal and float both supply `__int__`, but shouldn't be regarded as integer-like, for example.) I'm guessing that we're going to have the same issues with `__index__` in place of `__int__`, though. |
|||
| msg277704 - (view) | Author: Oren Milman (Oren Milman) * | Date: 2016年09月29日 12:48 | |
You are right about the terminology of course. My bad. Anyway, the bug is not related to __index__ (or nb_index), because the three aforementioned functions are using (in case '!PyLong_Check(v)') PyArg_Parse with the formats 'l' or 'L'. Ultimately, convertsimple (in Python/getargs.c) would call PyLong_AsLong or PyLong_AsLongLong (respectively). These two (in case '!PyLong_Check(v)') only try to use nb_int, as documented: * https://docs.python.org/3.7/c-api/long.html?highlight=pylong_aslong#c.PyLong_AsLong * https://docs.python.org/3.7/c-api/long.html?highlight=pylong_aslong#c.PyLong_AsLongLong But just in case, I ran the following: import array class LikeInt: def __init__(self, intVal): self.intVal = intVal def __index__(self): return self.intVal array.array('L').append(LikeInt(0)) and got a 'TypeError: an integer is required (got type LikeInt)' |
|||
| msg277707 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2016年09月29日 16:15 | |
> and got a 'TypeError: an integer is required (got type LikeInt)' Right, see #12974 for more on arrays, `__int__` and `__index__`. |
|||
| msg277729 - (view) | Author: Oren Milman (Oren Milman) * | Date: 2016年09月29日 21:15 | |
Ah, I should have read more about __int__ and __index__ before writing my last reply. So IIUC, this is a somewhat painful issue, which could be resolved by: * #20092 * replacing _PyLong_FromNbInt with PyNumber_Index in: - Objects/longobject.c (as you suggested in https://bugs.python.org/issue12965#msg146252) - Modules/zlibmodule.c in ssize_t_converter I didn't find any issue for the second one. If there is really no such issue, why is that? (I am sorry if I am the thousandth one to ask) The first paragraph of your comment in https://bugs.python.org/issue21111#msg215660 suggests it might break a lot of code in the wild, but shouldn't we start with raising a deprecation warning? With regard to my patch - should I make the following changes? 1. in Modules/arraymodule.c - add a call to PyNumber_Index before the call to _PyLong_FromNbInt (and move them into a helper function, as done in Modules/_struct.c) 2. in Lib/test/test_array.py: * replace the name 'LikeInt' with 'IntCompatible' (I am not sure this is an appropriate name either. If you have a better name in mind, please share :) ) * add tests for LikeInt (this time, a class with a __index__ method) 3. In Doc/library/array.rst: * add a note saying that setting int-like objects (i.e. objects with __index__) to items in an integers array is possible * while we are here, remove the note about the availability of 'q' and 'Q' only in certain platforms |
|||
| msg288866 - (view) | Author: Oren Milman (Oren Milman) * | Date: 2017年03月03日 07:20 | |
ping |
|||
| msg289218 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2017年03月08日 08:30 | |
LGTM. But maybe combine PyFloat_Check+_PyLong_FromNbInt in one helper function? Could you please create a PR Oren? |
|||
| msg289234 - (view) | Author: Oren Milman (Oren Milman) * | Date: 2017年03月08日 13:02 | |
yes and yes. I would start with a PR for 3.7. and thanks for the review :) |
|||
| msg289336 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2017年03月10日 06:14 | |
Thank you for your contribution Oren. |
|||
| msg289341 - (view) | Author: Oren Milman (Oren Milman) * | Date: 2017年03月10日 08:07 | |
Thanks for the reviews :) |
|||
| msg290243 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2017年03月24日 22:37 | |
New changeset e2c88bdd6bb3efbc81389958d62daf6dd0d6eda7 by Serhiy Storchaka (orenmn) in branch '3.5': bpo-28298: make array 'Q', 'L' and 'I' accept big intables as elements https://github.com/python/cpython/commit/e2c88bdd6bb3efbc81389958d62daf6dd0d6eda7 |
|||
| msg290251 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2017年03月24日 22:38 | |
New changeset 26d013e00f9d4adbcf3e084bbc890c799ff70407 by Serhiy Storchaka (orenmn) in branch '3.6': [3.6] bpo-28298: make array 'Q', 'L' and 'I' accept big intables as elements (#579) https://github.com/python/cpython/commit/26d013e00f9d4adbcf3e084bbc890c799ff70407 |
|||
| msg290252 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2017年03月24日 22:38 | |
New changeset 964281af59d7a17d923c4d72357e48832b774e39 by Serhiy Storchaka (orenmn) in branch 'master': bpo-28298: make array 'Q', 'L' and 'I' accept big intables as elements (#570) https://github.com/python/cpython/commit/964281af59d7a17d923c4d72357e48832b774e39 |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:58:37 | admin | set | github: 72485 |
| 2017年03月24日 22:38:54 | serhiy.storchaka | set | messages: + msg290252 |
| 2017年03月24日 22:38:40 | serhiy.storchaka | set | messages: + msg290251 |
| 2017年03月24日 22:37:28 | serhiy.storchaka | set | messages: + msg290243 |
| 2017年03月17日 21:00:34 | larry | set | pull_requests: + pull_request604 |
| 2017年03月15日 09:06:14 | serhiy.storchaka | link | issue15988 dependencies |
| 2017年03月10日 08:07:37 | Oren Milman | set | messages: + msg289341 |
| 2017年03月10日 06:14:23 | serhiy.storchaka | set | status: open -> closed resolution: fixed messages: + msg289336 stage: commit review -> resolved |
| 2017年03月09日 18:51:35 | Oren Milman | set | pull_requests: + pull_request485 |
| 2017年03月09日 13:33:31 | Oren Milman | set | pull_requests: + pull_request476 |
| 2017年03月08日 23:40:59 | Oren Milman | set | pull_requests: + pull_request466 |
| 2017年03月08日 13:02:58 | Oren Milman | set | messages: + msg289234 |
| 2017年03月08日 08:30:20 | serhiy.storchaka | set | stage: patch review -> commit review messages: + msg289218 versions: + Python 3.5, Python 3.6 |
| 2017年03月03日 07:40:55 | serhiy.storchaka | set | stage: patch review |
| 2017年03月03日 07:40:47 | serhiy.storchaka | set | assignee: serhiy.storchaka |
| 2017年03月03日 07:20:16 | Oren Milman | set | messages: + msg288866 |
| 2016年09月29日 21:15:45 | Oren Milman | set | messages: + msg277729 |
| 2016年09月29日 16:15:19 | mark.dickinson | set | messages: + msg277707 |
| 2016年09月29日 12:48:44 | Oren Milman | set | messages: + msg277704 |
| 2016年09月29日 08:10:51 | mark.dickinson | set | messages: + msg277685 |
| 2016年09月28日 11:48:09 | serhiy.storchaka | set | nosy:
+ mark.dickinson, meador.inge |
| 2016年09月28日 11:47:13 | serhiy.storchaka | set | nosy:
+ serhiy.storchaka |
| 2016年09月28日 10:14:35 | Oren Milman | set | versions: + Python 3.7 |
| 2016年09月28日 10:11:34 | Oren Milman | set | files:
+ issue28298_ver1.diff keywords: + patch |
| 2016年09月28日 10:11:08 | Oren Milman | set | files: + CPythonTestOutput.txt |
| 2016年09月28日 10:09:35 | Oren Milman | create | |