[pypy-commit] pypy py3.5: Python Issue #21310: Fixed possible resource leak in failed open()

amauryfa pypy.commits at gmail.com
Tue Apr 18 18:55:30 EDT 2017


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.5
Changeset: r91086:af84269c028b
Date: 2017-04-18 18:37 +0200
http://bitbucket.org/pypy/pypy/changeset/af84269c028b/

Log:	Python Issue #21310: Fixed possible resource leak in failed open()

diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py
--- a/pypy/module/_io/interp_io.py
+++ b/pypy/module/_io/interp_io.py
@@ -86,46 +86,61 @@
     if binary and newline is not None:
         raise oefmt(space.w_ValueError,
                     "binary mode doesn't take a newline argument")
-    w_raw = space.call_function(
-        space.gettypefor(W_FileIO), w_file, space.newtext(rawmode),
-        space.newbool(bool(closefd)), w_opener)
 
-    isatty = space.is_true(space.call_method(w_raw, "isatty"))
-    line_buffering = buffering == 1 or (buffering < 0 and isatty)
-    if line_buffering:
-        buffering = -1
+    w_result = None
+    try:
+        w_raw = space.call_function(
+            space.gettypefor(W_FileIO), w_file, space.newtext(rawmode),
+            space.newbool(bool(closefd)), w_opener)
+        w_result = w_raw
 
-    if buffering < 0:
-        buffering = space.c_int_w(space.getattr(w_raw, space.newtext("_blksize")))
+        isatty = space.is_true(space.call_method(w_raw, "isatty"))
+        line_buffering = buffering == 1 or (buffering < 0 and isatty)
+        if line_buffering:
+            buffering = -1
 
-    if buffering < 0:
-        raise oefmt(space.w_ValueError, "invalid buffering size")
+        if buffering < 0:
+            buffering = space.c_int_w(space.getattr(
+                w_raw, space.newtext("_blksize")))
 
-    if buffering == 0:
-        if not binary:
-            raise oefmt(space.w_ValueError, "can't have unbuffered text I/O")
-        return w_raw
+        if buffering < 0:
+            raise oefmt(space.w_ValueError, "invalid buffering size")
 
-    if updating:
-        buffer_cls = W_BufferedRandom
-    elif writing or creating or appending:
-        buffer_cls = W_BufferedWriter
-    elif reading:
-        buffer_cls = W_BufferedReader
-    else:
-        raise oefmt(space.w_ValueError, "unknown mode: '%s'", mode)
-    w_buffer = space.call_function(
-        space.gettypefor(buffer_cls), w_raw, space.newint(buffering)
-    )
-    if binary:
-        return w_buffer
+        if buffering == 0:
+            if not binary:
+                raise oefmt(space.w_ValueError,
+                            "can't have unbuffered text I/O")
+            return w_result
 
-    w_wrapper = space.call_function(space.gettypefor(W_TextIOWrapper),
-        w_buffer,
-        space.newtext_or_none(encoding),
-        space.newtext_or_none(errors),
-        space.newtext_or_none(newline),
-        space.newbool(line_buffering)
-    )
-    space.setattr(w_wrapper, space.newtext("mode"), space.newtext(mode))
-    return w_wrapper
+        if updating:
+            buffer_cls = W_BufferedRandom
+        elif writing or creating or appending:
+            buffer_cls = W_BufferedWriter
+        elif reading:
+            buffer_cls = W_BufferedReader
+        else:
+            raise oefmt(space.w_ValueError, "unknown mode: '%s'", mode)
+        w_buffer = space.call_function(
+            space.gettypefor(buffer_cls), w_raw, space.newint(buffering)
+        )
+        w_result = w_buffer
+        if binary:
+            return w_result
+
+        w_wrapper = space.call_function(space.gettypefor(W_TextIOWrapper),
+            w_buffer,
+            space.newtext_or_none(encoding),
+            space.newtext_or_none(errors),
+            space.newtext_or_none(newline),
+            space.newbool(line_buffering)
+        )
+        w_result = w_wrapper
+        space.setattr(w_wrapper, space.newtext("mode"), space.newtext(mode))
+        return w_result
+    except OperationError as e:
+        if w_result:
+            try:
+                space.call_method(w_result, "close")
+            except OperationError as e2:
+                e.chain_exceptions(space, e2)
+        raise
diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py
--- a/pypy/module/_io/test/test_io.py
+++ b/pypy/module/_io/test/test_io.py
@@ -474,6 +474,22 @@
             assert f.mode == 'x'
         raises(FileExistsError, _io.open, filename, 'x')
 
+    def test_nonbuffered_textio(self):
+        import warnings, _io as io
+        filename = self.tmpfile + '_x2'
+        warnings.simplefilter("always", category=ResourceWarning)
+        with warnings.catch_warnings(record=True) as recorded:
+            raises(ValueError, io.open, filename, 'w', buffering=0)
+        assert recorded == []
+
+    def test_invalid_newline(self):
+        import warnings, _io as io
+        filename = self.tmpfile + '_x2'
+        warnings.simplefilter("always", category=ResourceWarning)
+        with warnings.catch_warnings(record=True) as recorded:
+            raises(ValueError, io.open, filename, 'w', newline='invalid')
+        assert recorded == []
+
 
 class AppTestIoAferClose:
     spaceconfig = dict(usemodules=['_io'])


More information about the pypy-commit mailing list