[Python-checkins] cpython: Issue #26146: marshal.loads() now uses the empty frozenset singleton

victor.stinner python-checkins at python.org
Sat Jan 23 08:16:45 EST 2016


https://hg.python.org/cpython/rev/5de1bd759f3b
changeset:   100058:5de1bd759f3b
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Sat Jan 23 14:15:48 2016 +0100
summary:
  Issue #26146: marshal.loads() now uses the empty frozenset singleton

files:
  Lib/test/test_marshal.py |   7 ++
  Python/marshal.c         |  71 ++++++++++++++++-----------
  2 files changed, 48 insertions(+), 30 deletions(-)


diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -135,6 +135,13 @@
         for constructor in (set, frozenset):
             self.helper(constructor(self.d.keys()))
 
+    @support.cpython_only
+    def test_empty_frozenset_singleton(self):
+        # marshal.loads() must reuse the empty frozenset singleton
+        obj = frozenset()
+        obj2 = marshal.loads(marshal.dumps(obj))
+        self.assertIs(obj2, obj)
+
 
 class BufferTestCase(unittest.TestCase, HelperMixin):
 
diff --git a/Python/marshal.c b/Python/marshal.c
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -1266,41 +1266,52 @@
             PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)");
             break;
         }
-        v = (type == TYPE_SET) ? PySet_New(NULL) : PyFrozenSet_New(NULL);
-        if (type == TYPE_SET) {
+
+        if (n == 0 && type == TYPE_FROZENSET) {
+            /* call frozenset() to get the empty frozenset singleton */
+            v = PyObject_CallFunction((PyObject*)&PyFrozenSet_Type, NULL);
+            if (v == NULL)
+                break;
             R_REF(v);
-        } else {
-            /* must use delayed registration of frozensets because they must
-             * be init with a refcount of 1
-             */
-            idx = r_ref_reserve(flag, p);
-            if (idx < 0)
-                Py_CLEAR(v); /* signal error */
+            retval = v;
         }
-        if (v == NULL)
-            break;
+        else {
+            v = (type == TYPE_SET) ? PySet_New(NULL) : PyFrozenSet_New(NULL);
+            if (type == TYPE_SET) {
+                R_REF(v);
+            } else {
+                /* must use delayed registration of frozensets because they must
+                 * be init with a refcount of 1
+                 */
+                idx = r_ref_reserve(flag, p);
+                if (idx < 0)
+                    Py_CLEAR(v); /* signal error */
+            }
+            if (v == NULL)
+                break;
 
-        for (i = 0; i < n; i++) {
-            v2 = r_object(p);
-            if ( v2 == NULL ) {
-                if (!PyErr_Occurred())
-                    PyErr_SetString(PyExc_TypeError,
-                        "NULL object in marshal data for set");
-                Py_DECREF(v);
-                v = NULL;
-                break;
+            for (i = 0; i < n; i++) {
+                v2 = r_object(p);
+                if ( v2 == NULL ) {
+                    if (!PyErr_Occurred())
+                        PyErr_SetString(PyExc_TypeError,
+                            "NULL object in marshal data for set");
+                    Py_DECREF(v);
+                    v = NULL;
+                    break;
+                }
+                if (PySet_Add(v, v2) == -1) {
+                    Py_DECREF(v);
+                    Py_DECREF(v2);
+                    v = NULL;
+                    break;
+                }
+                Py_DECREF(v2);
             }
-            if (PySet_Add(v, v2) == -1) {
-                Py_DECREF(v);
-                Py_DECREF(v2);
-                v = NULL;
-                break;
-            }
-            Py_DECREF(v2);
+            if (type != TYPE_SET)
+                v = r_ref_insert(v, idx, flag, p);
+            retval = v;
         }
-        if (type != TYPE_SET)
-            v = r_ref_insert(v, idx, flag, p);
-        retval = v;
         break;
 
     case TYPE_CODE:

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list