Commit 05b0a1be authored by Serhiy Storchaka's avatar Serhiy Storchaka

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

parent 6453a01a
...@@ -192,38 +192,45 @@ def open(file, mode="r", buffering=-1, ...@@ -192,38 +192,45 @@ def open(file, mode="r", buffering=-1,
(appending and "a" or "") + (appending and "a" or "") +
(updating and "+" or ""), (updating and "+" or ""),
closefd) closefd)
line_buffering = False result = raw
if buffering == 1 or buffering < 0 and raw.isatty(): try:
buffering = -1 line_buffering = False
line_buffering = True if buffering == 1 or buffering < 0 and raw.isatty():
if buffering < 0: buffering = -1
buffering = DEFAULT_BUFFER_SIZE line_buffering = True
try: if buffering < 0:
bs = os.fstat(raw.fileno()).st_blksize buffering = DEFAULT_BUFFER_SIZE
except (os.error, AttributeError): try:
pass 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: else:
if bs > 1: raise ValueError("unknown mode: %r" % mode)
buffering = bs result = buffer
if buffering < 0:
raise ValueError("invalid buffering size")
if buffering == 0:
if binary: if binary:
return raw return result
raise ValueError("can't have unbuffered text I/O") text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
if updating: result = text
buffer = BufferedRandom(raw, buffering) text.mode = mode
elif writing or appending: return result
buffer = BufferedWriter(raw, buffering) except:
elif reading: result.close()
buffer = BufferedReader(raw, buffering) raise
else:
raise ValueError("unknown mode: %r" % mode)
if binary:
return buffer
text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
text.mode = mode
return text
class DocDescriptor: class DocDescriptor:
......
...@@ -29,6 +29,7 @@ import array ...@@ -29,6 +29,7 @@ import array
import random import random
import unittest import unittest
import weakref import weakref
import warnings
import abc import abc
import signal import signal
import errno import errno
...@@ -603,6 +604,20 @@ class IOTest(unittest.TestCase): ...@@ -603,6 +604,20 @@ class IOTest(unittest.TestCase):
fileio.close() fileio.close()
f2.readline() 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): class CIOTest(IOTest):
......
...@@ -25,6 +25,8 @@ Core and Builtins ...@@ -25,6 +25,8 @@ Core and Builtins
Library Library
------- -------
- Issue #21310: Fixed possible resource leak in failed open().
- Issue #21304: Backport the key derivation function hashlib.pbkdf2_hmac from - Issue #21304: Backport the key derivation function hashlib.pbkdf2_hmac from
Python 3 per PEP 466. Python 3 per PEP 466.
......
...@@ -303,7 +303,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -303,7 +303,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
int line_buffering; int line_buffering;
long isatty; 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, if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist,
&file, &mode, &buffering, &file, &mode, &buffering,
...@@ -416,6 +416,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -416,6 +416,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
"Osi", file, rawmode, closefd); "Osi", file, rawmode, closefd);
if (raw == NULL) if (raw == NULL)
return NULL; return NULL;
result = raw;
modeobj = PyUnicode_FromString(mode); modeobj = PyUnicode_FromString(mode);
if (modeobj == NULL) if (modeobj == NULL)
...@@ -474,7 +475,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -474,7 +475,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
} }
Py_DECREF(modeobj); Py_DECREF(modeobj);
return raw; return result;
} }
/* wraps into a buffered file */ /* wraps into a buffered file */
...@@ -495,15 +496,16 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -495,15 +496,16 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering); buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
} }
Py_CLEAR(raw);
if (buffer == NULL) if (buffer == NULL)
goto error; goto error;
result = buffer;
Py_DECREF(raw);
/* if binary, returns the buffered file */ /* if binary, returns the buffered file */
if (binary) { if (binary) {
Py_DECREF(modeobj); Py_DECREF(modeobj);
return buffer; return result;
} }
/* wraps into a TextIOWrapper */ /* wraps into a TextIOWrapper */
...@@ -512,20 +514,30 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -512,20 +514,30 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
buffer, buffer,
encoding, errors, newline, encoding, errors, newline,
line_buffering); line_buffering);
Py_CLEAR(buffer);
if (wrapper == NULL) if (wrapper == NULL)
goto error; goto error;
result = wrapper;
Py_DECREF(buffer);
if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0) if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0)
goto error; goto error;
Py_DECREF(modeobj); Py_DECREF(modeobj);
return wrapper; return result;
error: 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(modeobj);
Py_XDECREF(buffer);
Py_XDECREF(wrapper);
return NULL; return NULL;
} }
......
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