]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.10] GH-89988: Fix memory leak in pickle.Pickler dispatch_table lookup (GH-94298...
authorKumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Tue, 28 Jun 2022 16:14:47 +0000 (21:44 +0530)
committerGitHub <noreply@github.com>
Tue, 28 Jun 2022 16:14:47 +0000 (17:14 +0100)
Lib/test/test_pickle.py
Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst [new file with mode: 0644]
Modules/_pickle.c

index 8775ff4b79157df93156b142f08db4c36ed39499..aa18ba24044d7b885fe90788af7f0d85afff0f5a 100644 (file)
@@ -154,6 +154,29 @@ class PyIdPersPicklerTests(AbstractIdentityPersistentPicklerTests,
                 return obj
         check(PersPickler)
 
+    @support.cpython_only
+    def test_custom_pickler_dispatch_table_memleak(self):
+        # See https://github.com/python/cpython/issues/89988
+
+        class Pickler(self.pickler):
+            def __init__(self, *args, **kwargs):
+                self.dispatch_table = table
+                super().__init__(*args, **kwargs)
+
+        class DispatchTable:
+            pass
+
+        table = DispatchTable()
+        pickler = Pickler(io.BytesIO())
+        self.assertIs(pickler.dispatch_table, table)
+        table_ref = weakref.ref(table)
+        self.assertIsNotNone(table_ref())
+        del pickler
+        del table
+        support.gc_collect()
+        self.assertIsNone(table_ref())
+
+
     @support.cpython_only
     def test_unpickler_reference_cycle(self):
         def check(Unpickler):
diff --git a/Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst b/Misc/NEWS.d/next/Library/2022-06-26-10-59-15.gh-issue-89988.K8rnmt.rst
new file mode 100644 (file)
index 0000000..811a8d6
--- /dev/null
@@ -0,0 +1 @@
+Fix memory leak in :class:`pickle.Pickler` when looking up :attr:`dispatch_table`. Patch by Kumar Aditya.
index d05069a0d436d67841c2ccf6ec3afce46fadc163..ce54a2dbf3de34cd8418cee02cffe03e9448840a 100644 (file)
@@ -4790,8 +4790,12 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file,
         return -1;
     }
 
+
+    if (self->dispatch_table != NULL) {
+        return 0;
+    }
     if (_PyObject_LookupAttrId((PyObject *)self,
-                                    &PyId_dispatch_table, &self->dispatch_table) < 0) {
+            &PyId_dispatch_table, &self->dispatch_table) < 0) {
         return -1;
     }