Commit d13006dd authored by Tim Peters's avatar Tim Peters

cPickle support for TUPLE[123]. Incidentally plugged several undetected

overflow holes in Pdata_grow().
parent 90692719
......@@ -621,8 +621,11 @@ class Pickler:
proto = self.proto
n = len(obj)
if n == 0 and proto:
write(EMPTY_TUPLE)
if n == 0:
if proto:
write(EMPTY_TUPLE)
else:
write(MARK + TUPLE)
return
save = self.save
......@@ -639,13 +642,13 @@ class Pickler:
self.memoize(obj)
return
# proto 0, or proto 1 and tuple isn't empty, or proto > 1 and tuple
# proto 0 or proto 1 and tuple isn't empty, or proto > 1 and tuple
# has more than 3 elements.
write(MARK)
for element in obj:
save(element)
if n and id(obj) in memo:
if id(obj) in memo:
# Subtle. d was not in memo when we entered save_tuple(), so
# the process of saving the tuple's elements must have saved
# the tuple itself: the tuple is recursive. The proper action
......@@ -660,10 +663,9 @@ class Pickler:
write(POP * (n+1) + get)
return
# No recursion (including the empty-tuple case for protocol 0).
# No recursion.
self.write(TUPLE)
if obj: # No need to memoize empty tuple
self.memoize(obj)
self.memoize(obj)
dispatch[TupleType] = save_tuple
......
......@@ -484,6 +484,27 @@ class AbstractPickleTests(unittest.TestCase):
self.assertEqual(x, y)
def test_short_tuples(self):
# Map (proto, len(tuple)) to expected opcode.
expected_opcode = {(0, 0): pickle.TUPLE,
(0, 1): pickle.TUPLE,
(0, 2): pickle.TUPLE,
(0, 3): pickle.TUPLE,
(0, 4): pickle.TUPLE,
(1, 0): pickle.EMPTY_TUPLE,
(1, 1): pickle.TUPLE,
(1, 2): pickle.TUPLE,
(1, 3): pickle.TUPLE,
(1, 4): pickle.TUPLE,
(2, 0): pickle.EMPTY_TUPLE,
(2, 1): pickle.TUPLE1,
(2, 2): pickle.TUPLE2,
(2, 3): pickle.TUPLE3,
(2, 4): pickle.TUPLE,
}
all_tuple_opcodes = (pickle.TUPLE, pickle.EMPTY_TUPLE,
pickle.TUPLE1, pickle.TUPLE2, pickle.TUPLE3)
a = ()
b = (1,)
c = (1, 2)
......@@ -495,6 +516,16 @@ class AbstractPickleTests(unittest.TestCase):
y = self.loads(s)
self.assertEqual(x, y, (proto, x, s, y))
# Verify that the protocol-correct tuple-building opcode
# was generated.
expected = expected_opcode[proto, len(x)]
for opcode in s:
if opcode in all_tuple_opcodes:
self.assertEqual(expected, opcode)
break
else:
self.fail("didn't find a tuple-building opcode in pickle")
def test_singletons(self):
for proto in protocols:
for x in None, False, True:
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment