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:
Serhiy Storchaka 2015-12-25 21:04:29 +02:00
parent bc4ded9537
commit f81be8aa3f
4 changed files with 67 additions and 15 deletions

View file

@ -3831,7 +3831,7 @@ _PyType_GetSlotNames(PyTypeObject *cls)
}
Py_LOCAL(PyObject *)
_PyObject_GetState(PyObject *obj)
_PyObject_GetState(PyObject *obj, int required)
{
PyObject *state;
PyObject *getstate;
@ -3846,6 +3846,13 @@ _PyObject_GetState(PyObject *obj)
}
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;
dict = _PyObject_GetDictPtr(obj);
@ -3870,6 +3877,24 @@ _PyObject_GetState(PyObject *obj)
}
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) {
PyObject *slots;
Py_ssize_t slotnames_size, i;
@ -4099,29 +4124,24 @@ reduce_newobj(PyObject *obj, int proto)
PyObject *copyreg;
PyObject *newobj, *newargs, *state, *listitems, *dictitems;
PyObject *result;
int hasargs;
if (Py_TYPE(obj)->tp_new == NULL) {
PyErr_Format(PyExc_TypeError,
"can't pickle %s objects",
"can't pickle %.200s objects",
Py_TYPE(obj)->tp_name);
return NULL;
}
if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0)
return NULL;
if (args == NULL) {
args = PyTuple_New(0);
if (args == NULL) {
Py_XDECREF(kwargs);
return NULL;
}
}
copyreg = import_copyreg();
if (copyreg == NULL) {
Py_DECREF(args);
Py_XDECREF(args);
Py_XDECREF(kwargs);
return NULL;
}
hasargs = (args != NULL);
if (kwargs == NULL || PyDict_Size(kwargs) == 0) {
_Py_IDENTIFIER(__newobj__);
PyObject *cls;
@ -4131,13 +4151,13 @@ reduce_newobj(PyObject *obj, int proto)
newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__);
Py_DECREF(copyreg);
if (newobj == NULL) {
Py_DECREF(args);
Py_XDECREF(args);
return NULL;
}
n = PyTuple_GET_SIZE(args);
n = args ? PyTuple_GET_SIZE(args) : 0;
newargs = PyTuple_New(n+1);
if (newargs == NULL) {
Py_DECREF(args);
Py_XDECREF(args);
Py_DECREF(newobj);
return NULL;
}
@ -4149,7 +4169,7 @@ reduce_newobj(PyObject *obj, int proto)
Py_INCREF(v);
PyTuple_SET_ITEM(newargs, i+1, v);
}
Py_DECREF(args);
Py_XDECREF(args);
}
else if (proto >= 4) {
_Py_IDENTIFIER(__newobj_ex__);
@ -4180,7 +4200,8 @@ reduce_newobj(PyObject *obj, int proto)
return NULL;
}
state = _PyObject_GetState(obj);
state = _PyObject_GetState(obj,
!hasargs && !PyList_Check(obj) && !PyDict_Check(obj));
if (state == NULL) {
Py_DECREF(newobj);
Py_DECREF(newargs);