Skip to content

Commit

Permalink
pythongh-110300: Fix Refleaks in test_interpreters and test__xxinterp…
Browse files Browse the repository at this point in the history
…channels (pythongh-110318)
  • Loading branch information
ericsnowcurrently authored Oct 4, 2023
1 parent 625ecbe commit 269005e
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 10 deletions.
3 changes: 2 additions & 1 deletion Lib/test/support/interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,5 @@ def close(self):
_channels.close(self._id, send=True)


_channels._register_end_types(SendChannel, RecvChannel)
# XXX This is causing leaks (gh-110318):
#_channels._register_end_types(SendChannel, RecvChannel)
26 changes: 19 additions & 7 deletions Lib/test/test_interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ def run():

class TestBase(unittest.TestCase):

def pipe(self):
def ensure_closed(fd):
try:
os.close(fd)
except OSError:
pass
r, w = os.pipe()
self.addCleanup(lambda: ensure_closed(r))
self.addCleanup(lambda: ensure_closed(w))
return r, w

def tearDown(self):
clean_up_interpreters()

Expand Down Expand Up @@ -262,7 +273,7 @@ def test_subinterpreter(self):
self.assertFalse(interp.is_running())

def test_finished(self):
r, w = os.pipe()
r, w = self.pipe()
interp = interpreters.create()
interp.run(f"""if True:
import os
Expand Down Expand Up @@ -299,8 +310,8 @@ def test_bad_id(self):
interp.is_running()

def test_with_only_background_threads(self):
r_interp, w_interp = os.pipe()
r_thread, w_thread = os.pipe()
r_interp, w_interp = self.pipe()
r_thread, w_thread = self.pipe()

DONE = b'D'
FINISHED = b'F'
Expand Down Expand Up @@ -425,8 +436,8 @@ def test_still_running(self):
self.assertTrue(interp.is_running())

def test_subthreads_still_running(self):
r_interp, w_interp = os.pipe()
r_thread, w_thread = os.pipe()
r_interp, w_interp = self.pipe()
r_thread, w_thread = self.pipe()

FINISHED = b'F'

Expand Down Expand Up @@ -532,8 +543,8 @@ def test_bytes_for_script(self):
interp.run(b'print("spam")')

def test_with_background_threads_still_running(self):
r_interp, w_interp = os.pipe()
r_thread, w_thread = os.pipe()
r_interp, w_interp = self.pipe()
r_thread, w_thread = self.pipe()

RAN = b'R'
DONE = b'D'
Expand Down Expand Up @@ -822,6 +833,7 @@ def test_list_all(self):
after = set(interpreters.list_all_channels())
self.assertEqual(after, created)

@unittest.expectedFailure # See gh-110318:
def test_shareable(self):
rch, sch = interpreters.create_channel()

Expand Down
11 changes: 9 additions & 2 deletions Modules/_xxinterpchannelsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1992,6 +1992,7 @@ _get_current_channel_end_type(int end)
return NULL;
}
}
Py_DECREF(highlevel);
if (end == CHANNEL_SEND) {
cls = state->send_channel_type;
}
Expand All @@ -2012,6 +2013,7 @@ _channel_end_from_xid(_PyCrossInterpreterData *data)
}
PyTypeObject *cls = _get_current_channel_end_type(cid->end);
if (cls == NULL) {
Py_DECREF(cid);
return NULL;
}
PyObject *obj = PyObject_CallOneArg((PyObject *)cls, (PyObject *)cid);
Expand All @@ -2027,7 +2029,9 @@ _channel_end_shared(PyThreadState *tstate, PyObject *obj,
if (cidobj == NULL) {
return -1;
}
if (_channelid_shared(tstate, cidobj, data) < 0) {
int res = _channelid_shared(tstate, cidobj, data);
Py_DECREF(cidobj);
if (res < 0) {
return -1;
}
data->new_object = _channel_end_from_xid;
Expand Down Expand Up @@ -2464,7 +2468,10 @@ channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
PyTypeObject *cls = state->ChannelIDType;
assert(get_module_from_owned_type(cls) == self);

PyObject *mod = get_module_from_owned_type(cls);
assert(mod == self);
Py_DECREF(mod);

return _channelid_new(self, cls, args, kwds);
}
Expand Down

0 comments on commit 269005e

Please sign in to comment.