bpo-28298: make array 'Q', 'L' and 'I' accept big intables as elements

This commit is contained in:
orenmn 2017-03-09 21:29:22 +02:00 committed by Serhiy Storchaka
parent 5fad493dc6
commit e2c88bdd6b
3 changed files with 90 additions and 50 deletions

View file

@ -1225,7 +1225,26 @@ class NumberTest(BaseTest):
b = array.array(self.typecode, a) b = array.array(self.typecode, a)
self.assertEqual(a, b) self.assertEqual(a, b)
class SignedNumberTest(NumberTest): class IntegerNumberTest(NumberTest):
def test_type_error(self):
a = array.array(self.typecode)
a.append(42)
with self.assertRaises(TypeError):
a.append(42.0)
with self.assertRaises(TypeError):
a[0] = 42.0
class Intable:
def __init__(self, num):
self._num = num
def __int__(self):
return self._num
def __sub__(self, other):
return Intable(int(self) - int(other))
def __add__(self, other):
return Intable(int(self) + int(other))
class SignedNumberTest(IntegerNumberTest):
example = [-1, 0, 1, 42, 0x7f] example = [-1, 0, 1, 42, 0x7f]
smallerexample = [-1, 0, 1, 42, 0x7e] smallerexample = [-1, 0, 1, 42, 0x7e]
biggerexample = [-1, 0, 1, 43, 0x7f] biggerexample = [-1, 0, 1, 43, 0x7f]
@ -1236,8 +1255,9 @@ class SignedNumberTest(NumberTest):
lower = -1 * int(pow(2, a.itemsize * 8 - 1)) lower = -1 * int(pow(2, a.itemsize * 8 - 1))
upper = int(pow(2, a.itemsize * 8 - 1)) - 1 upper = int(pow(2, a.itemsize * 8 - 1)) - 1
self.check_overflow(lower, upper) self.check_overflow(lower, upper)
self.check_overflow(Intable(lower), Intable(upper))
class UnsignedNumberTest(NumberTest): class UnsignedNumberTest(IntegerNumberTest):
example = [0, 1, 17, 23, 42, 0xff] example = [0, 1, 17, 23, 42, 0xff]
smallerexample = [0, 1, 17, 23, 42, 0xfe] smallerexample = [0, 1, 17, 23, 42, 0xfe]
biggerexample = [0, 1, 17, 23, 43, 0xff] biggerexample = [0, 1, 17, 23, 43, 0xff]
@ -1248,6 +1268,7 @@ class UnsignedNumberTest(NumberTest):
lower = 0 lower = 0
upper = int(pow(2, a.itemsize * 8)) - 1 upper = int(pow(2, a.itemsize * 8)) - 1
self.check_overflow(lower, upper) self.check_overflow(lower, upper)
self.check_overflow(Intable(lower), Intable(upper))
def test_bytes_extend(self): def test_bytes_extend(self):
s = bytes(self.example) s = bytes(self.example)

View file

@ -41,6 +41,9 @@ Extension Modules
Library Library
------- -------
- bpo-28298: Fix a bug that prevented array 'Q', 'L' and 'I' from accepting big
intables (objects that have __int__) as elements. Patch by Oren Milman.
- bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other - bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other
exception) to exception(s) raised in the dispatched methods. exception) to exception(s) raised in the dispatched methods.
Patch by Petr Motejlek. Patch by Petr Motejlek.

View file

@ -331,35 +331,51 @@ II_getitem(arrayobject *ap, Py_ssize_t i)
(unsigned long) ((unsigned int *)ap->ob_item)[i]); (unsigned long) ((unsigned int *)ap->ob_item)[i]);
} }
static PyObject *
get_int_unless_float(PyObject *v)
{
if (PyFloat_Check(v)) {
PyErr_SetString(PyExc_TypeError,
"array item must be integer");
return NULL;
}
return (PyObject *)_PyLong_FromNbInt(v);
}
static int static int
II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{ {
unsigned long x; unsigned long x;
if (PyLong_Check(v)) { int do_decref = 0; /* if nb_int was called */
x = PyLong_AsUnsignedLong(v);
if (x == (unsigned long) -1 && PyErr_Occurred()) if (!PyLong_Check(v)) {
return -1; v = get_int_unless_float(v);
} if (NULL == v) {
else {
long y;
if (!PyArg_Parse(v, "l;array item must be integer", &y))
return -1;
if (y < 0) {
PyErr_SetString(PyExc_OverflowError,
"unsigned int is less than minimum");
return -1; return -1;
} }
x = (unsigned long)y; do_decref = 1;
}
x = PyLong_AsUnsignedLong(v);
if (x == (unsigned long)-1 && PyErr_Occurred()) {
if (do_decref) {
Py_DECREF(v);
}
return -1;
} }
if (x > UINT_MAX) { if (x > UINT_MAX) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"unsigned int is greater than maximum"); "unsigned int is greater than maximum");
if (do_decref) {
Py_DECREF(v);
}
return -1; return -1;
} }
if (i >= 0) if (i >= 0)
((unsigned int *)ap->ob_item)[i] = (unsigned int)x; ((unsigned int *)ap->ob_item)[i] = (unsigned int)x;
if (do_decref) {
Py_DECREF(v);
}
return 0; return 0;
} }
@ -390,31 +406,28 @@ static int
LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{ {
unsigned long x; unsigned long x;
if (PyLong_Check(v)) { int do_decref = 0; /* if nb_int was called */
x = PyLong_AsUnsignedLong(v);
if (x == (unsigned long) -1 && PyErr_Occurred()) if (!PyLong_Check(v)) {
return -1; v = get_int_unless_float(v);
} if (NULL == v) {
else {
long y;
if (!PyArg_Parse(v, "l;array item must be integer", &y))
return -1;
if (y < 0) {
PyErr_SetString(PyExc_OverflowError,
"unsigned long is less than minimum");
return -1; return -1;
} }
x = (unsigned long)y; do_decref = 1;
} }
if (x > ULONG_MAX) { x = PyLong_AsUnsignedLong(v);
PyErr_SetString(PyExc_OverflowError, if (x == (unsigned long)-1 && PyErr_Occurred()) {
"unsigned long is greater than maximum"); if (do_decref) {
Py_DECREF(v);
}
return -1; return -1;
} }
if (i >= 0) if (i >= 0)
((unsigned long *)ap->ob_item)[i] = x; ((unsigned long *)ap->ob_item)[i] = x;
if (do_decref) {
Py_DECREF(v);
}
return 0; return 0;
} }
@ -448,25 +461,28 @@ static int
QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{ {
unsigned PY_LONG_LONG x; unsigned PY_LONG_LONG x;
if (PyLong_Check(v)) { int do_decref = 0; /* if nb_int was called */
x = PyLong_AsUnsignedLongLong(v);
if (x == (unsigned PY_LONG_LONG) -1 && PyErr_Occurred()) if (!PyLong_Check(v)) {
return -1; v = get_int_unless_float(v);
} if (NULL == v) {
else {
PY_LONG_LONG y;
if (!PyArg_Parse(v, "L;array item must be integer", &y))
return -1;
if (y < 0) {
PyErr_SetString(PyExc_OverflowError,
"unsigned long long is less than minimum");
return -1; return -1;
} }
x = (unsigned PY_LONG_LONG)y; do_decref = 1;
}
x = PyLong_AsUnsignedLongLong(v);
if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) {
if (do_decref) {
Py_DECREF(v);
}
return -1;
} }
if (i >= 0) if (i >= 0)
((unsigned PY_LONG_LONG *)ap->ob_item)[i] = x; ((unsigned PY_LONG_LONG *)ap->ob_item)[i] = x;
if (do_decref) {
Py_DECREF(v);
}
return 0; return 0;
} }
#endif #endif