@@ -345,18 +345,29 @@ def test_eof(self):
345
345
self .assertRaises (EOFError , marshal .loads , data [0 : i ])
346
346
347
347
def test_deterministic_sets (self ):
348
- # bpo-37596: sets and frozensets must always marshal deterministically!
349
- # Test this by seeding string hashes:
350
- elements = "(float('nan'), b'a', b'b', b'c', 'x', 'y', 'z')"
348
+ # bpo-37596: To support reproducible builds, sets and frozensets need to
349
+ # have their elements serialized in a consistent order (even when they
350
+ # have been scrambled by hash randomization):
351
351
for kind in ("set" , "frozenset" ):
352
- script = f"import marshal; print(marshal.dumps({ kind } ({ elements } )))"
353
- with self .subTest (kind ):
354
- # {nan, b'b', 'x', b'a', b'c', 'y', 'z'}
355
- _ , a , _ = assert_python_ok ("-c" , script , PYTHONHASHSEED = "0" )
356
- # {nan, 'x', b'a', 'z', b'b', 'y', b'c'}
357
- _ , b , _ = assert_python_ok ("-c" , script , PYTHONHASHSEED = "1" )
358
- self .assertEqual (a , b )
359
-
352
+ for elements in (
353
+ "float('nan'), b'a', b'b', b'c', 'x', 'y', 'z'" ,
354
+ # Also test for bad interactions with backreferencing:
355
+ "('string', 1), ('string', 2), ('string', 3)" ,
356
+ ):
357
+ s = f"{ kind } ([{ elements } ])"
358
+ with self .subTest (s ):
359
+ # First, make sure that our test case still has different
360
+ # orders under hash seeds 0 and 1. If this check fails, we
361
+ # need to update this test with different elements:
362
+ args = ["-c" , f"print({ s } )" ]
363
+ _ , repr_0 , _ = assert_python_ok (* args , PYTHONHASHSEED = "0" )
364
+ _ , repr_1 , _ = assert_python_ok (* args , PYTHONHASHSEED = "1" )
365
+ self .assertNotEqual (repr_0 , repr_1 )
366
+ # Then, perform the actual test:
367
+ args = ["-c" , f"import marshal; print(marshal.dumps({ s } ))" ]
368
+ _ , dump_0 , _ = assert_python_ok (* args , PYTHONHASHSEED = "0" )
369
+ _ , dump_1 , _ = assert_python_ok (* args , PYTHONHASHSEED = "1" )
370
+ self .assertEqual (dump_0 , dump_1 )
360
371
361
372
LARGE_SIZE = 2 ** 31
362
373
pointer_size = 8 if sys .maxsize > 0xFFFFFFFF else 4
0 commit comments