Skip to content

gh-161353: Fix handle leak in test_tcl - #161368

Open
vstinner wants to merge 1 commit into
python:mainfrom
vstinner:test_tcl_finalize_thread
Open

vstinner wants to merge 1 commit into
python:mainfrom
vstinner:test_tcl_finalize_thread

Conversation

@vstinner

@vstinner vstinner commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

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 _tkinter.finalize_thread() function.

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 _tkinter.finalize_thread() function.
@vstinner

vstinner commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

See #161353 (comment) for the longer rationale.

@serhiy-storchaka @terryjreedy @gpshead: Would you mind to review my fix?

@vstinner

vstinner commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

This fix should be backported to 3.15 once #161071 will be merged.

@hugovk hugovk added needs backport to 3.15 bugs and security fixes and removed needs backport to 3.15 bugs and security fixes labels Nov 5, 2026
@vstinner

vstinner commented Nov 5, 2026

Copy link
Copy Markdown
Member Author

An alternative would be to register an atexit callback with threading._register_atexit() to call _tkinter.finalize_thread(). But I don't understand well if Tcl/Tk already cleans the thread state automatically when a thread exits, or only when the process exits.

I mean, I don't understand well if the handle leak (one Windows event) only impacts tests, or call impact real Python code.

@encukou

encukou commented Nov 5, 2026

Copy link
Copy Markdown
Member

!buildbot AMD64.Windows.Server.2025.Refleaks.

@bedevere-bot

Copy link
Copy Markdown

🤖 New build scheduled with the buildbot fleet by @encukou for commit bc80f6a 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F161368%2Fmerge

The command will test the builders whose names match following regular expression: AMD64.Windows.Server.2025.Refleaks.

The builders matched are:

  • AMD64 Windows Server 2025 Refleaks PR

@serhiy-storchaka
serhiy-storchaka self-requested a review November 5, 2026 18:53
@serhiy-storchaka

Copy link
Copy Markdown
Member

_tkinter.finalize_thread() is a large footgun. It does far more than close that event handle, and the damage is silent until later. I will try to find more focused fix, but I afraid that the only feasible solution is to change the test.

@serhiy-storchaka

Copy link
Copy Markdown
Member

Well, the simplest fix is to skip the test in the leak-hunting mode.

The leak is still here, but it is small, and once per thread.

@vstinner

vstinner commented Nov 5, 2026

Copy link
Copy Markdown
Member Author

_tkinter.finalize_thread() is a large footgun. It does far more than close that event handle, and the damage is silent until later.

In my PR, _tkinter.finalize_thread() is called when the thread exits, so I'm not sure of what you mean by "later"?

Do you mean executing more Tcl/Tk code after calling _tkinter.finalize_thread()?

Would you prefer to rename the function to _tkinter._finalize_thread() (add an underscore prefix) to highlight that it should only be used in tests, or if you really understand what you're doing?

@serhiy-storchaka

Copy link
Copy Markdown
Member

Adding an underscore and changing the docstring will help. But skipping the test is simpler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants