Issue #21310: Fixed possible resource leak in failed open().
This commit is contained in:
parent
8a8f7f9830
commit
f10063e3c3
67
Lib/_pyio.py
67
Lib/_pyio.py
|
@ -200,38 +200,45 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None,
|
|||
(appending and "a" or "") +
|
||||
(updating and "+" or ""),
|
||||
closefd, opener=opener)
|
||||
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 (OSError, 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 (OSError, 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 creating or 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 creating or 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:
|
||||
|
|
|
@ -653,6 +653,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):
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #21310: Fixed possible resource leak in failed open().
|
||||
|
||||
- Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
|
||||
|
||||
- Issue #11709: Fix the pydoc.help function to not fail when sys.stdin is not a
|
||||
|
|
|
@ -235,11 +235,12 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
char rawmode[6], *m;
|
||||
int line_buffering, isatty;
|
||||
|
||||
PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL;
|
||||
PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL;
|
||||
|
||||
_Py_IDENTIFIER(isatty);
|
||||
_Py_IDENTIFIER(fileno);
|
||||
_Py_IDENTIFIER(mode);
|
||||
_Py_IDENTIFIER(close);
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzziO:open", kwlist,
|
||||
&file, &mode, &buffering,
|
||||
|
@ -354,6 +355,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
"OsiO", file, rawmode, closefd, opener);
|
||||
if (raw == NULL)
|
||||
return NULL;
|
||||
result = raw;
|
||||
|
||||
modeobj = PyUnicode_FromString(mode);
|
||||
if (modeobj == NULL)
|
||||
|
@ -412,7 +414,7 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
|
||||
Py_DECREF(modeobj);
|
||||
return raw;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* wraps into a buffered file */
|
||||
|
@ -433,15 +435,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 */
|
||||
|
@ -450,20 +453,35 @@ 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_SetAttrId(wrapper, &PyId_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_CallMethodId(result, &PyId_close, NULL) != NULL)
|
||||
PyErr_Restore(exc, val, tb);
|
||||
else {
|
||||
PyObject *val2;
|
||||
PyErr_NormalizeException(&exc, &val, &tb);
|
||||
Py_XDECREF(exc);
|
||||
Py_XDECREF(tb);
|
||||
PyErr_Fetch(&exc, &val2, &tb);
|
||||
PyErr_NormalizeException(&exc, &val2, &tb);
|
||||
PyException_SetContext(val2, val);
|
||||
PyErr_Restore(exc, val2, tb);
|
||||
}
|
||||
Py_DECREF(result);
|
||||
}
|
||||
Py_XDECREF(modeobj);
|
||||
Py_XDECREF(buffer);
|
||||
Py_XDECREF(wrapper);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue