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`
or one of its conditional variants.
Basic skipping looks like this: ::
Basic skipping looks like this::
class MyTestCase(unittest.TestCase):
@ -603,7 +603,7 @@ Basic skipping looks like this: ::
# windows specific testing code
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_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)
Classes can be skipped just like methods: ::
Classes can be skipped just like methods::
@unittest.skip("showing class skipping")
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
: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):
if hasattr(obj, attr):

View File

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

View File

@ -479,6 +479,18 @@ class ExceptionTests(unittest.TestCase):
except AssertionError as e:
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
class ExcWithOverriddenStr(Exception):

View File

@ -315,6 +315,16 @@ def L(seqn):
'Test multiple tiers of iterators'
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):
module = None
@ -361,6 +371,22 @@ class TestErrorHandling(TestCase):
self.assertRaises(TypeError, f, 2, N(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):
module = py_heapq

View File

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

View File

@ -9,6 +9,9 @@ What's New in Python 2.7.4
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
BufferedWriter and BufferedRandom.
@ -211,6 +214,9 @@ Core and Builtins
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 #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 #16848: python-config now returns proper --ldflags values for OS X
framework builds.
Tools/Demos
-----------

View File

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

View File

@ -35,12 +35,14 @@ cmp_lt(PyObject *x, PyObject *y)
static int
_siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
{
PyObject *newitem, *parent;
PyObject *newitem, *parent, *olditem;
int cmp;
Py_ssize_t parentpos;
Py_ssize_t size;
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");
return -1;
}
@ -57,12 +59,24 @@ _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Py_DECREF(newitem);
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)
break;
Py_INCREF(parent);
Py_DECREF(PyList_GET_ITEM(heap, pos));
olditem = PyList_GET_ITEM(heap, pos);
PyList_SET_ITEM(heap, pos, parent);
Py_DECREF(olditem);
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));
PyList_SET_ITEM(heap, pos, newitem);
@ -74,10 +88,12 @@ _siftup(PyListObject *heap, Py_ssize_t pos)
{
Py_ssize_t startpos, endpos, childpos, rightpos;
int cmp;
PyObject *newitem, *tmp;
PyObject *newitem, *tmp, *olditem;
Py_ssize_t size;
assert(PyList_Check(heap));
endpos = PyList_GET_SIZE(heap);
size = PyList_GET_SIZE(heap);
endpos = size;
startpos = pos;
if (pos >= endpos) {
PyErr_SetString(PyExc_IndexError, "index out of range");
@ -102,13 +118,25 @@ _siftup(PyListObject *heap, Py_ssize_t pos)
if (cmp == 0)
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. */
tmp = PyList_GET_ITEM(heap, childpos);
Py_INCREF(tmp);
Py_DECREF(PyList_GET_ITEM(heap, pos));
olditem = PyList_GET_ITEM(heap, pos);
PyList_SET_ITEM(heap, pos, tmp);
Py_DECREF(olditem);
pos = childpos;
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

View File

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