Commit 243757eb authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #10180: Pickling file objects is now explicitly forbidden, since

unpickling them produced nonsensical results.
parent 4a5f9677
...@@ -747,6 +747,10 @@ class _BufferedIOMixin(BufferedIOBase): ...@@ -747,6 +747,10 @@ class _BufferedIOMixin(BufferedIOBase):
def mode(self): def mode(self):
return self.raw.mode return self.raw.mode
def __getstate__(self):
raise TypeError("can not serialize a '{0}' object"
.format(self.__class__.__name__))
def __repr__(self): def __repr__(self):
clsname = self.__class__.__name__ clsname = self.__class__.__name__
try: try:
......
...@@ -30,6 +30,7 @@ import abc ...@@ -30,6 +30,7 @@ import abc
import signal import signal
import errno import errno
import warnings import warnings
import pickle
from itertools import cycle, count from itertools import cycle, count
from collections import deque from collections import deque
from test import support from test import support
...@@ -2566,6 +2567,23 @@ class MiscIOTest(unittest.TestCase): ...@@ -2566,6 +2567,23 @@ class MiscIOTest(unittest.TestCase):
self._check_warn_on_dealloc_fd("r") self._check_warn_on_dealloc_fd("r")
def test_pickling(self):
# Pickling file objects is forbidden
for kwargs in [
{"mode": "w"},
{"mode": "wb"},
{"mode": "wb", "buffering": 0},
{"mode": "r"},
{"mode": "rb"},
{"mode": "rb", "buffering": 0},
{"mode": "w+"},
{"mode": "w+b"},
{"mode": "w+b", "buffering": 0},
]:
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
with self.open(support.TESTFN, **kwargs) as f:
self.assertRaises(TypeError, pickle.dumps, f, protocol)
class CMiscIOTest(MiscIOTest): class CMiscIOTest(MiscIOTest):
io = io io = io
......
...@@ -65,6 +65,9 @@ Core and Builtins ...@@ -65,6 +65,9 @@ Core and Builtins
Library Library
------- -------
- Issue #10180: Pickling file objects is now explicitly forbidden, since
unpickling them produced nonsensical results.
- Issue #10311: The signal module now restores errno before returning from - Issue #10311: The signal module now restores errno before returning from
its low-level signal handler. Patch by Hallvard B Furuseth. its low-level signal handler. Patch by Hallvard B Furuseth.
......
...@@ -549,6 +549,15 @@ buffered_isatty(buffered *self, PyObject *args) ...@@ -549,6 +549,15 @@ buffered_isatty(buffered *self, PyObject *args)
return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL); return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL);
} }
/* Serialization */
static PyObject *
buffered_getstate(buffered *self, PyObject *args)
{
PyErr_Format(PyExc_TypeError,
"cannot serialize '%s' object", Py_TYPE(self)->tp_name);
return NULL;
}
/* Forward decls */ /* Forward decls */
static PyObject * static PyObject *
...@@ -1489,6 +1498,7 @@ static PyMethodDef bufferedreader_methods[] = { ...@@ -1489,6 +1498,7 @@ static PyMethodDef bufferedreader_methods[] = {
{"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
{"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
{"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
{"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
{"read", (PyCFunction)buffered_read, METH_VARARGS}, {"read", (PyCFunction)buffered_read, METH_VARARGS},
{"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
...@@ -1872,6 +1882,7 @@ static PyMethodDef bufferedwriter_methods[] = { ...@@ -1872,6 +1882,7 @@ static PyMethodDef bufferedwriter_methods[] = {
{"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
{"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
{"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
{"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
{"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
{"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
...@@ -2137,6 +2148,8 @@ static PyMethodDef bufferedrwpair_methods[] = { ...@@ -2137,6 +2148,8 @@ static PyMethodDef bufferedrwpair_methods[] = {
{"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS}, {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS},
{"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS}, {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS},
{"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
{NULL, NULL} {NULL, NULL}
}; };
...@@ -2257,6 +2270,7 @@ static PyMethodDef bufferedrandom_methods[] = { ...@@ -2257,6 +2270,7 @@ static PyMethodDef bufferedrandom_methods[] = {
{"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
{"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
{"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
{"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
{"flush", (PyCFunction)buffered_flush, METH_NOARGS}, {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
......
...@@ -952,6 +952,14 @@ fileio_isatty(fileio *self) ...@@ -952,6 +952,14 @@ fileio_isatty(fileio *self)
return PyBool_FromLong(res); return PyBool_FromLong(res);
} }
static PyObject *
fileio_getstate(fileio *self)
{
PyErr_Format(PyExc_TypeError,
"cannot serialize '%s' object", Py_TYPE(self)->tp_name);
return NULL;
}
PyDoc_STRVAR(fileio_doc, PyDoc_STRVAR(fileio_doc,
"file(name: str[, mode: str]) -> file IO object\n" "file(name: str[, mode: str]) -> file IO object\n"
...@@ -1046,6 +1054,7 @@ static PyMethodDef fileio_methods[] = { ...@@ -1046,6 +1054,7 @@ static PyMethodDef fileio_methods[] = {
{"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
{"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
{"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
{"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
......
...@@ -2382,6 +2382,14 @@ textiowrapper_isatty(textio *self, PyObject *args) ...@@ -2382,6 +2382,14 @@ textiowrapper_isatty(textio *self, PyObject *args)
return PyObject_CallMethod(self->buffer, "isatty", NULL); return PyObject_CallMethod(self->buffer, "isatty", NULL);
} }
static PyObject *
textiowrapper_getstate(textio *self, PyObject *args)
{
PyErr_Format(PyExc_TypeError,
"cannot serialize '%s' object", Py_TYPE(self)->tp_name);
return NULL;
}
static PyObject * static PyObject *
textiowrapper_flush(textio *self, PyObject *args) textiowrapper_flush(textio *self, PyObject *args)
{ {
...@@ -2546,6 +2554,7 @@ static PyMethodDef textiowrapper_methods[] = { ...@@ -2546,6 +2554,7 @@ static PyMethodDef textiowrapper_methods[] = {
{"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS}, {"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS},
{"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS}, {"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS},
{"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS}, {"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS},
{"__getstate__", (PyCFunction)textiowrapper_getstate, METH_NOARGS},
{"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS}, {"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS},
{"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS}, {"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS},
......
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