[Python-checkins] cpython (2.7): Issue #21310: Fixed possible resource leak in failed open().

serhiy.storchaka python-checkins at python.org
Mon Jun 9 12:52:09 CEST 2014


http://hg.python.org/cpython/rev/1e30ecbfe181
changeset: 91103:1e30ecbfe181
branch: 2.7
parent: 91095:8bafb707d549
user: Serhiy Storchaka <storchaka at gmail.com>
date: Mon Jun 09 13:32:08 2014 +0300
summary:
 Issue #21310: Fixed possible resource leak in failed open().
files:
 Lib/_pyio.py | 67 ++++++++++++++++------------
 Lib/test/test_io.py | 15 ++++++
 Misc/NEWS | 2 +
 Modules/_io/_iomodule.c | 30 +++++++++---
 4 files changed, 75 insertions(+), 39 deletions(-)
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -192,38 +192,45 @@
 (appending and "a" or "") +
 (updating and "+" or ""),
 closefd)
- line_buffering = False
- if buffering == 1 or buffering < 0 and raw.isatty():
- buffering = -1
- line_buffering = True
- if buffering < 0:
- buffering = DEFAULT_BUFFER_SIZE
- try:
- bs = os.fstat(raw.fileno()).st_blksize
- except (os.error, AttributeError):
- pass
+ result = raw
+ try:
+ line_buffering = False
+ if buffering == 1 or buffering < 0 and raw.isatty():
+ buffering = -1
+ line_buffering = True
+ if buffering < 0:
+ buffering = DEFAULT_BUFFER_SIZE
+ try:
+ bs = os.fstat(raw.fileno()).st_blksize
+ except (os.error, AttributeError):
+ pass
+ else:
+ if bs > 1:
+ buffering = bs
+ if buffering < 0:
+ raise ValueError("invalid buffering size")
+ if buffering == 0:
+ if binary:
+ return result
+ raise ValueError("can't have unbuffered text I/O")
+ if updating:
+ buffer = BufferedRandom(raw, buffering)
+ elif writing or appending:
+ buffer = BufferedWriter(raw, buffering)
+ elif reading:
+ buffer = BufferedReader(raw, buffering)
 else:
- if bs > 1:
- buffering = bs
- if buffering < 0:
- raise ValueError("invalid buffering size")
- if buffering == 0:
+ raise ValueError("unknown mode: %r" % mode)
+ result = buffer
 if binary:
- return raw
- raise ValueError("can't have unbuffered text I/O")
- if updating:
- buffer = BufferedRandom(raw, buffering)
- elif writing or appending:
- buffer = BufferedWriter(raw, buffering)
- elif reading:
- buffer = BufferedReader(raw, buffering)
- else:
- raise ValueError("unknown mode: %r" % mode)
- if binary:
- return buffer
- text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
- text.mode = mode
- return text
+ return result
+ text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
+ result = text
+ text.mode = mode
+ return result
+ except:
+ result.close()
+ raise
 
 
 class DocDescriptor:
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -29,6 +29,7 @@
 import random
 import unittest
 import weakref
+import warnings
 import abc
 import signal
 import errno
@@ -603,6 +604,20 @@
 fileio.close()
 f2.readline()
 
+ def test_nonbuffered_textio(self):
+ with warnings.catch_warnings(record=True) as recorded:
+ with self.assertRaises(ValueError):
+ self.open(support.TESTFN, 'w', buffering=0)
+ support.gc_collect()
+ self.assertEqual(recorded, [])
+
+ def test_invalid_newline(self):
+ with warnings.catch_warnings(record=True) as recorded:
+ with self.assertRaises(ValueError):
+ self.open(support.TESTFN, 'w', newline='invalid')
+ support.gc_collect()
+ self.assertEqual(recorded, [])
+
 
 class CIOTest(IOTest):
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -25,6 +25,8 @@
 Library
 -------
 
+- Issue #21310: Fixed possible resource leak in failed open().
+
 - Issue #21304: Backport the key derivation function hashlib.pbkdf2_hmac from
 Python 3 per PEP 466.
 
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -303,7 +303,7 @@
 int line_buffering;
 long isatty;
 
- PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL;
+ PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL;
 
 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist,
 &file, &mode, &buffering,
@@ -416,6 +416,7 @@
 				"Osi", file, rawmode, closefd);
 if (raw == NULL)
 return NULL;
+ result = raw;
 
 modeobj = PyUnicode_FromString(mode);
 if (modeobj == NULL)
@@ -474,7 +475,7 @@
 }
 
 Py_DECREF(modeobj);
- return raw;
+ return result;
 }
 
 /* wraps into a buffered file */
@@ -495,15 +496,16 @@
 
 buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
 }
- Py_CLEAR(raw);
 if (buffer == NULL)
 goto error;
+ result = buffer;
+ Py_DECREF(raw);
 
 
 /* if binary, returns the buffered file */
 if (binary) {
 Py_DECREF(modeobj);
- return buffer;
+ return result;
 }
 
 /* wraps into a TextIOWrapper */
@@ -512,20 +514,30 @@
 				 buffer,
 				 encoding, errors, newline,
 				 line_buffering);
- Py_CLEAR(buffer);
 if (wrapper == NULL)
 goto error;
+ result = wrapper;
+ Py_DECREF(buffer);
 
 if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0)
 goto error;
 Py_DECREF(modeobj);
- return wrapper;
+ return result;
 
 error:
- Py_XDECREF(raw);
+ if (result != NULL) {
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ if (PyObject_CallMethod(result, "close", NULL) != NULL)
+ PyErr_Restore(exc, val, tb);
+ else {
+ Py_XDECREF(exc);
+ Py_XDECREF(val);
+ Py_XDECREF(tb);
+ }
+ Py_DECREF(result);
+ }
 Py_XDECREF(modeobj);
- Py_XDECREF(buffer);
- Py_XDECREF(wrapper);
 return NULL;
 }
 
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /