https://github.com/python/cpython/commit/e7dccf087096d39dc5de1312be4e4bacd9e021ef commit: e7dccf087096d39dc5de1312be4e4bacd9e021ef branch: 3.15 author: Gregory P. Smith <[email protected]> committer: vstinner <[email protected]> date: 2026-11-09T12:02:02+01:00 summary:
[3.15] gh-161353: Fix handle leak in test_tcl (GH-161368) (#161650) Fix handle leaks in test_tcl when the test is run with -R 3:3. Call explicitly Tcl_FinalizeThread() in test_returning_deeply_nested() to clean up explicitly per-thread state. The test is run in a thread because of the @run_with_limited_c_stack() decorator. On Windows, Tcl_CreateInterp() creates an event in the Tcl notifier implementation. The event is stored in per-thread state which is only cleaned up at exit. Add the private _tkinter._finalize_thread() function. (cherry picked from commit 2781ffe1f29b0ecf64b011c927ad71df2321b6af) Co-authored-by: Victor Stinner <[email protected]> files: M Lib/test/test_tcl.py M Modules/_tkinter.c M Modules/clinic/_tkinter.c.h diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 0707b05af03a433..1442cb18dd05691 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -595,6 +595,11 @@ def test_returning_deeply_nested(self): interp.eval('set x a; for {set i 0} {$i < %d} {incr i} {set x [list $x]}' % support.exceeds_recursion_limit()) self.assertRaises(RecursionError, interp.getvar, 'x') + interp = None + + # gh-161353: Clean up explicitly per-thread state to avoid leaking an + # event handle on Windows when test_tcl is run with -R 3:3 option. + _tkinter._finalize_thread() def test_setvar_evil(self): # gh-161388 diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index b4a0215d11edc1e..09928b6e1a849ba 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3399,6 +3399,20 @@ _tkinter_getbusywaitinterval_impl(PyObject *module) return Tkinter_busywaitinterval; } +/*[clinic input] +_tkinter._finalize_thread + +Clean up per-thread state. +[clinic start generated code]*/ + +static PyObject * +_tkinter__finalize_thread_impl(PyObject *module) +/*[clinic end generated code: output=4ed0d3be4d1f8de8 input=ea68096ee9b83d23]*/ +{ + Tcl_FinalizeThread(); + Py_RETURN_NONE; +} + #include "clinic/_tkinter.c.h" static PyMethodDef Tktt_methods[] = @@ -3490,6 +3504,7 @@ static PyMethodDef moduleMethods[] = _TKINTER_CREATE_METHODDEF _TKINTER_SETBUSYWAITINTERVAL_METHODDEF _TKINTER_GETBUSYWAITINTERVAL_METHODDEF + _TKINTER__FINALIZE_THREAD_METHODDEF {NULL, NULL} }; diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h index 3147cf7f9d2cff3..27bad6cd33e6665 100644 --- a/Modules/clinic/_tkinter.c.h +++ b/Modules/clinic/_tkinter.c.h @@ -960,6 +960,24 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +PyDoc_STRVAR(_tkinter__finalize_thread__doc__, +"_finalize_thread($module, /)\n" +"--\n" +"\n" +"Clean up per-thread state."); + +#define _TKINTER__FINALIZE_THREAD_METHODDEF \ + {"_finalize_thread", (PyCFunction)_tkinter__finalize_thread, METH_NOARGS, _tkinter__finalize_thread__doc__}, + +static PyObject * +_tkinter__finalize_thread_impl(PyObject *module); + +static PyObject * +_tkinter__finalize_thread(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _tkinter__finalize_thread_impl(module); +} + #ifndef _TKINTER_TKAPP_CREATEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_CREATEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_CREATEFILEHANDLER_METHODDEF) */ @@ -967,4 +985,4 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=c807adb73e305725 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=83f034c0d0887f2e input=a9049054013a1b77]*/ _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
