Issue #22995: Instances of extension types with a state that aren't
subclasses of list or dict and haven't implemented any pickle-related methods (__reduce__, __reduce_ex__, __getnewargs__, __getnewargs_ex__, or __getstate__), can no longer be pickled. Including memoryview.
This commit is contained in:
commit
f9253c96fd
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2001,2002 Python Software Foundation
|
# Copyright (C) 2001,2002 Python Software Foundation
|
||||||
# csv package unit tests
|
# csv package unit tests
|
||||||
|
|
||||||
|
import copy
|
||||||
import io
|
import io
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
@ -9,6 +10,7 @@ from io import StringIO
|
||||||
from tempfile import TemporaryFile
|
from tempfile import TemporaryFile
|
||||||
import csv
|
import csv
|
||||||
import gc
|
import gc
|
||||||
|
import pickle
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
class Test_Csv(unittest.TestCase):
|
class Test_Csv(unittest.TestCase):
|
||||||
|
@ -424,6 +426,17 @@ class TestDialectRegistry(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, csv.reader, [], quoting = -1)
|
self.assertRaises(TypeError, csv.reader, [], quoting = -1)
|
||||||
self.assertRaises(TypeError, csv.reader, [], quoting = 100)
|
self.assertRaises(TypeError, csv.reader, [], quoting = 100)
|
||||||
|
|
||||||
|
def test_copy(self):
|
||||||
|
for name in csv.list_dialects():
|
||||||
|
dialect = csv.get_dialect(name)
|
||||||
|
self.assertRaises(TypeError, copy.copy, dialect)
|
||||||
|
|
||||||
|
def test_pickle(self):
|
||||||
|
for name in csv.list_dialects():
|
||||||
|
dialect = csv.get_dialect(name)
|
||||||
|
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
self.assertRaises(TypeError, pickle.dumps, dialect, proto)
|
||||||
|
|
||||||
class TestCsvBase(unittest.TestCase):
|
class TestCsvBase(unittest.TestCase):
|
||||||
def readerAssertEqual(self, input, expected_result):
|
def readerAssertEqual(self, input, expected_result):
|
||||||
with TemporaryFile("w+", newline='') as fileobj:
|
with TemporaryFile("w+", newline='') as fileobj:
|
||||||
|
|
|
@ -11,6 +11,8 @@ import gc
|
||||||
import weakref
|
import weakref
|
||||||
import array
|
import array
|
||||||
import io
|
import io
|
||||||
|
import copy
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
class AbstractMemoryTests:
|
class AbstractMemoryTests:
|
||||||
|
@ -519,6 +521,17 @@ class OtherTest(unittest.TestCase):
|
||||||
m2 = m1[::-1]
|
m2 = m1[::-1]
|
||||||
self.assertEqual(m2.hex(), '30' * 200000)
|
self.assertEqual(m2.hex(), '30' * 200000)
|
||||||
|
|
||||||
|
def test_copy(self):
|
||||||
|
m = memoryview(b'abc')
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
copy.copy(m)
|
||||||
|
|
||||||
|
def test_pickle(self):
|
||||||
|
m = memoryview(b'abc')
|
||||||
|
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
pickle.dumps(m, proto)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -10,6 +10,11 @@ Release date: tba
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #22995: Instances of extension types with a state that aren't
|
||||||
|
subclasses of list or dict and haven't implemented any pickle-related
|
||||||
|
methods (__reduce__, __reduce_ex__, __getnewargs__, __getnewargs_ex__,
|
||||||
|
or __getstate__), can no longer be pickled. Including memoryview.
|
||||||
|
|
||||||
- Issue #20440: Massive replacing unsafe attribute setting code with special
|
- Issue #20440: Massive replacing unsafe attribute setting code with special
|
||||||
macro Py_SETREF.
|
macro Py_SETREF.
|
||||||
|
|
||||||
|
|
|
@ -3839,7 +3839,7 @@ _PyType_GetSlotNames(PyTypeObject *cls)
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_LOCAL(PyObject *)
|
Py_LOCAL(PyObject *)
|
||||||
_PyObject_GetState(PyObject *obj)
|
_PyObject_GetState(PyObject *obj, int required)
|
||||||
{
|
{
|
||||||
PyObject *state;
|
PyObject *state;
|
||||||
PyObject *getstate;
|
PyObject *getstate;
|
||||||
|
@ -3854,6 +3854,13 @@ _PyObject_GetState(PyObject *obj)
|
||||||
}
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
|
||||||
|
if (required && obj->ob_type->tp_itemsize) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"can't pickle %.200s objects",
|
||||||
|
Py_TYPE(obj)->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
PyObject **dict;
|
PyObject **dict;
|
||||||
dict = _PyObject_GetDictPtr(obj);
|
dict = _PyObject_GetDictPtr(obj);
|
||||||
|
@ -3878,6 +3885,24 @@ _PyObject_GetState(PyObject *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(slotnames == Py_None || PyList_Check(slotnames));
|
assert(slotnames == Py_None || PyList_Check(slotnames));
|
||||||
|
if (required) {
|
||||||
|
Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize;
|
||||||
|
if (obj->ob_type->tp_dictoffset)
|
||||||
|
basicsize += sizeof(PyObject *);
|
||||||
|
if (obj->ob_type->tp_weaklistoffset)
|
||||||
|
basicsize += sizeof(PyObject *);
|
||||||
|
if (slotnames != Py_None)
|
||||||
|
basicsize += sizeof(PyObject *) * Py_SIZE(slotnames);
|
||||||
|
if (obj->ob_type->tp_basicsize > basicsize) {
|
||||||
|
Py_DECREF(slotnames);
|
||||||
|
Py_DECREF(state);
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"can't pickle %.200s objects",
|
||||||
|
Py_TYPE(obj)->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (slotnames != Py_None && Py_SIZE(slotnames) > 0) {
|
if (slotnames != Py_None && Py_SIZE(slotnames) > 0) {
|
||||||
PyObject *slots;
|
PyObject *slots;
|
||||||
Py_ssize_t slotnames_size, i;
|
Py_ssize_t slotnames_size, i;
|
||||||
|
@ -4107,29 +4132,24 @@ reduce_newobj(PyObject *obj)
|
||||||
PyObject *copyreg;
|
PyObject *copyreg;
|
||||||
PyObject *newobj, *newargs, *state, *listitems, *dictitems;
|
PyObject *newobj, *newargs, *state, *listitems, *dictitems;
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
int hasargs;
|
||||||
|
|
||||||
if (Py_TYPE(obj)->tp_new == NULL) {
|
if (Py_TYPE(obj)->tp_new == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"can't pickle %s objects",
|
"can't pickle %.200s objects",
|
||||||
Py_TYPE(obj)->tp_name);
|
Py_TYPE(obj)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0)
|
if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (args == NULL) {
|
|
||||||
args = PyTuple_New(0);
|
|
||||||
if (args == NULL) {
|
|
||||||
Py_XDECREF(kwargs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
copyreg = import_copyreg();
|
copyreg = import_copyreg();
|
||||||
if (copyreg == NULL) {
|
if (copyreg == NULL) {
|
||||||
Py_DECREF(args);
|
Py_XDECREF(args);
|
||||||
Py_XDECREF(kwargs);
|
Py_XDECREF(kwargs);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
hasargs = (args != NULL);
|
||||||
if (kwargs == NULL || PyDict_Size(kwargs) == 0) {
|
if (kwargs == NULL || PyDict_Size(kwargs) == 0) {
|
||||||
_Py_IDENTIFIER(__newobj__);
|
_Py_IDENTIFIER(__newobj__);
|
||||||
PyObject *cls;
|
PyObject *cls;
|
||||||
|
@ -4139,13 +4159,13 @@ reduce_newobj(PyObject *obj)
|
||||||
newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__);
|
newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__);
|
||||||
Py_DECREF(copyreg);
|
Py_DECREF(copyreg);
|
||||||
if (newobj == NULL) {
|
if (newobj == NULL) {
|
||||||
Py_DECREF(args);
|
Py_XDECREF(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
n = PyTuple_GET_SIZE(args);
|
n = args ? PyTuple_GET_SIZE(args) : 0;
|
||||||
newargs = PyTuple_New(n+1);
|
newargs = PyTuple_New(n+1);
|
||||||
if (newargs == NULL) {
|
if (newargs == NULL) {
|
||||||
Py_DECREF(args);
|
Py_XDECREF(args);
|
||||||
Py_DECREF(newobj);
|
Py_DECREF(newobj);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -4157,7 +4177,7 @@ reduce_newobj(PyObject *obj)
|
||||||
Py_INCREF(v);
|
Py_INCREF(v);
|
||||||
PyTuple_SET_ITEM(newargs, i+1, v);
|
PyTuple_SET_ITEM(newargs, i+1, v);
|
||||||
}
|
}
|
||||||
Py_DECREF(args);
|
Py_XDECREF(args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_Py_IDENTIFIER(__newobj_ex__);
|
_Py_IDENTIFIER(__newobj_ex__);
|
||||||
|
@ -4178,7 +4198,8 @@ reduce_newobj(PyObject *obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state = _PyObject_GetState(obj);
|
state = _PyObject_GetState(obj,
|
||||||
|
!hasargs && !PyList_Check(obj) && !PyDict_Check(obj));
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
Py_DECREF(newobj);
|
Py_DECREF(newobj);
|
||||||
Py_DECREF(newargs);
|
Py_DECREF(newargs);
|
||||||
|
|
Loading…
Reference in New Issue