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()
|
kind, result = c.recv()
|
||||||
if kind == '#RETURN':
|
if kind == '#RETURN':
|
||||||
return result
|
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):
|
def convert_to_error(kind, result):
|
||||||
if kind == '#ERROR':
|
if kind == '#ERROR':
|
||||||
@ -833,7 +836,10 @@ class BaseProxy(object):
|
|||||||
conn = self._Client(token.address, authkey=self._authkey)
|
conn = self._Client(token.address, authkey=self._authkey)
|
||||||
dispatch(conn, None, 'decref', (token.id,))
|
dispatch(conn, None, 'decref', (token.id,))
|
||||||
return proxy
|
return proxy
|
||||||
raise convert_to_error(kind, result)
|
try:
|
||||||
|
raise convert_to_error(kind, result)
|
||||||
|
finally:
|
||||||
|
del result # break reference cycle
|
||||||
|
|
||||||
def _getvalue(self):
|
def _getvalue(self):
|
||||||
'''
|
'''
|
||||||
|
@ -3149,6 +3149,44 @@ class _TestManagerRestart(BaseTestCase):
|
|||||||
if hasattr(manager, "shutdown"):
|
if hasattr(manager, "shutdown"):
|
||||||
self.addCleanup(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