@@ -419,6 +419,58 @@ def test_issue18339(self):
419419 unpickler .memo = {- 1 : None }
420420 unpickler .memo = {1 : None }
421421
422+ def test_concurrent_pickler_dump (self ):
423+ f = io .BytesIO ()
424+ pickler = self .pickler_class (f )
425+ class X :
426+ def __reduce__ (slf ):
427+ self .assertRaises (RuntimeError , pickler .dump , 42 )
428+ return list , ()
429+ pickler .dump (X ()) # should not crash
430+ self .assertEqual (pickle .loads (f .getvalue ()), [])
431+
432+ def test_concurrent_pickler_dump_and_clear_memo (self ):
433+ for clear_memo in [lambda : pickler .clear_memo (), lambda : pickler .memo .clear ()]:
434+ f = io .BytesIO ()
435+ pickler = self .pickler_class (f )
436+ class X :
437+ def __reduce__ (slf ):
438+ self .assertRaises (RuntimeError , clear_memo )
439+ return list , (('inner' ,),), None , iter ((slf ,))
440+ pickler .dump (['outer' , X ()])
441+ unpickled = pickle .loads (f .getvalue ())
442+ self .assertIs (unpickled [1 ][1 ], unpickled [1 ])
443+
444+ def test_concurrent_pickler_dump_and_init (self ):
445+ f = io .BytesIO ()
446+ pickler = self .pickler_class (f )
447+ class X :
448+ def __reduce__ (slf ):
449+ self .assertRaises (RuntimeError , pickler .__init__ , f )
450+ return list , ()
451+ pickler .dump ([X ()]) # should not fail
452+ self .assertEqual (pickle .loads (f .getvalue ()), [[]])
453+
454+ def test_concurrent_unpickler_load (self ):
455+ global reducer
456+ def reducer ():
457+ self .assertRaises (RuntimeError , unpickler .load )
458+ return 42
459+ f = io .BytesIO (b'(c%b\n reducer\n (tRl.' % (__name__ .encode (),))
460+ unpickler = self .unpickler_class (f )
461+ unpickled = unpickler .load () # should not fail
462+ self .assertEqual (unpickled , [42 ])
463+
464+ def test_concurrent_unpickler_load_and_init (self ):
465+ global reducer
466+ def reducer ():
467+ self .assertRaises (RuntimeError , unpickler .__init__ , f )
468+ return 42
469+ f = io .BytesIO (b'(c%b\n reducer\n (tRl.' % (__name__ .encode (),))
470+ unpickler = self .unpickler_class (f )
471+ unpickled = unpickler .load () # should not crash
472+ self .assertEqual (unpickled , [42 ])
473+
422474 class CDispatchTableTests (AbstractDispatchTableTests , unittest .TestCase ):
423475 pickler_class = pickle .Pickler
424476 def get_dispatch_table (self ):
@@ -467,7 +519,7 @@ class SizeofTests(unittest.TestCase):
467519 check_sizeof = support .check_sizeof
468520
469521 def test_pickler (self ):
470- basesize = support .calcobjsize ('7P2n3i2n3i2P ' )
522+ basesize = support .calcobjsize ('7P2n3i2n4i2P ' )
471523 p = _pickle .Pickler (io .BytesIO ())
472524 self .assertEqual (object .__sizeof__ (p ), basesize )
473525 MT_size = struct .calcsize ('3nP0n' )
@@ -484,7 +536,7 @@ def test_pickler(self):
484536 0 ) # Write buffer is cleared after every dump().
485537
486538 def test_unpickler (self ):
487- basesize = support .calcobjsize ('2P2n3P 2P2n2i5P 2P3n8P2n2i ' )
539+ basesize = support .calcobjsize ('2P2n3P 2P2n2i5P 2P3n8P2n3i ' )
488540 unpickler = _pickle .Unpickler
489541 P = struct .calcsize ('P' ) # Size of memo table entry.
490542 n = struct .calcsize ('n' ) # Size of mark table entry.
0 commit comments