From 8b4367ec10c0518b06a8291f4313ef7677d85988 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Mon, 11 Apr 2011 03:44:28 +0300 Subject: [PATCH] #4877: Fix a segfault in xml.parsers.expat while attempting to parse a closed file. --- Lib/test/test_pyexpat.py | 11 +++++++++++ Misc/NEWS | 5 ++++- Modules/pyexpat.c | 38 ++++++++++++-------------------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index 840a7a83559..75b031ac178 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -6,6 +6,7 @@ import unittest from xml.parsers import expat +from test import test_support from test.test_support import sortdict, run_unittest @@ -217,6 +218,16 @@ class ParseTest(unittest.TestCase): self.assertEqual(op[15], "External entity ref: (None, u'entity.file', None)") self.assertEqual(op[16], "End element: u'root'") + # Issue 4877: expat.ParseFile causes segfault on a closed file. + fp = open(test_support.TESTFN, 'wb') + try: + fp.close() + parser = expat.ParserCreate() + with self.assertRaises(ValueError): + parser.ParseFile(fp) + finally: + test_support.unlink(test_support.TESTFN) + class NamespaceSeparatorTest(unittest.TestCase): def test_legal(self): diff --git a/Misc/NEWS b/Misc/NEWS index 5eb38dabd82..c34428d2a9e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,11 +51,14 @@ Core and Builtins Library ------- +- Issue #4877: Fix a segfault in xml.parsers.expat while attempting to parse + a closed file. + - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating worker processes: new processes would be spawned while the pool is being shut down. Patch by Charles-François Natali. -- Issue #7311: fix HTMLParser to accept non-ASCII attribute values. +- Issue #7311: Fix HTMLParser to accept non-ASCII attribute values. - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 0555b6d662a..af85582ab8c 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -962,21 +962,15 @@ static PyObject * xmlparse_ParseFile(xmlparseobject *self, PyObject *f) { int rv = 1; - FILE *fp; PyObject *readmethod = NULL; - if (PyFile_Check(f)) { - fp = PyFile_AsFile(f); - } - else { - fp = NULL; - readmethod = PyObject_GetAttrString(f, "read"); - if (readmethod == NULL) { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, - "argument must have 'read' attribute"); - return NULL; - } + readmethod = PyObject_GetAttrString(f, "read"); + if (readmethod == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "argument must have 'read' attribute"); + return NULL; + } for (;;) { int bytes_read; @@ -986,20 +980,12 @@ xmlparse_ParseFile(xmlparseobject *self, PyObject *f) return PyErr_NoMemory(); } - if (fp) { - bytes_read = fread(buf, sizeof(char), BUF_SIZE, fp); - if (bytes_read < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - } - else { - bytes_read = readinst(buf, BUF_SIZE, readmethod); - if (bytes_read < 0) { - Py_XDECREF(readmethod); - return NULL; - } + bytes_read = readinst(buf, BUF_SIZE, readmethod); + if (bytes_read < 0) { + Py_XDECREF(readmethod); + return NULL; } + rv = XML_ParseBuffer(self->itself, bytes_read, bytes_read == 0); if (PyErr_Occurred()) { Py_XDECREF(readmethod);