diff options
-rw-r--r-- | Lib/test/crashers/trace_at_recursion_limit.py | 27 | ||||
-rw-r--r-- | Lib/test/test_cmd_line.py | 12 | ||||
-rw-r--r-- | Lib/test/test_zlib.py | 13 | ||||
-rw-r--r-- | Misc/NEWS | 7 | ||||
-rw-r--r-- | Modules/zlibmodule.c | 29 | ||||
-rw-r--r-- | Python/pythonrun.c | 12 |
6 files changed, 88 insertions, 12 deletions
diff --git a/Lib/test/crashers/trace_at_recursion_limit.py b/Lib/test/crashers/trace_at_recursion_limit.py new file mode 100644 index 0000000..acd863f --- /dev/null +++ b/Lib/test/crashers/trace_at_recursion_limit.py @@ -0,0 +1,27 @@ +""" +From http://bugs.python.org/issue6717 + +A misbehaving trace hook can trigger a segfault by exceeding the recursion +limit. +""" +import sys + + +def x(): + pass + +def g(*args): + if True: # change to True to crash interpreter + try: + x() + except: + pass + return g + +def f(): + print(sys.getrecursionlimit()) + f() + +sys.settrace(g) + +f() diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index f463af4..7d039ee 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -364,6 +364,18 @@ class CmdLineTest(unittest.TestCase): self.assertEqual(rc, 0) self.assertIn(b'random is 1', out) + def test_del___main__(self): + # Issue #15001: PyRun_SimpleFileExFlags() did crash because it kept a + # borrowed reference to the dict of __main__ module and later modify + # the dict whereas the module was destroyed + filename = test.support.TESTFN + self.addCleanup(test.support.unlink, filename) + with open(filename, "w") as script: + print("import sys", file=script) + print("del sys.modules['__main__']", file=script) + assert_python_ok(filename) + + def test_main(): test.support.run_unittest(CmdLineTest) test.support.reap_children() diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 60081e2..c17b4d0 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -434,6 +434,19 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): y += dco.flush() self.assertEqual(y, b'foo') + def test_decompress_unused_data(self): + # Repeated calls to decompress() after EOF should accumulate data in + # dco.unused_data, instead of just storing the arg to the last call. + x = zlib.compress(HAMLET_SCENE) + HAMLET_SCENE + for step in 1, 2, 100: + dco = zlib.decompressobj() + data = b''.join(dco.decompress(x[i : i + step]) + for i in range(0, len(x), step)) + data += dco.flush() + + self.assertEqual(data, HAMLET_SCENE) + self.assertEqual(dco.unused_data, HAMLET_SCENE) + if hasattr(zlib.compressobj(), "copy"): def test_compresscopy(self): # Test copying a compression object @@ -10,6 +10,9 @@ What's New in Python 3.2.4 Core and Builtins ----------------- +- Issue #15001: fix segfault on "del sys.module['__main__']". Patch by Victor + Stinner. + - Issue #5057: the peepholer no longer optimizes subscription on unicode literals (e.g. u'foo'[0]) in order to produce compatible pyc files between narrow and wide builds. @@ -156,6 +159,10 @@ Core and Builtins Library ------- +- Issue #16350: zlib.Decompress.decompress() now accumulates data from + successive calls after EOF in unused_data, instead of only saving the argument + to the last call. Patch by Serhiy Storchaka. + - Issue #12759: sre_parse now raises a proper error when the name of the group is missing. Initial patch by Serhiy Storchaka. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index a1e605b..7734ba6 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -610,12 +610,29 @@ PyZlib_objdecompress(compobject *self, PyObject *args) preserved. */ if (err == Z_STREAM_END) { - Py_XDECREF(self->unused_data); /* Free original empty string */ - self->unused_data = PyBytes_FromStringAndSize( - (char *)self->zst.next_in, self->zst.avail_in); - if (self->unused_data == NULL) { - Py_DECREF(RetVal); - goto error; + if (self->zst.avail_in > 0) { + /* Append the leftover data to the existing value of unused_data. */ + Py_ssize_t old_size = PyBytes_GET_SIZE(self->unused_data); + Py_ssize_t new_size = old_size + self->zst.avail_in; + PyObject *new_data; + if (new_size <= old_size) { /* Check for overflow. */ + PyErr_NoMemory(); + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + new_data = PyBytes_FromStringAndSize(NULL, new_size); + if (new_data == NULL) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + Py_MEMCPY(PyBytes_AS_STRING(new_data), + PyBytes_AS_STRING(self->unused_data), old_size); + Py_MEMCPY(PyBytes_AS_STRING(new_data) + old_size, + self->zst.next_in, self->zst.avail_in); + Py_DECREF(self->unused_data); + self->unused_data = new_data; } /* We will only get Z_BUF_ERROR if the output buffer was full but there wasn't more output when we tried again, so it is diff --git a/Python/pythonrun.c b/Python/pythonrun.c index cf4e34c..3639fa7 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1257,25 +1257,26 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, { PyObject *m, *d, *v; const char *ext; - int set_file_name = 0, ret; + int set_file_name = 0, ret = -1; size_t len; m = PyImport_AddModule("__main__"); if (m == NULL) return -1; + Py_INCREF(m); d = PyModule_GetDict(m); if (PyDict_GetItemString(d, "__file__") == NULL) { PyObject *f; f = PyUnicode_DecodeFSDefault(filename); if (f == NULL) - return -1; + goto done; if (PyDict_SetItemString(d, "__file__", f) < 0) { Py_DECREF(f); - return -1; + goto done; } if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) { Py_DECREF(f); - return -1; + goto done; } set_file_name = 1; Py_DECREF(f); @@ -1288,7 +1289,6 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, fclose(fp); if ((fp = fopen(filename, "rb")) == NULL) { fprintf(stderr, "python: Can't reopen .pyc file\n"); - ret = -1; goto done; } /* Turn on optimization if a .pyo file is given */ @@ -1302,7 +1302,6 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, flush_io(); if (v == NULL) { PyErr_Print(); - ret = -1; goto done; } Py_DECREF(v); @@ -1310,6 +1309,7 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, done: if (set_file_name && PyDict_DelItemString(d, "__file__")) PyErr_Clear(); + Py_DECREF(m); return ret; } |