summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/unittest.rst8
-rw-r--r--Lib/test/pickletester.py4
-rw-r--r--Lib/test/test_exceptions.py12
-rw-r--r--Lib/test/test_heapq.py26
-rw-r--r--Lib/test/test_posixpath.py1
-rw-r--r--Misc/NEWS9
-rw-r--r--Misc/python-config.in3
-rw-r--r--Modules/_heapqmodule.c40
-rw-r--r--Objects/exceptions.c3
9 files changed, 91 insertions, 15 deletions
diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
index d92b10e..c3170c0 100644
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -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):
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index f735e95..3e7e11d 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -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 = []
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 2160641..a485cba 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -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):
diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py
index 5932a40..73b88f0 100644
--- a/Lib/test/test_heapq.py
+++ b/Lib/test/test_heapq.py
@@ -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
diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py
index d9867a6..f74dc14 100644
--- a/Lib/test/test_posixpath.py
+++ b/Lib/test/test_posixpath.py
@@ -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.
diff --git a/Misc/NEWS b/Misc/NEWS
index 78d52f0..588a5c6 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
-----------
diff --git a/Misc/python-config.in b/Misc/python-config.in
index 552bbd5..ca9857a 100644
--- a/Misc/python-config.in
+++ b/Misc/python-config.in
@@ -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)
diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c
index fc24471..64259de 100644
--- a/Modules/_heapqmodule.c
+++ b/Modules/_heapqmodule.c
@@ -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
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 49f6d30..0f86cfb 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -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;
}