Skip to content

Commit d7a4415

Browse files
Issue #22995: Default implementation of __reduce__ and __reduce_ex__ now
rejects builtin types with not defined __new__. Added tests for non-pickleable types.
1 parent a9dcdab commit d7a4415

6 files changed

Lines changed: 78 additions & 0 deletions

File tree

Lib/test/test_dictviews.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import copy
2+
import pickle
13
import unittest
24
from test import support
35

@@ -198,6 +200,22 @@ def test_recursive_repr(self):
198200
d[42] = d.values()
199201
self.assertRaises(RuntimeError, repr, d)
200202

203+
def test_copy(self):
204+
d = {1: 10, "a": "ABC"}
205+
self.assertRaises(TypeError, copy.copy, d.keys())
206+
self.assertRaises(TypeError, copy.copy, d.values())
207+
self.assertRaises(TypeError, copy.copy, d.items())
208+
209+
def test_pickle(self):
210+
d = {1: 10, "a": "ABC"}
211+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
212+
self.assertRaises((TypeError, pickle.PicklingError),
213+
pickle.dumps, d.keys(), proto)
214+
self.assertRaises((TypeError, pickle.PicklingError),
215+
pickle.dumps, d.values(), proto)
216+
self.assertRaises((TypeError, pickle.PicklingError),
217+
pickle.dumps, d.items(), proto)
218+
201219

202220
def test_main():
203221
support.run_unittest(DictSetTest)

Lib/test/test_generators.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import copy
12
import gc
3+
import pickle
24
import sys
35
import unittest
46
import weakref
@@ -70,6 +72,24 @@ def g3(): return (yield from f())
7072
self.assertEqual(cm.exception.value, 2)
7173

7274

75+
class GeneratorTest(unittest.TestCase):
76+
77+
def test_copy(self):
78+
def f():
79+
yield 1
80+
g = f()
81+
with self.assertRaises(TypeError):
82+
copy.copy(g)
83+
84+
def test_pickle(self):
85+
def f():
86+
yield 1
87+
g = f()
88+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
89+
with self.assertRaises((TypeError, pickle.PicklingError)):
90+
pickle.dumps(g, proto)
91+
92+
7393
class ExceptionTest(unittest.TestCase):
7494
# Tests for the issue #23353: check that the currently handled exception
7595
# is correctly saved/restored in PyEval_EvalFrameEx().

Lib/test/test_xml_etree.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# For this purpose, the module-level "ET" symbol is temporarily
66
# monkey-patched when running the "test_xml_etree_c" test suite.
77

8+
import copy
89
import html
910
import io
1011
import operator
@@ -2082,6 +2083,19 @@ def test_iter_by_tag(self):
20822083
self.assertEqual(self._ilist(doc), all_tags)
20832084
self.assertEqual(self._ilist(doc, '*'), all_tags)
20842085

2086+
def test_copy(self):
2087+
a = ET.Element('a')
2088+
it = a.iter()
2089+
with self.assertRaises(TypeError):
2090+
copy.copy(it)
2091+
2092+
def test_pickle(self):
2093+
a = ET.Element('a')
2094+
it = a.iter()
2095+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
2096+
with self.assertRaises((TypeError, pickle.PicklingError)):
2097+
pickle.dumps(it, proto)
2098+
20852099

20862100
class TreeBuilderTest(unittest.TestCase):
20872101
sample1 = ('<!DOCTYPE html PUBLIC'

Lib/test/test_zlib.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22
from test import support
33
import binascii
4+
import pickle
45
import random
56
import sys
67
from test.support import bigmemtest, _1G, _4G
@@ -600,6 +601,16 @@ def test_baddecompresscopy(self):
600601
d.flush()
601602
self.assertRaises(ValueError, d.copy)
602603

604+
def test_compresspickle(self):
605+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
606+
with self.assertRaises((TypeError, pickle.PicklingError)):
607+
pickle.dumps(zlib.compressobj(zlib.Z_BEST_COMPRESSION), proto)
608+
609+
def test_decompresspickle(self):
610+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
611+
with self.assertRaises((TypeError, pickle.PicklingError)):
612+
pickle.dumps(zlib.decompressobj(), proto)
613+
603614
# Memory use of the following functions takes into account overallocation
604615

605616
@bigmemtest(size=_1G + 1024 * 1024, memuse=3)

Misc/NEWS

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

13+
- Issue #22995: Default implementation of __reduce__ and __reduce_ex__ now
14+
rejects builtin types with not defined __new__.
15+
1316
- Issue #24802: Avoid buffer overreads when int(), float(), compile(), exec()
1417
and eval() are passed bytes-like objects. These objects are not
1518
necessarily terminated by a null byte, but the functions assumed they were.

Objects/typeobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3980,6 +3980,12 @@ reduce_4(PyObject *obj)
39803980
PyObject *result;
39813981
_Py_IDENTIFIER(__newobj_ex__);
39823982

3983+
if (Py_TYPE(obj)->tp_new == NULL) {
3984+
PyErr_Format(PyExc_TypeError,
3985+
"can't pickle %s objects",
3986+
Py_TYPE(obj)->tp_name);
3987+
return NULL;
3988+
}
39833989
if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) {
39843990
return NULL;
39853991
}
@@ -4046,6 +4052,12 @@ reduce_2(PyObject *obj)
40464052
Py_ssize_t i, n;
40474053
_Py_IDENTIFIER(__newobj__);
40484054

4055+
if (Py_TYPE(obj)->tp_new == NULL) {
4056+
PyErr_Format(PyExc_TypeError,
4057+
"can't pickle %s objects",
4058+
Py_TYPE(obj)->tp_name);
4059+
return NULL;
4060+
}
40494061
if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) {
40504062
return NULL;
40514063
}

0 commit comments

Comments
 (0)