summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorAndrew Geng <pteromys@gmail.com>2023-08-11 17:44:18 (GMT)
committerGitHub <noreply@github.com>2023-08-11 17:44:18 (GMT)
commit5f7d4ecf301ef12eb1d1d347add054f4fcd8fc5c (patch)
tree33c687f8dfb36db77ce66c08e72bca5025941c61 /Lib
parentcaa41a4f1db0112690cf610bab7d9c6dce9ff1ce (diff)
downloadcpython-5f7d4ecf301ef12eb1d1d347add054f4fcd8fc5c.zip
cpython-5f7d4ecf301ef12eb1d1d347add054f4fcd8fc5c.tar.gz
cpython-5f7d4ecf301ef12eb1d1d347add054f4fcd8fc5c.tar.bz2
gh-106558: break ref cycles through exceptions in multiprocessing manager (#106559)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/multiprocessing/managers.py10
-rw-r--r--Lib/test/_test_multiprocessing.py38
2 files changed, 46 insertions, 2 deletions
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index b653493..273c22a 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -90,7 +90,10 @@ def dispatch(c, id, methodname, args=(), kwds={}):
kind, result = c.recv()
if kind == '#RETURN':
return result
- raise convert_to_error(kind, result)
+ try:
+ raise convert_to_error(kind, result)
+ finally:
+ del result # break reference cycle
def convert_to_error(kind, result):
if kind == '#ERROR':
@@ -833,7 +836,10 @@ class BaseProxy(object):
conn = self._Client(token.address, authkey=self._authkey)
dispatch(conn, None, 'decref', (token.id,))
return proxy
- raise convert_to_error(kind, result)
+ try:
+ raise convert_to_error(kind, result)
+ finally:
+ del result # break reference cycle
def _getvalue(self):
'''
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index c1f9487..f881a5d 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -3149,6 +3149,44 @@ class _TestManagerRestart(BaseTestCase):
if hasattr(manager, "shutdown"):
self.addCleanup(manager.shutdown)
+
+class FakeConnection:
+ def send(self, payload):
+ pass
+
+ def recv(self):
+ return '#ERROR', pyqueue.Empty()
+
+class TestManagerExceptions(unittest.TestCase):
+ # Issue 106558: Manager exceptions avoids creating cyclic references.
+ def setUp(self):
+ self.mgr = multiprocessing.Manager()
+
+ def tearDown(self):
+ self.mgr.shutdown()
+ self.mgr.join()
+
+ def test_queue_get(self):
+ queue = self.mgr.Queue()
+ if gc.isenabled():
+ gc.disable()
+ self.addCleanup(gc.enable)
+ try:
+ queue.get_nowait()
+ except pyqueue.Empty as e:
+ wr = weakref.ref(e)
+ self.assertEqual(wr(), None)
+
+ def test_dispatch(self):
+ if gc.isenabled():
+ gc.disable()
+ self.addCleanup(gc.enable)
+ try:
+ multiprocessing.managers.dispatch(FakeConnection(), None, None)
+ except pyqueue.Empty as e:
+ wr = weakref.ref(e)
+ self.assertEqual(wr(), None)
+
#
#
#