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: ...@@ -621,8 +621,11 @@ class Pickler:
proto = self.proto proto = self.proto
n = len(obj) n = len(obj)
if n == 0 and proto: if n == 0:
write(EMPTY_TUPLE) if proto:
write(EMPTY_TUPLE)
else:
write(MARK + TUPLE)
return return
save = self.save save = self.save
...@@ -639,13 +642,13 @@ class Pickler: ...@@ -639,13 +642,13 @@ class Pickler:
self.memoize(obj) self.memoize(obj)
return 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. # has more than 3 elements.
write(MARK) write(MARK)
for element in obj: for element in obj:
save(element) 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 # Subtle. d was not in memo when we entered save_tuple(), so
# the process of saving the tuple's elements must have saved # the process of saving the tuple's elements must have saved
# the tuple itself: the tuple is recursive. The proper action # the tuple itself: the tuple is recursive. The proper action
...@@ -660,10 +663,9 @@ class Pickler: ...@@ -660,10 +663,9 @@ class Pickler:
write(POP * (n+1) + get) write(POP * (n+1) + get)
return return
# No recursion (including the empty-tuple case for protocol 0). # No recursion.
self.write(TUPLE) self.write(TUPLE)
if obj: # No need to memoize empty tuple self.memoize(obj)
self.memoize(obj)
dispatch[TupleType] = save_tuple dispatch[TupleType] = save_tuple
......
...@@ -484,6 +484,27 @@ class AbstractPickleTests(unittest.TestCase): ...@@ -484,6 +484,27 @@ class AbstractPickleTests(unittest.TestCase):
self.assertEqual(x, y) self.assertEqual(x, y)
def test_short_tuples(self): 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 = () a = ()
b = (1,) b = (1,)
c = (1, 2) c = (1, 2)
...@@ -495,6 +516,16 @@ class AbstractPickleTests(unittest.TestCase): ...@@ -495,6 +516,16 @@ class AbstractPickleTests(unittest.TestCase):
y = self.loads(s) y = self.loads(s)
self.assertEqual(x, y, (proto, x, s, y)) 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): def test_singletons(self):
for proto in protocols: for proto in protocols:
for x in None, False, True: 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