mirror of https://github.com/python/cpython
Isuse #17720: Fix APPENDS handling in the Python implementation of Unpickler
to correctly process the opcode when it is used on non-list objects.
This commit is contained in:
parent
bdf940d3bd
commit
1f7492c28a
|
@ -1208,8 +1208,14 @@ class _Unpickler:
|
||||||
def load_appends(self):
|
def load_appends(self):
|
||||||
stack = self.stack
|
stack = self.stack
|
||||||
mark = self.marker()
|
mark = self.marker()
|
||||||
list = stack[mark - 1]
|
list_obj = stack[mark - 1]
|
||||||
list.extend(stack[mark + 1:])
|
items = stack[mark + 1:]
|
||||||
|
if isinstance(list_obj, list):
|
||||||
|
list_obj.extend(items)
|
||||||
|
else:
|
||||||
|
append = list_obj.append
|
||||||
|
for item in items:
|
||||||
|
append(item)
|
||||||
del stack[mark:]
|
del stack[mark:]
|
||||||
dispatch[APPENDS[0]] = load_appends
|
dispatch[APPENDS[0]] = load_appends
|
||||||
|
|
||||||
|
|
|
@ -1214,6 +1214,29 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.'
|
dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.'
|
||||||
self.assertRaises(ValueError, self.loads, dumped)
|
self.assertRaises(ValueError, self.loads, dumped)
|
||||||
|
|
||||||
|
def _check_pickling_with_opcode(self, obj, opcode, proto):
|
||||||
|
pickled = self.dumps(obj, proto)
|
||||||
|
self.assertTrue(opcode_in_pickle(opcode, pickled))
|
||||||
|
unpickled = self.loads(pickled)
|
||||||
|
self.assertEqual(obj, unpickled)
|
||||||
|
|
||||||
|
def test_appends_on_non_lists(self):
|
||||||
|
# Issue #17720
|
||||||
|
obj = REX_six([1, 2, 3])
|
||||||
|
for proto in protocols:
|
||||||
|
if proto == 0:
|
||||||
|
self._check_pickling_with_opcode(obj, pickle.APPEND, proto)
|
||||||
|
else:
|
||||||
|
self._check_pickling_with_opcode(obj, pickle.APPENDS, proto)
|
||||||
|
|
||||||
|
def test_setitems_on_non_dicts(self):
|
||||||
|
obj = REX_seven({1: -1, 2: -2, 3: -3})
|
||||||
|
for proto in protocols:
|
||||||
|
if proto == 0:
|
||||||
|
self._check_pickling_with_opcode(obj, pickle.SETITEM, proto)
|
||||||
|
else:
|
||||||
|
self._check_pickling_with_opcode(obj, pickle.SETITEMS, proto)
|
||||||
|
|
||||||
|
|
||||||
class BigmemPickleTests(unittest.TestCase):
|
class BigmemPickleTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -1299,18 +1322,18 @@ class BigmemPickleTests(unittest.TestCase):
|
||||||
# Test classes for reduce_ex
|
# Test classes for reduce_ex
|
||||||
|
|
||||||
class REX_one(object):
|
class REX_one(object):
|
||||||
|
"""No __reduce_ex__ here, but inheriting it from object"""
|
||||||
_reduce_called = 0
|
_reduce_called = 0
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
self._reduce_called = 1
|
self._reduce_called = 1
|
||||||
return REX_one, ()
|
return REX_one, ()
|
||||||
# No __reduce_ex__ here, but inheriting it from object
|
|
||||||
|
|
||||||
class REX_two(object):
|
class REX_two(object):
|
||||||
|
"""No __reduce__ here, but inheriting it from object"""
|
||||||
_proto = None
|
_proto = None
|
||||||
def __reduce_ex__(self, proto):
|
def __reduce_ex__(self, proto):
|
||||||
self._proto = proto
|
self._proto = proto
|
||||||
return REX_two, ()
|
return REX_two, ()
|
||||||
# No __reduce__ here, but inheriting it from object
|
|
||||||
|
|
||||||
class REX_three(object):
|
class REX_three(object):
|
||||||
_proto = None
|
_proto = None
|
||||||
|
@ -1321,18 +1344,45 @@ class REX_three(object):
|
||||||
raise TestFailed("This __reduce__ shouldn't be called")
|
raise TestFailed("This __reduce__ shouldn't be called")
|
||||||
|
|
||||||
class REX_four(object):
|
class REX_four(object):
|
||||||
|
"""Calling base class method should succeed"""
|
||||||
_proto = None
|
_proto = None
|
||||||
def __reduce_ex__(self, proto):
|
def __reduce_ex__(self, proto):
|
||||||
self._proto = proto
|
self._proto = proto
|
||||||
return object.__reduce_ex__(self, proto)
|
return object.__reduce_ex__(self, proto)
|
||||||
# Calling base class method should succeed
|
|
||||||
|
|
||||||
class REX_five(object):
|
class REX_five(object):
|
||||||
|
"""This one used to fail with infinite recursion"""
|
||||||
_reduce_called = 0
|
_reduce_called = 0
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
self._reduce_called = 1
|
self._reduce_called = 1
|
||||||
return object.__reduce__(self)
|
return object.__reduce__(self)
|
||||||
# This one used to fail with infinite recursion
|
|
||||||
|
class REX_six(object):
|
||||||
|
"""This class is used to check the 4th argument (list iterator) of the reduce
|
||||||
|
protocol.
|
||||||
|
"""
|
||||||
|
def __init__(self, items=None):
|
||||||
|
self.items = items if items is not None else []
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) is type(other) and self.items == self.items
|
||||||
|
def append(self, item):
|
||||||
|
self.items.append(item)
|
||||||
|
def __reduce__(self):
|
||||||
|
return type(self), (), None, iter(self.items), None
|
||||||
|
|
||||||
|
class REX_seven(object):
|
||||||
|
"""This class is used to check the 5th argument (dict iterator) of the reduce
|
||||||
|
protocol.
|
||||||
|
"""
|
||||||
|
def __init__(self, table=None):
|
||||||
|
self.table = table if table is not None else {}
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) is type(other) and self.table == self.table
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self.table[key] = value
|
||||||
|
def __reduce__(self):
|
||||||
|
return type(self), (), None, None, iter(self.table.items())
|
||||||
|
|
||||||
|
|
||||||
# Test classes for newobj
|
# Test classes for newobj
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ Library
|
||||||
- Issue #17707: multiprocessing.Queue's get() method does not block for short
|
- Issue #17707: multiprocessing.Queue's get() method does not block for short
|
||||||
timeouts.
|
timeouts.
|
||||||
|
|
||||||
|
- Isuse #17720: Fix the Python implementation of pickle.Unpickler to correctly
|
||||||
|
process the APPENDS opcode when it is used on non-list objects.
|
||||||
|
|
||||||
- Issue #17012: shutil.which() no longer fallbacks to the PATH environment
|
- Issue #17012: shutil.which() no longer fallbacks to the PATH environment
|
||||||
variable if empty path argument is specified. Patch by Serhiy Storchaka.
|
variable if empty path argument is specified. Patch by Serhiy Storchaka.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue