From 243757eb79fe4bee33882b1813cf33839117570f Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Fri, 5 Nov 2010 21:15:39 +0000 Subject: [PATCH] Issue #10180: Pickling file objects is now explicitly forbidden, since unpickling them produced nonsensical results. --- Lib/_pyio.py | 4 ++++ Lib/test/test_io.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ Modules/_io/bufferedio.c | 14 ++++++++++++++ Modules/_io/fileio.c | 9 +++++++++ Modules/_io/textio.c | 9 +++++++++ 6 files changed, 57 insertions(+) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 83bce709b5..87c833c964 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -747,6 +747,10 @@ class _BufferedIOMixin(BufferedIOBase): def mode(self): return self.raw.mode + def __getstate__(self): + raise TypeError("can not serialize a '{0}' object" + .format(self.__class__.__name__)) + def __repr__(self): clsname = self.__class__.__name__ try: diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 680e36dc8d..91dd8037b6 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -30,6 +30,7 @@ import abc import signal import errno import warnings +import pickle from itertools import cycle, count from collections import deque from test import support @@ -2566,6 +2567,23 @@ class MiscIOTest(unittest.TestCase): 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): io = io diff --git a/Misc/NEWS b/Misc/NEWS index af33d2838f..18c1cde754 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -65,6 +65,9 @@ Core and Builtins 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 its low-level signal handler. Patch by Hallvard B Furuseth. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 30451692b3..504e2cbd14 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -549,6 +549,15 @@ buffered_isatty(buffered *self, PyObject *args) 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 */ static PyObject * @@ -1489,6 +1498,7 @@ static PyMethodDef bufferedreader_methods[] = { {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, {"read", (PyCFunction)buffered_read, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, @@ -1872,6 +1882,7 @@ static PyMethodDef bufferedwriter_methods[] = { {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, @@ -2137,6 +2148,8 @@ static PyMethodDef bufferedrwpair_methods[] = { {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS}, {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS}, + {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, + {NULL, NULL} }; @@ -2257,6 +2270,7 @@ static PyMethodDef bufferedrandom_methods[] = { {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 09ea80f179..96fce15fef 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -952,6 +952,14 @@ fileio_isatty(fileio *self) 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, "file(name: str[, mode: str]) -> file IO object\n" @@ -1046,6 +1054,7 @@ static PyMethodDef fileio_methods[] = { {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, + {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index e222067a3a..2559714aaf 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -2382,6 +2382,14 @@ textiowrapper_isatty(textio *self, PyObject *args) 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 * textiowrapper_flush(textio *self, PyObject *args) { @@ -2546,6 +2554,7 @@ static PyMethodDef textiowrapper_methods[] = { {"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS}, {"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS}, {"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS}, + {"__getstate__", (PyCFunction)textiowrapper_getstate, METH_NOARGS}, {"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS}, {"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS}, -- 2.40.0