mirror of https://github.com/python/cpython
Issue 1242657: list(obj) can swallow KeyboardInterrupt.
This commit is contained in:
parent
d7bb4d484f
commit
b516370bcb
|
@ -438,7 +438,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
/*
|
/*
|
||||||
Guess the size of object o using len(o) or o.__length_hint__().
|
Guess the size of object o using len(o) or o.__length_hint__().
|
||||||
If neither of those return a non-negative value, then return the
|
If neither of those return a non-negative value, then return the
|
||||||
default value. This function never fails. All exceptions are cleared.
|
default value. If one of the calls fails, this function returns -1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key);
|
PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key);
|
||||||
|
|
|
@ -195,6 +195,36 @@ class TestListReversed(TestInvariantWithoutMutations):
|
||||||
d.extend(xrange(20))
|
d.extend(xrange(20))
|
||||||
self.assertEqual(len(it), 0)
|
self.assertEqual(len(it), 0)
|
||||||
|
|
||||||
|
## -- Check to make sure exceptions are not suppressed by __length_hint__()
|
||||||
|
|
||||||
|
|
||||||
|
class BadLen(object):
|
||||||
|
def __iter__(self): return iter(range(10))
|
||||||
|
def __len__(self):
|
||||||
|
raise RuntimeError('hello')
|
||||||
|
|
||||||
|
class BadLengthHint(object):
|
||||||
|
def __iter__(self): return iter(range(10))
|
||||||
|
def __length_hint__(self):
|
||||||
|
raise RuntimeError('hello')
|
||||||
|
|
||||||
|
class TestLengthHintExceptions(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_issue1242657(self):
|
||||||
|
self.assertRaises(RuntimeError, list, BadLen())
|
||||||
|
self.assertRaises(RuntimeError, list, BadLengthHint())
|
||||||
|
self.assertRaises(RuntimeError, [].extend, BadLen())
|
||||||
|
self.assertRaises(RuntimeError, [].extend, BadLengthHint())
|
||||||
|
self.assertRaises(RuntimeError, zip, BadLen())
|
||||||
|
self.assertRaises(RuntimeError, zip, BadLengthHint())
|
||||||
|
self.assertRaises(RuntimeError, filter, None, BadLen())
|
||||||
|
self.assertRaises(RuntimeError, filter, None, BadLengthHint())
|
||||||
|
self.assertRaises(RuntimeError, map, chr, BadLen())
|
||||||
|
self.assertRaises(RuntimeError, map, chr, BadLengthHint())
|
||||||
|
b = bytearray(range(10))
|
||||||
|
self.assertRaises(RuntimeError, b.extend, BadLen())
|
||||||
|
self.assertRaises(RuntimeError, b.extend, BadLengthHint())
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
unittests = [
|
unittests = [
|
||||||
TestRepeat,
|
TestRepeat,
|
||||||
|
@ -209,6 +239,7 @@ def test_main():
|
||||||
TestSet,
|
TestSet,
|
||||||
TestList,
|
TestList,
|
||||||
TestListReversed,
|
TestListReversed,
|
||||||
|
TestLengthHintExceptions,
|
||||||
]
|
]
|
||||||
test_support.run_unittest(*unittests)
|
test_support.run_unittest(*unittests)
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ Core and Builtins
|
||||||
|
|
||||||
- Issue #4978: Passing keyword arguments as unicode strings is now allowed.
|
- Issue #4978: Passing keyword arguments as unicode strings is now allowed.
|
||||||
|
|
||||||
|
- Issue 1242657: the __len__() and __length_hint__() calls in several tools
|
||||||
|
were suppressing all exceptions. These include list(), filter(), map(),
|
||||||
|
zip(), and bytearray().
|
||||||
|
|
||||||
- os.ftruncate raises OSErrors instead of IOErrors for consistency with other os
|
- os.ftruncate raises OSErrors instead of IOErrors for consistency with other os
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
|
|
|
@ -85,8 +85,8 @@ PyObject_Length(PyObject *o)
|
||||||
|
|
||||||
/* The length hint function returns a non-negative value from o.__len__()
|
/* The length hint function returns a non-negative value from o.__len__()
|
||||||
or o.__length_hint__(). If those methods aren't found or return a negative
|
or o.__length_hint__(). If those methods aren't found or return a negative
|
||||||
value, then the defaultvalue is returned. This function never fails.
|
value, then the defaultvalue is returned. If one of the calls fails,
|
||||||
Accordingly, it will mask exceptions raised in either method.
|
this function returns -1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
|
@ -100,29 +100,32 @@ _PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
|
||||||
rv = PyObject_Size(o);
|
rv = PyObject_Size(o);
|
||||||
if (rv >= 0)
|
if (rv >= 0)
|
||||||
return rv;
|
return rv;
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred()) {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
|
||||||
|
!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||||
|
return -1;
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/* cache a hashed version of the attribute string */
|
/* cache a hashed version of the attribute string */
|
||||||
if (hintstrobj == NULL) {
|
if (hintstrobj == NULL) {
|
||||||
hintstrobj = PyString_InternFromString("__length_hint__");
|
hintstrobj = PyString_InternFromString("__length_hint__");
|
||||||
if (hintstrobj == NULL)
|
if (hintstrobj == NULL)
|
||||||
goto defaultcase;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try o.__length_hint__() */
|
/* try o.__length_hint__() */
|
||||||
ro = PyObject_CallMethodObjArgs(o, hintstrobj, NULL);
|
ro = PyObject_CallMethodObjArgs(o, hintstrobj, NULL);
|
||||||
if (ro == NULL)
|
if (ro == NULL) {
|
||||||
goto defaultcase;
|
if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
|
||||||
|
!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||||
|
return -1;
|
||||||
|
PyErr_Clear();
|
||||||
|
return defaultvalue;
|
||||||
|
}
|
||||||
rv = PyInt_AsLong(ro);
|
rv = PyInt_AsLong(ro);
|
||||||
Py_DECREF(ro);
|
Py_DECREF(ro);
|
||||||
if (rv >= 0)
|
return rv;
|
||||||
return rv;
|
|
||||||
|
|
||||||
defaultcase:
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
PyErr_Clear();
|
|
||||||
return defaultvalue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -2128,7 +2131,7 @@ PySequence_Tuple(PyObject *v)
|
||||||
{
|
{
|
||||||
PyObject *it; /* iter(v) */
|
PyObject *it; /* iter(v) */
|
||||||
Py_ssize_t n; /* guess for result tuple size */
|
Py_ssize_t n; /* guess for result tuple size */
|
||||||
PyObject *result;
|
PyObject *result = NULL;
|
||||||
Py_ssize_t j;
|
Py_ssize_t j;
|
||||||
|
|
||||||
if (v == NULL)
|
if (v == NULL)
|
||||||
|
@ -2153,6 +2156,8 @@ PySequence_Tuple(PyObject *v)
|
||||||
|
|
||||||
/* Guess result size and allocate space. */
|
/* Guess result size and allocate space. */
|
||||||
n = _PyObject_LengthHint(v, 10);
|
n = _PyObject_LengthHint(v, 10);
|
||||||
|
if (n == -1)
|
||||||
|
goto Fail;
|
||||||
result = PyTuple_New(n);
|
result = PyTuple_New(n);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
|
|
@ -2691,6 +2691,10 @@ bytes_extend(PyByteArrayObject *self, PyObject *arg)
|
||||||
|
|
||||||
/* Try to determine the length of the argument. 32 is abitrary. */
|
/* Try to determine the length of the argument. 32 is abitrary. */
|
||||||
buf_size = _PyObject_LengthHint(arg, 32);
|
buf_size = _PyObject_LengthHint(arg, 32);
|
||||||
|
if (buf_size == -1) {
|
||||||
|
Py_DECREF(it);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bytes_obj = PyByteArray_FromStringAndSize(NULL, buf_size);
|
bytes_obj = PyByteArray_FromStringAndSize(NULL, buf_size);
|
||||||
if (bytes_obj == NULL)
|
if (bytes_obj == NULL)
|
||||||
|
|
|
@ -838,6 +838,10 @@ listextend(PyListObject *self, PyObject *b)
|
||||||
|
|
||||||
/* Guess a result list size. */
|
/* Guess a result list size. */
|
||||||
n = _PyObject_LengthHint(b, 8);
|
n = _PyObject_LengthHint(b, 8);
|
||||||
|
if (n == -1) {
|
||||||
|
Py_DECREF(it);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
m = Py_SIZE(self);
|
m = Py_SIZE(self);
|
||||||
mn = m + n;
|
mn = m + n;
|
||||||
if (mn >= m) {
|
if (mn >= m) {
|
||||||
|
|
|
@ -268,6 +268,8 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
/* Guess a result list size. */
|
/* Guess a result list size. */
|
||||||
len = _PyObject_LengthHint(seq, 8);
|
len = _PyObject_LengthHint(seq, 8);
|
||||||
|
if (len == -1)
|
||||||
|
goto Fail_it;
|
||||||
|
|
||||||
/* Get a result list. */
|
/* Get a result list. */
|
||||||
if (PyList_Check(seq) && seq->ob_refcnt == 1) {
|
if (PyList_Check(seq) && seq->ob_refcnt == 1) {
|
||||||
|
|
Loading…
Reference in New Issue