mirror of https://github.com/python/cpython
gh-90494: Reject 6th element of the __reduce__() tuple (GH-93609) (GH-93631)
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.
(cherry picked from commit a365dd64c2
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
516d90eb21
commit
c3045d809c
|
@ -258,7 +258,7 @@ def _keep_alive(x, memo):
|
||||||
|
|
||||||
def _reconstruct(x, memo, func, args,
|
def _reconstruct(x, memo, func, args,
|
||||||
state=None, listiter=None, dictiter=None,
|
state=None, listiter=None, dictiter=None,
|
||||||
deepcopy=deepcopy):
|
*, deepcopy=deepcopy):
|
||||||
deep = memo is not None
|
deep = memo is not None
|
||||||
if deep and args:
|
if deep and args:
|
||||||
args = (deepcopy(arg, memo) for arg in args)
|
args = (deepcopy(arg, memo) for arg in args)
|
||||||
|
|
|
@ -619,7 +619,7 @@ class _Pickler:
|
||||||
"persistent IDs in protocol 0 must be ASCII strings")
|
"persistent IDs in protocol 0 must be ASCII strings")
|
||||||
|
|
||||||
def save_reduce(self, func, args, state=None, listitems=None,
|
def save_reduce(self, func, args, state=None, listitems=None,
|
||||||
dictitems=None, state_setter=None, obj=None):
|
dictitems=None, state_setter=None, *, obj=None):
|
||||||
# This API is called by some subclasses
|
# This API is called by some subclasses
|
||||||
|
|
||||||
if not isinstance(args, tuple):
|
if not isinstance(args, tuple):
|
||||||
|
|
|
@ -678,6 +678,28 @@ class TestCopy(unittest.TestCase):
|
||||||
self.assertIsNot(x, y)
|
self.assertIsNot(x, y)
|
||||||
self.assertIsNot(x["foo"], y["foo"])
|
self.assertIsNot(x["foo"], y["foo"])
|
||||||
|
|
||||||
|
def test_reduce_6tuple(self):
|
||||||
|
def state_setter(*args, **kwargs):
|
||||||
|
self.fail("shouldn't call this")
|
||||||
|
class C:
|
||||||
|
def __reduce__(self):
|
||||||
|
return C, (), self.__dict__, None, None, state_setter
|
||||||
|
x = C()
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
copy.copy(x)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
copy.deepcopy(x)
|
||||||
|
|
||||||
|
def test_reduce_6tuple_none(self):
|
||||||
|
class C:
|
||||||
|
def __reduce__(self):
|
||||||
|
return C, (), self.__dict__, None, None, None
|
||||||
|
x = C()
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
copy.copy(x)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
copy.deepcopy(x)
|
||||||
|
|
||||||
def test_copy_slots(self):
|
def test_copy_slots(self):
|
||||||
class C(object):
|
class C(object):
|
||||||
__slots__ = ["foo"]
|
__slots__ = ["foo"]
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
:func:`copy.copy` and :func:`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.
|
Loading…
Reference in New Issue