Skip to content

gh-83274: Stop deallocation of Tkapp causing Python interpreter crash #21532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
31 changes: 31 additions & 0 deletions Lib/tkinter/test/test_tkinter/test_misc.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import unittest
import subprocess
import sys
import threading
import tkinter
from test import support
from tkinter.test.support import AbstractTkTest

support.requires('gui')

def test_thread_gc():
root = tkinter.Tk()
root.destroy()
ev = threading.Event()
threading.Thread(target=lambda obj: ev.wait(), args=(root,)).start()
del root
ev.set()
print("passed")

class MiscTest(AbstractTkTest, unittest.TestCase):

def test_all(self):
Expand All @@ -26,6 +38,25 @@ def test_repr(self):
f = tkinter.Frame(t, name='child')
self.assertEqual(repr(f), '<tkinter.Frame object .top.child>')

def test_thread_gc(self):
p = subprocess.Popen([sys.executable, "-c",
"from tkinter.test.test_tkinter import test_misc; "
"test_misc.test_thread_gc()"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
stderr = stderr.strip()
try:
self.assertTrue(b"Exception ignored in: <class 'RuntimeWarning'>" in stderr)
self.assertTrue(b"RuntimeWarning: Deallocation of Tkapp attempted in wrong "
b"thread. Skipping deletion of Tcl interpreter (this will "
b"cause a memory leak)." in stderr)
except AssertionError:
# If there is an error in the subprocess
# we need to be able to debug it
print(stderr.decode("utf-8"), file=sys.stderr)
raise
self.assertEqual(stdout.strip(), b"passed")

def test_generated_names(self):
t = tkinter.Toplevel(self.root)
f = tkinter.Frame(t)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed crash when Tcl interpreter was deallocated in wrong thread
17 changes: 13 additions & 4 deletions Modules/_tkinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3040,10 +3040,19 @@ static void
Tkapp_Dealloc(PyObject *self)
{
PyObject *tp = (PyObject *) Py_TYPE(self);
/*CHECK_TCL_APPARTMENT;*/
ENTER_TCL
Tcl_DeleteInterp(Tkapp_Interp(self));
LEAVE_TCL
if (((TkappObject *)self)->threaded && \
((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) {
// We cannot delete the interpreter in the wrong thread (bpo-39093)
PyErr_SetString(PyExc_RuntimeWarning, "Deallocation of Tkapp " \
"attempted in wrong thread. Skipping deletion of Tcl " \
"interpreter (this will cause a memory leak).");
PyErr_WriteUnraisable(PyErr_Occurred());
PyErr_Clear();
} else {
ENTER_TCL
Tcl_DeleteInterp(Tkapp_Interp(self));
LEAVE_TCL
}
PyObject_Del(self);
Py_DECREF(tp);
DisableEventHook();
Expand Down