@@ -310,6 +310,96 @@ def test_recursion_limit(self):
310310 last .append ([0 ])
311311 self .assertRaises (ValueError , marshal .dumps , head )
312312
313+ def test_reference_loop_list (self ):
314+ a = []
315+ a .append (a )
316+ for v in range (3 ):
317+ self .assertRaises (ValueError , marshal .dumps , a , v )
318+ for v in range (3 , marshal .version + 1 ):
319+ d = marshal .dumps (a , v )
320+ b = marshal .loads (d )
321+ self .assertIsInstance (b , list )
322+ self .assertIs (b [0 ], b )
323+
324+ def test_reference_loop_dict (self ):
325+ a = {}
326+ a [None ] = a
327+ for v in range (3 ):
328+ self .assertRaises (ValueError , marshal .dumps , a , v )
329+ for v in range (3 , marshal .version + 1 ):
330+ d = marshal .dumps (a , v )
331+ b = marshal .loads (d )
332+ self .assertIsInstance (b , dict )
333+ self .assertIs (b [None ], b )
334+
335+ def test_reference_loop_tuple (self ):
336+ a = ([],)
337+ a [0 ].append (a )
338+ for v in range (3 ):
339+ self .assertRaises (ValueError , marshal .dumps , a , v )
340+ for v in range (3 , marshal .version + 1 ):
341+ d = marshal .dumps (a , v )
342+ b = marshal .loads (d )
343+ self .assertIsInstance (b , tuple )
344+ self .assertIsInstance (b [0 ], list )
345+ self .assertIs (b [0 ][0 ], b )
346+
347+ def test_reference_loop_code (self ):
348+ def f ():
349+ return 1234.5
350+ code = f .__code__
351+ a = []
352+ code = code .replace (co_consts = code .co_consts + (a ,))
353+ a .append (code )
354+ for v in range (marshal .version + 1 ):
355+ self .assertRaises (ValueError , marshal .dumps , code , v )
356+
357+ def test_loads_reference_loop_list (self ):
358+ data = b'\xdb \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # [<R>]
359+ a = marshal .loads (data )
360+ self .assertIsInstance (a , list )
361+ self .assertIs (a [0 ], a )
362+
363+ def test_loads_reference_loop_dict (self ):
364+ data = b'\xfb Nr\x00 \x00 \x00 \x00 0' # {None: <R>}
365+ a = marshal .loads (data )
366+ self .assertIsInstance (a , dict )
367+ self .assertIs (a [None ], a )
368+
369+ def test_loads_abnormal_reference_loops (self ):
370+ # Indirect self-references of tuples.
371+ data = b'\xa8 \x01 \x00 \x00 \x00 [\x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # ([<R>],)
372+ a = marshal .loads (data )
373+ self .assertIsInstance (a , tuple )
374+ self .assertIsInstance (a [0 ], list )
375+ self .assertIs (a [0 ][0 ], a )
376+
377+ data = b'\xa8 \x01 \x00 \x00 \x00 {Nr\x00 \x00 \x00 \x00 0' # ({None: <R>},)
378+ a = marshal .loads (data )
379+ self .assertIsInstance (a , tuple )
380+ self .assertIsInstance (a [0 ], dict )
381+ self .assertIs (a [0 ][None ], a )
382+
383+ # Direct self-reference which cannot be created in Python.
384+ data = b'\xa8 \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # (<R>,)
385+ a = marshal .loads (data )
386+ self .assertIsInstance (a , tuple )
387+ self .assertIs (a [0 ], a )
388+
389+ # Direct self-references which cannot be created in Python
390+ # because of unhashability.
391+ data = b'\xfb r\x00 \x00 \x00 \x00 N0' # {<R>: None}
392+ self .assertRaises (TypeError , marshal .loads , data )
393+ data = b'\xbc \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' # {<R>}
394+ self .assertRaises (TypeError , marshal .loads , data )
395+
396+ for data in [
397+ # Direct self-references which cannot be created in Python.
398+ b'\xbe \x01 \x00 \x00 \x00 r\x00 \x00 \x00 \x00 ' , # frozenset({<R>})
399+ ]:
400+ with self .subTest (data = data ):
401+ self .assertRaises (ValueError , marshal .loads , data )
402+
313403 def test_exact_type_match (self ):
314404 # Former bug:
315405 # >>> class Int(int): pass
0 commit comments