gh-106558: break ref cycles through exceptions in multiprocessing manager (#106559)
This commit is contained in:
parent
caa41a4f1d
commit
5f7d4ecf30
@ -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):
|
||||
'''
|
||||
|
@ -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)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
@ -0,0 +1,3 @@
|
||||
Remove ref cycle in callers of
|
||||
:func:`~multiprocessing.managers.convert_to_error` by deleting ``result``
|
||||
from scope in a ``finally`` block.
|
Loading…
x
Reference in New Issue
Block a user