Index: Lib/test/test_fileio.py =================================================================== --- Lib/test/test_fileio.py (revision 85314) +++ Lib/test/test_fileio.py (working copy) @@ -398,6 +398,22 @@ self.assertRaises(ValueError, _FileIO, "/some/invalid/name", "rt") self.assertEqual(w.warnings, []) + def testUnclosedFDOnException(self): + class MyException(Exception): pass + class MyFileIO(_FileIO): + def __setattr__(self, name, value): + if name == "name": + raise MyException("blocked setting name") + return super(MyFileIO, self).__setattr__(name, value) + fd = os.open(__file__, os.O_RDONLY) + try: + MyFileIO(fd) + except MyException: + pass + else: + self.skipTest("MyException was not raised") + # exception set is cleared here. MyFileIO's dealloc is called + self.assertIsNone(os.close(fd)) # should not raise IOError(EBADF) def test_main(): # Historically, these tests have been sloppy about removing TESTFN. Index: Modules/_io/fileio.c =================================================================== --- Modules/_io/fileio.c (revision 85314) +++ Modules/_io/fileio.c (working copy) @@ -325,27 +325,25 @@ if (fd >= 0) { if (check_fd(fd)) goto error; - self->fd = fd; - self->closefd = closefd; } else { - self->closefd = 1; if (!closefd) { PyErr_SetString(PyExc_ValueError, "Cannot use closefd=False with file name"); goto error; } + closefd = 1; Py_BEGIN_ALLOW_THREADS errno = 0; #ifdef MS_WINDOWS if (widename != NULL) - self->fd = _wopen(widename, flags, 0666); + fd = _wopen(widename, flags, 0666); else #endif - self->fd = open(name, flags, 0666); + fd = open(name, flags, 0666); Py_END_ALLOW_THREADS - if (self->fd < 0) { + if (fd < 0) { #ifdef MS_WINDOWS if (widename != NULL) PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename); @@ -365,12 +363,14 @@ /* For consistent behaviour, we explicitly seek to the end of file (otherwise, it might be done only on the first write()). */ - PyObject *pos = portable_lseek(self->fd, NULL, 2); + PyObject *pos = portable_lseek(fd, NULL, 2); if (pos == NULL) goto error; Py_DECREF(pos); } + self->fd = fd; + self->closefd = closefd; goto done; error: