[Python-checkins] r69230 - in python/branches/release30-maint: Include/abstract.h Lib/test/test_iterlen.py Misc/NEWS Objects/abstract.c Objects/bytearrayobject.c Objects/listobject.c

raymond.hettinger python-checkins at python.org
Tue Feb 3 00:42:37 CET 2009


Author: raymond.hettinger
Date: Tue Feb 3 00:42:36 2009
New Revision: 69230
Log:
Issue 1242657: list(obj) can swallow KeyboardInterrupt.
Modified:
 python/branches/release30-maint/Include/abstract.h
 python/branches/release30-maint/Lib/test/test_iterlen.py
 python/branches/release30-maint/Misc/NEWS
 python/branches/release30-maint/Objects/abstract.c
 python/branches/release30-maint/Objects/bytearrayobject.c
 python/branches/release30-maint/Objects/listobject.c
Modified: python/branches/release30-maint/Include/abstract.h
==============================================================================
--- python/branches/release30-maint/Include/abstract.h	(original)
+++ python/branches/release30-maint/Include/abstract.h	Tue Feb 3 00:42:36 2009
@@ -392,7 +392,7 @@
 /*
 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
- 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);
Modified: python/branches/release30-maint/Lib/test/test_iterlen.py
==============================================================================
--- python/branches/release30-maint/Lib/test/test_iterlen.py	(original)
+++ python/branches/release30-maint/Lib/test/test_iterlen.py	Tue Feb 3 00:42:36 2009
@@ -195,6 +195,29 @@
 d.extend(range(20))
 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())
+ b = bytearray(range(10))
+ self.assertRaises(RuntimeError, b.extend, BadLen())
+ self.assertRaises(RuntimeError, b.extend, BadLengthHint())
 
 def test_main():
 unittests = [
@@ -210,6 +233,7 @@
 TestSet,
 TestList,
 TestListReversed,
+ TestLengthHintExceptions,
 ]
 support.run_unittest(*unittests)
 
Modified: python/branches/release30-maint/Misc/NEWS
==============================================================================
--- python/branches/release30-maint/Misc/NEWS	(original)
+++ python/branches/release30-maint/Misc/NEWS	Tue Feb 3 00:42:36 2009
@@ -17,6 +17,9 @@
 the type definition cmpfunc. The tp_compare slot has been renamed
 to tp_reserved, and is reserved for future usage.
 
+- Issue 1242657: the __len__() and __length_hint__() calls in several tools
+ were suppressing all exceptions. These include list() and bytearray().
+
 - Issue #4707: round(x, n) now returns an integer if x is an integer.
 Previously it returned a float.
 
Modified: python/branches/release30-maint/Objects/abstract.c
==============================================================================
--- python/branches/release30-maint/Objects/abstract.c	(original)
+++ python/branches/release30-maint/Objects/abstract.c	Tue Feb 3 00:42:36 2009
@@ -67,8 +67,8 @@
 
 /* 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
- value, then the defaultvalue is returned. This function never fails. 
- Accordingly, it will mask exceptions raised in either method.
+ value, then the defaultvalue is returned. If one of the calls fails,
+ this function returns -1.
 */
 
 Py_ssize_t
@@ -82,29 +82,32 @@
 	rv = PyObject_Size(o);
 	if (rv >= 0)
 		return rv;
-	if (PyErr_Occurred())
+	if (PyErr_Occurred()) {
+		if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
+			!PyErr_ExceptionMatches(PyExc_AttributeError))
+				return -1;
 		PyErr_Clear();
+	}
 
 	/* cache a hashed version of the attribute string */
 	if (hintstrobj == NULL) {
 		hintstrobj = PyUnicode_InternFromString("__length_hint__");
 		if (hintstrobj == NULL)
-			goto defaultcase;
+			return -1;
 	}
 
 	/* try o.__length_hint__() */
 	ro = PyObject_CallMethodObjArgs(o, hintstrobj, NULL);
-	if (ro == NULL)
-		goto defaultcase;
+	if (ro == NULL) {
+		if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
+			!PyErr_ExceptionMatches(PyExc_AttributeError))
+				return -1;
+		PyErr_Clear();
+		return defaultvalue;
+	}
 	rv = PyLong_AsSsize_t(ro);
 	Py_DECREF(ro);
-	if (rv >= 0)
-		return rv;
-
-defaultcase:
-	if (PyErr_Occurred())
-		PyErr_Clear();
-	return defaultvalue;
+	return rv;
 }
 
 PyObject *
@@ -1742,7 +1745,7 @@
 {
 	PyObject *it; /* iter(v) */
 	Py_ssize_t n;	 /* guess for result tuple size */
-	PyObject *result;
+	PyObject *result = NULL;
 	Py_ssize_t j;
 
 	if (v == NULL)
@@ -1767,6 +1770,8 @@
 
 	/* Guess result size and allocate space. */
 	n = _PyObject_LengthHint(v, 10);
+	if (n == -1)
+		goto Fail;
 	result = PyTuple_New(n);
 	if (result == NULL)
 		goto Fail;
Modified: python/branches/release30-maint/Objects/bytearrayobject.c
==============================================================================
--- python/branches/release30-maint/Objects/bytearrayobject.c	(original)
+++ python/branches/release30-maint/Objects/bytearrayobject.c	Tue Feb 3 00:42:36 2009
@@ -2608,6 +2608,10 @@
 
 /* Try to determine the length of the argument. 32 is abitrary. */
 buf_size = _PyObject_LengthHint(arg, 32);
+	if (buf_size == -1) {
+		Py_DECREF(it);
+		return NULL;
+	}
 
 bytes_obj = PyByteArray_FromStringAndSize(NULL, buf_size);
 if (bytes_obj == NULL)
Modified: python/branches/release30-maint/Objects/listobject.c
==============================================================================
--- python/branches/release30-maint/Objects/listobject.c	(original)
+++ python/branches/release30-maint/Objects/listobject.c	Tue Feb 3 00:42:36 2009
@@ -802,6 +802,10 @@
 
 	/* Guess a result list size. */
 	n = _PyObject_LengthHint(b, 8);
+	if (n == -1) {
+		Py_DECREF(it);
+		return NULL;
+	}
 	m = Py_SIZE(self);
 	mn = m + n;
 	if (mn >= m) {


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /