Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f81be8a

Browse files
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.
1 parent bc4ded9 commit f81be8a

4 files changed

Lines changed: 67 additions & 15 deletions

File tree

Lib/test/test_csv.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (C) 2001,2002 Python Software Foundation
22
# csv package unit tests
33

4+
import copy
45
import io
56
import sys
67
import os
@@ -9,6 +10,7 @@
910
from tempfile import TemporaryFile
1011
import csv
1112
import gc
13+
import pickle
1214
from test import support
1315

1416
class Test_Csv(unittest.TestCase):
@@ -424,6 +426,17 @@ def test_bad_dialect(self):
424426
self.assertRaises(TypeError, csv.reader, [], quoting = -1)
425427
self.assertRaises(TypeError, csv.reader, [], quoting = 100)
426428

429+
def test_copy(self):
430+
for name in csv.list_dialects():
431+
dialect = csv.get_dialect(name)
432+
self.assertRaises(TypeError, copy.copy, dialect)
433+
434+
def test_pickle(self):
435+
for name in csv.list_dialects():
436+
dialect = csv.get_dialect(name)
437+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
438+
self.assertRaises(TypeError, pickle.dumps, dialect, proto)
439+
427440
class TestCsvBase(unittest.TestCase):
428441
def readerAssertEqual(self, input, expected_result):
429442
with TemporaryFile("w+", newline='') as fileobj:

Lib/test/test_memoryview.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import weakref
1212
import array
1313
import io
14+
import copy
15+
import pickle
1416

1517

1618
class AbstractMemoryTests:
@@ -519,6 +521,17 @@ def test_memoryview_hex(self):
519521
m2 = m1[::-1]
520522
self.assertEqual(m2.hex(), '30' * 200000)
521523

524+
def test_copy(self):
525+
m = memoryview(b'abc')
526+
with self.assertRaises(TypeError):
527+
copy.copy(m)
528+
529+
def test_pickle(self):
530+
m = memoryview(b'abc')
531+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
532+
with self.assertRaises(TypeError):
533+
pickle.dumps(m, proto)
534+
522535

523536
if __name__ == "__main__":
524537
unittest.main()

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ Release date: tba
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #22995: Instances of extension types with a state that aren't
14+
subclasses of list or dict and haven't implemented any pickle-related
15+
methods (__reduce__, __reduce_ex__, __getnewargs__, __getnewargs_ex__,
16+
or __getstate__), can no longer be pickled. Including memoryview.
17+
1318
- Issue #20440: Massive replacing unsafe attribute setting code with special
1419
macro Py_SETREF.
1520

Objects/typeobject.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3831,7 +3831,7 @@ _PyType_GetSlotNames(PyTypeObject *cls)
38313831
}
38323832

38333833
Py_LOCAL(PyObject *)
3834-
_PyObject_GetState(PyObject *obj)
3834+
_PyObject_GetState(PyObject *obj, int required)
38353835
{
38363836
PyObject *state;
38373837
PyObject *getstate;
@@ -3846,6 +3846,13 @@ _PyObject_GetState(PyObject *obj)
38463846
}
38473847
PyErr_Clear();
38483848

3849+
if (required && obj->ob_type->tp_itemsize) {
3850+
PyErr_Format(PyExc_TypeError,
3851+
"can't pickle %.200s objects",
3852+
Py_TYPE(obj)->tp_name);
3853+
return NULL;
3854+
}
3855+
38493856
{
38503857
PyObject **dict;
38513858
dict = _PyObject_GetDictPtr(obj);
@@ -3870,6 +3877,24 @@ _PyObject_GetState(PyObject *obj)
38703877
}
38713878

38723879
assert(slotnames == Py_None || PyList_Check(slotnames));
3880+
if (required) {
3881+
Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize;
3882+
if (obj->ob_type->tp_dictoffset)
3883+
basicsize += sizeof(PyObject *);
3884+
if (obj->ob_type->tp_weaklistoffset)
3885+
basicsize += sizeof(PyObject *);
3886+
if (slotnames != Py_None)
3887+
basicsize += sizeof(PyObject *) * Py_SIZE(slotnames);
3888+
if (obj->ob_type->tp_basicsize > basicsize) {
3889+
Py_DECREF(slotnames);
3890+
Py_DECREF(state);
3891+
PyErr_Format(PyExc_TypeError,
3892+
"can't pickle %.200s objects",
3893+
Py_TYPE(obj)->tp_name);
3894+
return NULL;
3895+
}
3896+
}
3897+
38733898
if (slotnames != Py_None && Py_SIZE(slotnames) > 0) {
38743899
PyObject *slots;
38753900
Py_ssize_t slotnames_size, i;
@@ -4099,29 +4124,24 @@ reduce_newobj(PyObject *obj, int proto)
40994124
PyObject *copyreg;
41004125
PyObject *newobj, *newargs, *state, *listitems, *dictitems;
41014126
PyObject *result;
4127+
int hasargs;
41024128

41034129
if (Py_TYPE(obj)->tp_new == NULL) {
41044130
PyErr_Format(PyExc_TypeError,
4105-
"can't pickle %s objects",
4131+
"can't pickle %.200s objects",
41064132
Py_TYPE(obj)->tp_name);
41074133
return NULL;
41084134
}
41094135
if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0)
41104136
return NULL;
41114137

4112-
if (args == NULL) {
4113-
args = PyTuple_New(0);
4114-
if (args == NULL) {
4115-
Py_XDECREF(kwargs);
4116-
return NULL;
4117-
}
4118-
}
41194138
copyreg = import_copyreg();
41204139
if (copyreg == NULL) {
4121-
Py_DECREF(args);
4140+
Py_XDECREF(args);
41224141
Py_XDECREF(kwargs);
41234142
return NULL;
41244143
}
4144+
hasargs = (args != NULL);
41254145
if (kwargs == NULL || PyDict_Size(kwargs) == 0) {
41264146
_Py_IDENTIFIER(__newobj__);
41274147
PyObject *cls;
@@ -4131,13 +4151,13 @@ reduce_newobj(PyObject *obj, int proto)
41314151
newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__);
41324152
Py_DECREF(copyreg);
41334153
if (newobj == NULL) {
4134-
Py_DECREF(args);
4154+
Py_XDECREF(args);
41354155
return NULL;
41364156
}
4137-
n = PyTuple_GET_SIZE(args);
4157+
n = args ? PyTuple_GET_SIZE(args) : 0;
41384158
newargs = PyTuple_New(n+1);
41394159
if (newargs == NULL) {
4140-
Py_DECREF(args);
4160+
Py_XDECREF(args);
41414161
Py_DECREF(newobj);
41424162
return NULL;
41434163
}
@@ -4149,7 +4169,7 @@ reduce_newobj(PyObject *obj, int proto)
41494169
Py_INCREF(v);
41504170
PyTuple_SET_ITEM(newargs, i+1, v);
41514171
}
4152-
Py_DECREF(args);
4172+
Py_XDECREF(args);
41534173
}
41544174
else if (proto >= 4) {
41554175
_Py_IDENTIFIER(__newobj_ex__);
@@ -4180,7 +4200,8 @@ reduce_newobj(PyObject *obj, int proto)
41804200
return NULL;
41814201
}
41824202

4183-
state = _PyObject_GetState(obj);
4203+
state = _PyObject_GetState(obj,
4204+
!hasargs && !PyList_Check(obj) && !PyDict_Check(obj));
41844205
if (state == NULL) {
41854206
Py_DECREF(newobj);
41864207
Py_DECREF(newargs);

0 commit comments

Comments
 (0)