Skip to content

Commit a2376d8

Browse files
pythongh-90494: Reject 6th element of the __reduce__() tuple
copy.copy() and copy.deepcopy() now always raise a TypeError if __reduce__() returns a tuple with length 6 instead of silently ignore the 6th item or produce incorrect result.
1 parent 2dece90 commit a2376d8

File tree

4 files changed

+27
-2
lines changed

4 files changed

+27
-2
lines changed

Lib/copy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def _keep_alive(x, memo):
258258

259259
def _reconstruct(x, memo, func, args,
260260
state=None, listiter=None, dictiter=None,
261-
deepcopy=deepcopy):
261+
*, deepcopy=deepcopy):
262262
deep = memo is not None
263263
if deep and args:
264264
args = (deepcopy(arg, memo) for arg in args)

Lib/pickle.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ def save_pers(self, pid):
619619
"persistent IDs in protocol 0 must be ASCII strings")
620620

621621
def save_reduce(self, func, args, state=None, listitems=None,
622-
dictitems=None, state_setter=None, obj=None):
622+
dictitems=None, state_setter=None, *, obj=None):
623623
# This API is called by some subclasses
624624

625625
if not isinstance(args, tuple):

Lib/test/test_copy.py

+22
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,28 @@ def __eq__(self, other):
678678
self.assertIsNot(x, y)
679679
self.assertIsNot(x["foo"], y["foo"])
680680

681+
def test_reduce_6tuple(self):
682+
def state_setter(*args, **kwargs):
683+
self.fail("shouldn't call this")
684+
class C:
685+
def __reduce__(self):
686+
return C, (), self.__dict__, None, None, state_setter
687+
x = C()
688+
with self.assertRaises(TypeError):
689+
copy.copy(x)
690+
with self.assertRaises(TypeError):
691+
copy.deepcopy(x)
692+
693+
def test_reduce_6tuple_none(self):
694+
class C:
695+
def __reduce__(self):
696+
return C, (), self.__dict__, None, None, None
697+
x = C()
698+
with self.assertRaises(TypeError):
699+
copy.copy(x)
700+
with self.assertRaises(TypeError):
701+
copy.deepcopy(x)
702+
681703
def test_copy_slots(self):
682704
class C(object):
683705
__slots__ = ["foo"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`copy.copy` and :func:`copy.deepcopy` now always raise a TypeError if
2+
``__reduce__()`` returns a tuple with length 6 instead of silently ignore
3+
the 6th item or produce incorrect result.

0 commit comments

Comments
 (0)