make sure fdopen always closes the fd in error cases (closes #21191)

This commit is contained in:
Benjamin Peterson 2014-04-09 15:40:18 -04:00
parent d546009677
commit 02ab7a84ef
4 changed files with 22 additions and 6 deletions

View File

@ -463,8 +463,9 @@ These functions create new file objects. (See also :func:`open`.)
.. index:: single: I/O control; buffering
Return an open file object connected to the file descriptor *fd*. The *mode*
and *bufsize* arguments have the same meaning as the corresponding arguments to
the built-in :func:`open` function.
and *bufsize* arguments have the same meaning as the corresponding arguments
to the built-in :func:`open` function. If :func:`fdopen` raises an
exception, it closes *fd*.
Availability: Unix, Windows.

View File

@ -194,6 +194,10 @@ class PosixTester(unittest.TestCase):
self.fdopen_helper('r')
self.fdopen_helper('r', 100)
fd = os.open(test_support.TESTFN, os.O_RDONLY)
self.assertRaises(OSError, posix.fdopen, fd, 'w')
self.assertRaises(OSError, os.close, fd) # fd should be closed.
@unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
'test needs posix.O_EXLOCK')
def test_osexlock(self):

View File

@ -43,6 +43,9 @@ Core and Builtins
Library
-------
- Issue #21191: In os.fdopen, alwyas close the file descriptor when an exception
happens.
- Issue #21149: Improved thread-safety in logging cleanup during interpreter
shutdown. Thanks to Devin Jeanpierre for the patch.

View File

@ -6841,16 +6841,21 @@ posix_fdopen(PyObject *self, PyObject *args)
/* Sanitize mode. See fileobject.c */
mode = PyMem_MALLOC(strlen(orgmode)+3);
if (!mode) {
close(fd);
PyErr_NoMemory();
return NULL;
}
strcpy(mode, orgmode);
if (_PyFile_SanitizeMode(mode)) {
close(fd);
PyMem_FREE(mode);
return NULL;
}
if (!_PyVerify_fd(fd))
return posix_error();
if (!_PyVerify_fd(fd)) {
posix_error();
close(fd);
return NULL;
}
Py_BEGIN_ALLOW_THREADS
#if !defined(MS_WINDOWS) && defined(HAVE_FCNTL_H)
if (mode[0] == 'a') {
@ -6871,8 +6876,11 @@ posix_fdopen(PyObject *self, PyObject *args)
#endif
Py_END_ALLOW_THREADS
PyMem_FREE(mode);
if (fp == NULL)
return posix_error();
if (fp == NULL) {
posix_error();
close(fd);
return NULL;
}
/* The dummy filename used here must be kept in sync with the value
tested against in gzip.GzipFile.__init__() - see issue #13781. */
f = PyFile_FromFile(fp, "<fdopen>", orgmode, fclose);