This commit is contained in:
Raymond Hettinger 2013-03-05 02:16:45 -05:00
commit 757408a2f3
9 changed files with 91 additions and 15 deletions

View File

@ -584,7 +584,7 @@ that is broken and will fail, but shouldn't be counted as a failure on a
Skipping a test is simply a matter of using the :func:`skip` :term:`decorator` Skipping a test is simply a matter of using the :func:`skip` :term:`decorator`
or one of its conditional variants. or one of its conditional variants.
Basic skipping looks like this: :: Basic skipping looks like this::
class MyTestCase(unittest.TestCase): class MyTestCase(unittest.TestCase):
@ -603,7 +603,7 @@ Basic skipping looks like this: ::
# windows specific testing code # windows specific testing code
pass pass
This is the output of running the example above in verbose mode: :: This is the output of running the example above in verbose mode::
test_format (__main__.MyTestCase) ... skipped 'not supported in this library version' test_format (__main__.MyTestCase) ... skipped 'not supported in this library version'
test_nothing (__main__.MyTestCase) ... skipped 'demonstrating skipping' test_nothing (__main__.MyTestCase) ... skipped 'demonstrating skipping'
@ -614,7 +614,7 @@ This is the output of running the example above in verbose mode: ::
OK (skipped=3) OK (skipped=3)
Classes can be skipped just like methods: :: Classes can be skipped just like methods::
@unittest.skip("showing class skipping") @unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase): class MySkippedTestCase(unittest.TestCase):
@ -633,7 +633,7 @@ Expected failures use the :func:`expectedFailure` decorator. ::
It's easy to roll your own skipping decorators by making a decorator that calls It's easy to roll your own skipping decorators by making a decorator that calls
:func:`skip` on the test when it wants it to be skipped. This decorator skips :func:`skip` on the test when it wants it to be skipped. This decorator skips
the test unless the passed object has a certain attribute: :: the test unless the passed object has a certain attribute::
def skipUnlessHasattr(obj, attr): def skipUnlessHasattr(obj, attr):
if hasattr(obj, attr): if hasattr(obj, attr):

View File

@ -503,10 +503,10 @@ class AbstractPickleTests(unittest.TestCase):
i = C() i = C()
i.attr = i i.attr = i
for proto in protocols: for proto in protocols:
s = self.dumps(i, 2) s = self.dumps(i, proto)
x = self.loads(s) x = self.loads(s)
self.assertEqual(dir(x), dir(i)) self.assertEqual(dir(x), dir(i))
self.assertTrue(x.attr is x) self.assertIs(x.attr, x)
def test_recursive_multi(self): def test_recursive_multi(self):
l = [] l = []

View File

@ -479,6 +479,18 @@ class ExceptionTests(unittest.TestCase):
except AssertionError as e: except AssertionError as e:
self.assertEqual(str(e), "(3,)") self.assertEqual(str(e), "(3,)")
def test_bad_exception_clearing(self):
# See issue 16445: use of Py_XDECREF instead of Py_CLEAR in
# BaseException_set_message gave a possible way to segfault the
# interpreter.
class Nasty(str):
def __del__(message):
del e.message
e = ValueError(Nasty("msg"))
e.args = ()
del e.message
# Helper class used by TestSameStrAndUnicodeMsg # Helper class used by TestSameStrAndUnicodeMsg
class ExcWithOverriddenStr(Exception): class ExcWithOverriddenStr(Exception):

View File

