@@ -317,6 +317,123 @@ def test_recursion_limit(self):
317317 last .append ([0 ])
318318 self .assertRaises (ValueError , marshal .dumps , head )
319319
320+ def test_reference_loop_list (self ):
321+ a = []
322+ a .append (a )
323+ for v in range (3 ):
324+ self .assertRaises (ValueError , marshal .dumps , a , v )
325+ for v in range (3 , marshal .version + 1 ):
326+ d = marshal .dumps (a , v )
327+ b = marshal .loads (d )
328+ self .assertIsInstance (b , list )
329+ self .assertIs (b [0 ], b )
330+
331+ def test_reference_loop_dict (self ):
332+ a = {}
333+ a [None ] = a
334+ for v in range (3 ):
335+ self .assertRaises (ValueError , marshal .dumps , a , v )
336+ for v in range (3 , marshal .version + 1 ):
337+ d = marshal .dumps (a , v )
338+ b = marshal .loads (d )
339+ self .assertIsInstance (b , dict )
340+ self .assertIs (b [None ], b )
341+
342+ def test_reference_loop_tuple (self ):
343+ a = ([],)
344+ a [0 ].append (a )
345+ for v in range (3 ):
346+ self .assertRaises (ValueError , marshal .dumps , a , v )
347+ for v in range (3 , marshal .version + 1 ):
348+ d = marshal .dumps (a , v )
349+ b = marshal .loads (d )
350+ self .assertIsInstance (b , tuple )
351+ self .assertIsInstance (b [0 ], list )
352+ self .assertIs (b [0 ][0 ], b )
353+
354+ def test_reference_loop_code (self ):
355+ def f ():
356+ return 1234.5
357+ code = f .__code__
358+ a = []
359+ code = code .replace (co_consts = code .co_consts + (a ,))
360+ a .append (code )
361+ for v in range (marshal .version + 1 ):
362+ self .assertRaises (ValueError , marshal .dumps , code , v )
363+
364+ def test_reference_loop_slice (self ):
365+ a = slice ([], None )
366+ a .start .append (a )
367+ for v in range (marshal .version + 1 ):
368+ self .assertRaises (ValueError , marshal .dumps , a , v )
369+
370+ a = slice (None , [])
371+ a .stop .append (a )
372+ for v in range (marshal .version + 1 ):
373+ self .assertRaises (ValueError , marshal .dumps , a , v )
374+
375+ a = slice (None , None , [])
376+ a .step .append (a )
377+ for v in range (marshal .version + 1 ):
378+ self .assertRaises (ValueError , marshal .dumps , a , v )
379+
380+ def test_loads_reference_loop_list (self ):
381+ data = b'\xdb \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # [<R>]
382+ a = marshal .loads (data )
383+ self .assertIsInstance (a , list )
384+ self .assertIs (a [0 ], a )
385+
386+ def test_loads_reference_loop_dict (self ):
387+ data = b'\xfb Nr\x00 \x00 \x00 \x00 0' # {None: <R>}
388+ a = marshal .loads (data )
389+ self .assertIsInstance (a , dict )
390+ self .assertIs (a [None ], a )
391+
392+ def test_loads_abnormal_reference_loops (self ):
393+ # Indirect self-references of tuples.
394+ data = b'\xa8 \x01 \x00 \x00 \x00 [\x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # ([<R>],)
395+ a = marshal .loads (data )
396+ self .assertIsInstance (a , tuple )
397+ self .assertIsInstance (a [0 ], list )
398+ self .assertIs (a [0 ][0 ], a )
399+
400+ data = b'\xa8 \x01 \x00 \x00 \x00 {Nr\x00 \x00 \x00 \x00 0' # ({None: <R>},)
401+ a = marshal .loads (data )
402+ self .assertIsInstance (a , tuple )
403+ self .assertIsInstance (a [0 ], dict )
404+ self .assertIs (a [0 ][None ], a )
405+
406+ # Direct self-reference which cannot be created in Python.
407+ data = b'\xa8 \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # (<R>,)
408+ a = marshal .loads (data )
409+ self .assertIsInstance (a , tuple )
410+ self .assertIs (a [0 ], a )
411+
412+ # Direct self-references which cannot be created in Python
413+ # because of unhashability.
414+ data = b'\xfb r\x00 \x00 \x00 \x00 N0' # {<R>: None}
415+ self .assertRaises (TypeError , marshal .loads , data )
416+ data = b'\xbc \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # {<R>}
417+ self .assertRaises (TypeError , marshal .loads , data )
418+
419+ for data in [
420+ # Indirect self-references of immutable objects.
421+ b'\xba [\x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 NN' , # slice([<R>], None)
422+ b'\xba N[\x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 N' , # slice(None, [<R>])
423+ b'\xba NN[\x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' , # slice(None, None, [<R>])
424+ b'\xba {Nr\x00 \x00 \x00 \x00 0NN' , # slice({None: <R>}, None)
425+ b'\xba N{Nr\x00 \x00 \x00 \x00 0N' , # slice(None, {None: <R>})
426+ b'\xba NN{Nr\x00 \x00 \x00 \x00 0' , # slice(None, None, {None: <R>})
427+
428+ # Direct self-references which cannot be created in Python.
429+ b'\xbe \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' , # frozenset({<R>})
430+ b'\xba r\x00 \x00 \x00 \x00 NN' , # slice(<R>, None)
431+ b'\xba Nr\x00 \x00 \x00 \x00 N' , # slice(None, <R>)
432+ b'\xba NNr\x00 \x00 \x00 \x00 ' , # slice(None, None, <R>)
433+ ]:
434+ with self .subTest (data = data ):
435+ self .assertRaises (ValueError , marshal .loads , data )
436+
320437 def test_exact_type_match (self ):
321438 # Former bug:
322439 # >>> class Int(int): pass
0 commit comments