summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-11-05 21:15:39 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2010-11-05 21:15:39 (GMT)
commit243757eb79fe4bee33882b1813cf33839117570f (patch)
treea9403be5a75dedbb5c5b6ea4ee563b7155c707fd
parent4a5f9677f31d75454ec10a0baefef37b63568a31 (diff)
downloadcpython-243757eb79fe4bee33882b1813cf33839117570f.zip
cpython-243757eb79fe4bee33882b1813cf33839117570f.tar.gz
cpython-243757eb79fe4bee33882b1813cf33839117570f.tar.bz2
Issue #10180: Pickling file objects is now explicitly forbidden, since
unpickling them produced nonsensical results.
-rw-r--r--Lib/_pyio.py4
-rw-r--r--Lib/test/test_io.py18
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_io/bufferedio.c14
-rw-r--r--Modules/_io/fileio.c9
-rw-r--r--Modules/_io/textio.c9
6 files changed, 57 insertions, 0 deletions
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index 83bce70..87c833c 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 680e36d..91dd803 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 af33d28..18c1cde 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 3045169..504e2cb 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 09ea80f..96fce15 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 e222067..2559714 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -2383,6 +2383,14 @@ textiowrapper_isatty(textio *self, PyObject *args)
}
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)
{
CHECK_INITIALIZED(self);
@@ -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},