summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2023-10-04 00:36:50 (GMT)
committerGitHub <noreply@github.com>2023-10-04 00:36:50 (GMT)
commit269005e78429d6ee518643daa633e9aa7e8b9c33 (patch)
tree7e2ee89bca5a30b844ca3b64a411b2c1fe22cef7
parent625ecbe92eb69d2850c2e6dbe9538e9b1a098baa (diff)
downloadcpython-269005e78429d6ee518643daa633e9aa7e8b9c33.zip
cpython-269005e78429d6ee518643daa633e9aa7e8b9c33.tar.gz
cpython-269005e78429d6ee518643daa633e9aa7e8b9c33.tar.bz2
gh-110300: Fix Refleaks in test_interpreters and test__xxinterpchannels (gh-110318)
-rw-r--r--Lib/test/support/interpreters.py3
-rw-r--r--Lib/test/test_interpreters.py26
-rw-r--r--Modules/_xxinterpchannelsmodule.c11
3 files changed, 30 insertions, 10 deletions
diff --git a/Lib/test/support/interpreters.py b/Lib/test/support/interpreters.py
index d2beba3..3b50161 100644
--- a/Lib/test/support/interpreters.py
+++ b/Lib/test/support/interpreters.py
@@ -215,4 +215,5 @@ class SendChannel(_ChannelEnd):
_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)
diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py
index ffdd8a1..f2ef172 100644
--- a/Lib/test/test_interpreters.py
+++ b/Lib/test/test_interpreters.py
@@ -68,6 +68,17 @@ def _running(interp):
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()
@@ -262,7 +273,7 @@ class TestInterpreterIsRunning(TestBase):
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
@@ -299,8 +310,8 @@ class TestInterpreterIsRunning(TestBase):
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'
@@ -425,8 +436,8 @@ class TestInterpreterClose(TestBase):
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'
@@ -532,8 +543,8 @@ class TestInterpreterRun(TestBase):
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'
@@ -822,6 +833,7 @@ class TestChannels(TestBase):
after = set(interpreters.list_all_channels())
self.assertEqual(after, created)
+ @unittest.expectedFailure # See gh-110318:
def test_shareable(self):
rch, sch = interpreters.create_channel()
diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c
index d5be76f..d762f44 100644
--- a/Modules/_xxinterpchannelsmodule.c
+++ b/Modules/_xxinterpchannelsmodule.c
@@ -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;
}
@@ -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);
@@ -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;
@@ -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);
}