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,
(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:
......
......@@ -29,6 +29,7 @@ import array
import random
import unittest
import weakref
import warnings
import abc
import signal
import errno
......@@ -603,6 +604,20 @@ class IOTest(unittest.TestCase):
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):
......
......@@ -25,6 +25,8 @@ Core and Builtins
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.
......
......@@ -303,7 +303,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
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 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
"Osi", file, rawmode, closefd);
if (raw == NULL)
return NULL;
result = raw;
modeobj = PyUnicode_FromString(mode);
if (modeobj == NULL)
......@@ -474,7 +475,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
}
Py_DECREF(modeobj);
return raw;
return result;
}
/* wraps into a buffered file */
......@@ -495,15 +496,16 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
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 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
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;
}
......
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