@ -315,6 +315,16 @@ def L(seqn):
'Test multiple tiers of iterators' 'Test multiple tiers of iterators'
return chain(imap(lambda x:x, R(Ig(G(seqn))))) return chain(imap(lambda x:x, R(Ig(G(seqn)))))
class SideEffectLT:
def __init__(self, value, heap):
self.value = value
self.heap = heap
def __lt__(self, other):
self.heap[:] = []
return self.value < other.value
class TestErrorHandling(TestCase): class TestErrorHandling(TestCase):
module = None module = None
@ -361,6 +371,22 @@ class TestErrorHandling(TestCase):
self.assertRaises(TypeError, f, 2, N(s)) self.assertRaises(TypeError, f, 2, N(s))
self.assertRaises(ZeroDivisionError, f, 2, E(s)) self.assertRaises(ZeroDivisionError, f, 2, E(s))
# Issue #17278: the heap may change size while it's being walked.
def test_heappush_mutating_heap(self):
heap = []
heap.extend(SideEffectLT(i, heap) for i in range(200))
# Python version raises IndexError, C version RuntimeError
with self.assertRaises((IndexError, RuntimeError)):
self.module.heappush(heap, SideEffectLT(5, heap))
def test_heappop_mutating_heap(self):
heap = []
heap.extend(SideEffectLT(i, heap) for i in range(200))
# Python version raises IndexError, C version RuntimeError
with self.assertRaises((IndexError, RuntimeError)):
self.module.heappop(heap)
class TestErrorHandlingPython(TestErrorHandling): class TestErrorHandlingPython(TestErrorHandling):
module = py_heapq module = py_heapq

View File

@ -284,6 +284,7 @@ class PosixPathTest(unittest.TestCase):
test_support.unlink(ABSTFN+"2") test_support.unlink(ABSTFN+"2")
test_support.unlink(ABSTFN+"y") test_support.unlink(ABSTFN+"y")
test_support.unlink(ABSTFN+"c") test_support.unlink(ABSTFN+"c")
test_support.unlink(ABSTFN+"a")
def test_realpath_repeated_indirect_symlinks(self): def test_realpath_repeated_indirect_symlinks(self):
# Issue #6975. # Issue #6975.

View File

@ -9,6 +9,9 @@ What's New in Python 2.7.4
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #16445: Fixed potential segmentation fault when deleting an exception
message.
- Issue #17275: Corrected class name in init error messages of the C version of - Issue #17275: Corrected class name in init error messages of the C version of
BufferedWriter and BufferedRandom. BufferedWriter and BufferedRandom.
@ -211,6 +214,9 @@ Core and Builtins
Library Library
------- -------
- Issue #17278: Fix a crash in heapq.heappush() and heapq.heappop() when
the list is being resized concurrently.
- Issue #17018: Make Process.join() retry if os.waitpid() fails with EINTR. - Issue #17018: Make Process.join() retry if os.waitpid() fails with EINTR.
- Issue #14720: sqlite3: Convert datetime microseconds correctly. - Issue #14720: sqlite3: Convert datetime microseconds correctly.
@ -917,6 +923,9 @@ Build
- Issue #17161: make install now also installs a python2 and python man page. - Issue #17161: make install now also installs a python2 and python man page.
- Issue #16848: python-config now returns proper --ldflags values for OS X
framework builds.
Tools/Demos Tools/Demos
----------- -----------

View File

@ -51,6 +51,7 @@ for opt in opt_flags:
if opt == '--ldflags': if opt == '--ldflags':
if not getvar('Py_ENABLE_SHARED'): if not getvar('Py_ENABLE_SHARED'):
libs.insert(0, '-L' + getvar('LIBPL')) libs.insert(0, '-L' + getvar('LIBPL'))
libs.extend(getvar('LINKFORSHARED').split()) if not getvar('PYTHONFRAMEWORK'):
libs.extend(getvar('LINKFORSHARED').split())
print ' '.join(libs) print ' '.join(libs)

View File

@ -35,12 +35,14 @@ cmp_lt(PyObject *x, PyObject *y)
static int static int
_siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
{ {
PyObject *newitem, *parent; PyObject *newitem, *parent, *olditem;
int cmp; int cmp;
Py_ssize_t parentpos; Py_ssize_t parentpos;
Py_ssize_t size;
assert(PyList_Check(heap)); assert(PyList_Check(heap));
if (pos >= PyList_GET_SIZE(heap)) { size = PyList_GET_SIZE(heap);
if (pos >= size) {
PyErr_SetString(PyExc_IndexError, "index out of range"); PyErr_SetString(PyExc_IndexError, "index out of range");
return -1; return -1;
} }
@ -57,12 +59,24 @@ _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Py_DECREF(newitem); Py_DECREF(newitem);
return -1; return -1;
} }
if (size != PyList_GET_SIZE(heap)) {
Py_DECREF(newitem);
PyErr_SetString(PyExc_RuntimeError,
"list changed size during iteration");
return -1;
}
if (cmp == 0) if (cmp == 0)
break; break;
Py_INCREF(parent); Py_INCREF(parent);
Py_DECREF(PyList_GET_ITEM(heap, pos)); olditem = PyList_GET_ITEM(heap, pos);
PyList_SET_ITEM(heap, pos, parent); PyList_SET_ITEM(heap, pos, parent);
Py_DECREF(olditem);
pos = parentpos; pos = parentpos;
if (size != PyList_GET_SIZE(heap)) {
PyErr_SetString(PyExc_RuntimeError,
"list changed size during iteration");
return -1;
}
} }
Py_DECREF(PyList_GET_ITEM(heap, pos)); Py_DECREF(PyList_GET_ITEM(heap, pos));
PyList_SET_ITEM(heap, pos, newitem); PyList_SET_ITEM(heap, pos, newitem);
@ -74,10 +88,12 @@ _siftup(PyListObject *heap, Py_ssize_t pos)
{ {
Py_ssize_t startpos, endpos, childpos, rightpos; Py_ssize_t startpos, endpos, childpos, rightpos;
int cmp; int cmp;
PyObject *newitem, *tmp; PyObject *newitem, *tmp, *olditem;
Py_ssize_t size;
assert(PyList_Check(heap)); assert(PyList_Check(heap));
endpos = PyList_GET_SIZE(heap); size = PyList_GET_SIZE(heap);
endpos = size;
startpos = pos; startpos = pos;
if (pos >= endpos) { if (pos >= endpos) {
PyErr_SetString(PyExc_IndexError, "index out of range"); PyErr_SetString(PyExc_IndexError, "index out of range");
@ -102,13 +118,25 @@ _siftup(PyListObject *heap, Py_ssize_t pos)
if (cmp == 0) if (cmp == 0)
childpos = rightpos; childpos = rightpos;
} }
if (size != PyList_GET_SIZE(heap)) {
Py_DECREF(newitem);
PyErr_SetString(PyExc_RuntimeError,
"list changed size during iteration");
return -1;
}
/* Move the smaller child up. */ /* Move the smaller child up. */
tmp = PyList_GET_ITEM(heap, childpos); tmp = PyList_GET_ITEM(heap, childpos);
Py_INCREF(tmp); Py_INCREF(tmp);
Py_DECREF(PyList_GET_ITEM(heap, pos)); olditem = PyList_GET_ITEM(heap, pos);
PyList_SET_ITEM(heap, pos, tmp); PyList_SET_ITEM(heap, pos, tmp);
Py_DECREF(olditem);
pos = childpos; pos = childpos;
childpos = 2*pos + 1; childpos = 2*pos + 1;
if (size != PyList_GET_SIZE(heap)) {
PyErr_SetString(PyExc_RuntimeError,
"list changed size during iteration");
return -1;
}
} }
/* The leaf at pos is empty now. Put newitem there, and and bubble /* The leaf at pos is empty now. Put newitem there, and and bubble

View File

@ -349,8 +349,7 @@ BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
if (PyDict_DelItemString(self->dict, "message") < 0) if (PyDict_DelItemString(self->dict, "message") < 0)
return -1; return -1;
} }
Py_XDECREF(self->message); Py_CLEAR(self->message);
self->message = NULL;
return 0; return 0;
} }