Skip to content
Snippets Groups Projects
Unverified Commit 67408c6e authored by Johannes Schauer Marin Rodrigues's avatar Johannes Schauer Marin Rodrigues
Browse files

make python pyc files reproducible

parent ea1c99f5
No related branches found
No related tags found
No related merge requests found
#!/bin/sh
set -e
# #1004558
patch -p1 << 'EOF'
diff -Nru python3.9-3.9.10/debian/patches/reproducible-pyc.diff python3.9-3.9.10/debian/patches/reproducible-pyc.diff
--- python3.9-3.9.10/debian/patches/reproducible-pyc.diff 1970-01-01 01:00:00.000000000 +0100
+++ python3.9-3.9.10/debian/patches/reproducible-pyc.diff 2022-02-05 07:52:33.000000000 +0100
@@ -0,0 +1,105 @@
+From 36ae9beb04763d498df2114657bfbbcfe58bf913 Mon Sep 17 00:00:00 2001
+From: Brandt Bucher <brandt@python.org>
+Date: Mon, 23 Aug 2021 18:34:17 -0700
+Subject: [PATCH] Serialize frozenset elements deterministically
+
+---
+ Lib/test/test_marshal.py | 25 +++++++++++++++
+ .../2021-08-23-21-39-59.bpo-37596.ojRcwB.rst | 2 ++
+ Python/marshal.c | 32 +++++++++++++++++++
+ 3 files changed, 59 insertions(+)
+ create mode 100644 Misc/NEWS.d/next/Library/2021-08-23-21-39-59.bpo-37596.ojRcwB.rst
+
+diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
+index 7bcf8e8..8252be3 100644
+--- a/Lib/test/test_marshal.py
++++ b/Lib/test/test_marshal.py
+@@ -318,6 +318,31 @@ class BugsTestCase(unittest.TestCase):
+ for i in range(len(data)):
+ self.assertRaises(EOFError, marshal.loads, data[0: i])
+
++ def test_deterministic_sets(self):
++ # bpo-37596: To support reproducible builds, sets and frozensets need to
++ # have their elements serialized in a consistent order (even when they
++ # have been scrambled by hash randomization):
++ for kind in ("set", "frozenset"):
++ for elements in (
++ "float('nan'), b'a', b'b', b'c', 'x', 'y', 'z'",
++ # Also test for bad interactions with backreferencing:
++ "('string', 1), ('string', 2), ('string', 3)",
++ ):
++ s = f"{kind}([{elements}])"
++ with self.subTest(s):
++ # First, make sure that our test case still has different
++ # orders under hash seeds 0 and 1. If this check fails, we
++ # need to update this test with different elements:
++ args = ["-c", f"print({s})"]
++ _, repr_0, _ = assert_python_ok(*args, PYTHONHASHSEED="0")
++ _, repr_1, _ = assert_python_ok(*args, PYTHONHASHSEED="1")
++ self.assertNotEqual(repr_0, repr_1)
++ # Then, perform the actual test:
++ args = ["-c", f"import marshal; print(marshal.dumps({s}))"]
++ _, dump_0, _ = assert_python_ok(*args, PYTHONHASHSEED="0")
++ _, dump_1, _ = assert_python_ok(*args, PYTHONHASHSEED="1")
++ self.assertEqual(dump_0, dump_1)
++
+ LARGE_SIZE = 2**31
+ pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
+
+diff --git a/Misc/NEWS.d/next/Library/2021-08-23-21-39-59.bpo-37596.ojRcwB.rst b/Misc/NEWS.d/next/Library/2021-08-23-21-39-59.bpo-37596.ojRcwB.rst
+new file mode 100644
+index 0000000..81fdfeb
+--- /dev/null
++++ b/Misc/NEWS.d/next/Library/2021-08-23-21-39-59.bpo-37596.ojRcwB.rst
+@@ -0,0 +1,2 @@
++Ensure that :class:`set` and :class:`frozenset` objects are always
++:mod:`marshalled <marshal>` reproducibly.
+diff --git a/Python/marshal.c b/Python/marshal.c
+index 4125240..6bd4537 100644
+--- a/Python/marshal.c
++++ b/Python/marshal.c
+@@ -502,9 +502,41 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
+ W_TYPE(TYPE_SET, p);
+ n = PySet_GET_SIZE(v);
+ W_SIZE(n, p);
++ // bpo-37596: To support reproducible builds, sets and frozensets need
++ // to have their elements serialized in a consistent order (even when
++ // they have been scrambled by hash randomization). To ensure this, we
++ // use an order equivalent to sorted(v, key=marshal.dumps):
++ PyObject *pairs = PyList_New(0);
++ if (pairs == NULL) {
++ p->error = WFERR_NOMEMORY;
++ return;
++ }
+ while (_PySet_NextEntry(v, &pos, &value, &hash)) {
++ PyObject *dump = PyMarshal_WriteObjectToString(value, p->version);
++ if (dump == NULL) {
++ p->error = WFERR_UNMARSHALLABLE;
++ goto anyset_done;
++ }
++ PyObject *pair = PyTuple_Pack(2, dump, value);
++ Py_DECREF(dump);
++ if (pair == NULL || PyList_Append(pairs, pair)) {
++ p->error = WFERR_NOMEMORY;
++ Py_XDECREF(pair);
++ goto anyset_done;
++ }
++ Py_DECREF(pair);
++ }
++ if (PyList_Sort(pairs)) {
++ p->error = WFERR_NOMEMORY;
++ goto anyset_done;
++ }
++ for (Py_ssize_t i = 0; i < n; i++) {
++ PyObject *pair = PyList_GET_ITEM(pairs, i);
++ value = PyTuple_GET_ITEM(pair, 1);
+ w_object(value, p);
+ }
++ anyset_done:
++ Py_DECREF(pairs);
+ }
+ else if (PyCode_Check(v)) {
+ PyCodeObject *co = (PyCodeObject *)v;
+--
+2.33.0
+
diff -Nru python3.9-3.9.10/debian/patches/series python3.9-3.9.10/debian/patches/series
--- python3.9-3.9.10/debian/patches/series 2022-01-16 17:07:24.000000000 +0100
+++ python3.9-3.9.10/debian/patches/series 2022-02-05 07:52:42.000000000 +0100
@@ -40,3 +40,4 @@
sphinx3.diff
mpdecimal-2.5.1.diff
destshared-location.diff
+reproducible-pyc.diff
EOF
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment