Commit 9e284c00 authored by Benjamin Peterson's avatar Benjamin Peterson

when an exception is raised in fdopen, never close the fd (changing on my mind on #21191)

parent f94f11ba
...@@ -465,7 +465,7 @@ These functions create new file objects. (See also :func:`open`.) ...@@ -465,7 +465,7 @@ These functions create new file objects. (See also :func:`open`.)
Return an open file object connected to the file descriptor *fd*. The *mode* Return an open file object connected to the file descriptor *fd*. The *mode*
and *bufsize* arguments have the same meaning as the corresponding arguments and *bufsize* arguments have the same meaning as the corresponding arguments
to the built-in :func:`open` function. If :func:`fdopen` raises an to the built-in :func:`open` function. If :func:`fdopen` raises an
exception, it closes *fd*. exception, it leaves *fd* untouched (unclosed).
Availability: Unix, Windows. Availability: Unix, Windows.
......
...@@ -196,7 +196,7 @@ class PosixTester(unittest.TestCase): ...@@ -196,7 +196,7 @@ class PosixTester(unittest.TestCase):
fd = os.open(test_support.TESTFN, os.O_RDONLY) fd = os.open(test_support.TESTFN, os.O_RDONLY)
self.assertRaises(OSError, posix.fdopen, fd, 'w') self.assertRaises(OSError, posix.fdopen, fd, 'w')
self.assertRaises(OSError, os.close, fd) # fd should be closed. os.close(fd) # fd should not be closed.
@unittest.skipUnless(hasattr(posix, 'O_EXLOCK'), @unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
'test needs posix.O_EXLOCK') 'test needs posix.O_EXLOCK')
......
...@@ -51,7 +51,7 @@ Library ...@@ -51,7 +51,7 @@ Library
- Issue #21172: isinstance check relaxed from dict to collections.Mapping. - Issue #21172: isinstance check relaxed from dict to collections.Mapping.
- Issue #21191: In os.fdopen, alwyas close the file descriptor when an exception - Issue #21191: In os.fdopen, never close the file descriptor when an exception
happens. happens.
- Issue #21149: Improved thread-safety in logging cleanup during interpreter - Issue #21149: Improved thread-safety in logging cleanup during interpreter
......
...@@ -6841,19 +6841,37 @@ posix_fdopen(PyObject *self, PyObject *args) ...@@ -6841,19 +6841,37 @@ posix_fdopen(PyObject *self, PyObject *args)
/* Sanitize mode. See fileobject.c */ /* Sanitize mode. See fileobject.c */
mode = PyMem_MALLOC(strlen(orgmode)+3); mode = PyMem_MALLOC(strlen(orgmode)+3);
if (!mode) { if (!mode) {
close(fd);
PyErr_NoMemory(); PyErr_NoMemory();
return NULL; return NULL;
} }
strcpy(mode, orgmode); strcpy(mode, orgmode);
if (_PyFile_SanitizeMode(mode)) { if (_PyFile_SanitizeMode(mode)) {
close(fd);
PyMem_FREE(mode); PyMem_FREE(mode);
return NULL; return NULL;
} }
if (!_PyVerify_fd(fd)) { if (!_PyVerify_fd(fd)) {
posix_error(); PyMem_FREE(mode);
close(fd); return posix_error();
}
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
{
struct stat buf;
if (fstat(fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
PyMem_FREE(mode);
char *msg = strerror(EISDIR);
PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)",
EISDIR, msg, "<fdopen>");
PyErr_SetObject(PyExc_IOError, exc);
Py_XDECREF(exc);
return NULL;
}
}
#endif
/* 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(NULL, "<fdopen>", orgmode, fclose);
if (f == NULL) {
PyMem_FREE(mode);
return NULL; return NULL;
} }
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
...@@ -6876,15 +6894,10 @@ posix_fdopen(PyObject *self, PyObject *args) ...@@ -6876,15 +6894,10 @@ posix_fdopen(PyObject *self, PyObject *args)
#endif #endif
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
PyMem_FREE(mode); PyMem_FREE(mode);
if (fp == NULL) { if (fp == NULL)
posix_error(); return posix_error();
close(fd); /* We now know we will succeed, so initialize the file object. */
return NULL; ((PyFileObject *)f)->f_fp = fp;
}
/* 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);
if (f != NULL)
PyFile_SetBufSize(f, bufsize); PyFile_SetBufSize(f, bufsize);
return f; return f;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment