[Python-checkins] cpython (2.7): when an exception is raised in fdopen, never close the fd (changing on my mind

benjamin.peterson python-checkins at python.org
Tue Apr 15 01:46:09 CEST 2014


http://hg.python.org/cpython/rev/339c79791b65
changeset:   90307:339c79791b65
branch:      2.7
user:        Benjamin Peterson <benjamin at python.org>
date:        Mon Apr 14 19:45:46 2014 -0400
summary:
  when an exception is raised in fdopen, never close the fd (changing on my mind on #21191)

files:
  Doc/library/os.rst     |   2 +-
  Lib/test/test_posix.py |   2 +-
  Misc/NEWS              |   2 +-
  Modules/posixmodule.c  |  41 +++++++++++++++++++----------
  4 files changed, 30 insertions(+), 17 deletions(-)


diff --git a/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -465,7 +465,7 @@
    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.  If :func:`fdopen` raises an
-   exception, it closes *fd*.
+   exception, it leaves *fd* untouched (unclosed).
 
    Availability: Unix, Windows.
 
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -196,7 +196,7 @@
 
         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.
+        os.close(fd) # fd should not be closed.
 
     @unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
                          'test needs posix.O_EXLOCK')
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -51,7 +51,7 @@
 
 - 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.
 
 - Issue #21149: Improved thread-safety in logging cleanup during interpreter
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -6841,19 +6841,37 @@
     /* 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)) {
-        posix_error();
-        close(fd);
+        PyMem_FREE(mode);
+        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;
     }
     Py_BEGIN_ALLOW_THREADS
@@ -6876,16 +6894,11 @@
 #endif
     Py_END_ALLOW_THREADS
     PyMem_FREE(mode);
-    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);
-    if (f != NULL)
-        PyFile_SetBufSize(f, bufsize);
+    if (fp == NULL)
+        return posix_error();
+    /* We now know we will succeed, so initialize the file object. */
+    ((PyFileObject *)f)->f_fp = fp;
+    PyFile_SetBufSize(f, bufsize);
     return f;
 }
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list