| Ticket UUID: | f10d91c2d39e1b015be44c41840f4cd0b4f4640 | ||
| Title: | dead-console busy-loop in tclWinConsole.c | ||
| Type: | Bug | Created on: | 2026-07-12 03:30:07 |
| Submitter: | juliannoble2 | Assigned to: | apnadkarni |
| Subsystem: | 02. Event Loops | Severity: | Important |
| Priority: | 5 Medium | Last modified: | 2026-09-18 17:52:23 |
| Status: | Closed | Closed by: | sebres |
| Resolution: | Fixed | Closed on: | 2026-09-18 17:52:23 |
| Version: | 9 | ||
| Description: | ||||
process orphaned by console-host death busy-loops two threads indefinitely. This is a placeholder ticket because CDN gates aggressively. Unclear what text in here triggers it. Backchannel for ticket details? | ||||
| User Comments: | ||||
juliannoble2 added on 2026-07-12 04:01:53:
My failed initial ticket submission was clearly marked described as having been generated by use of Fable 5 - with my own preamble. I mentioned that it should be taken with a grain of salt as to whether this is triggered in real-world application use versus the llm generated scratch scripts and testing harnesses that caught this. I was able to reproduce the effect using the generated repro powershell scripts and noticed increased cpu use and fan spinups. First part of report here. I've ommitted the rest under the guess that CDN was triggered by code samples rather than detecting AI content. llm was pointed at up to date tcl source and did a fairly full analysis with suggestions. Ping me for more if it seems interesting. ------------------------------------------------------ **Component:** win/tclWinConsole.c (channel driver) **Versions affected:** verified 9.0.2 and 9.0.3 on Windows 11 (build 26200); the defective code paths are unchanged in 9.1b1 sources. Tcl 8.6 is not affected (pre-rewrite console driver; different mechanism). **Severity:** Serious. Each occurrence leaves a near-invisible orphan burning ~1-2 cores forever, and occurrences accumulate: nothing ever reaps them, so every console-host death against a fileevent-reading tclsh adds one. Eight concurrent orphans produced an audible thermal/fan response on the test workstation while still showing nothing conspicuous in Task Manager (see Observability). ## Summary When the console *server* (conhost.exe) serving a Tcl 9 process dies without the client being terminated, a script with a `chan event stdin readable` handler is never notified: the driver detects the error internally, but the event it queues for the interp thread is discarded before `Tcl_NotifyChannel`, so no readable event, no EOF, no read error ever reaches script level. Meanwhile the driver's console reader thread busy-loops on the persistent error with no wait, and its continuous watcher-nudging keeps the interp thread's event loop cycling at zero block time. The process cannot even implement its own defence via fileevents - only a poll (see Workaround) can see the condition. ## Real-world triggers (legitimate application scenarios) The reproduction below force-kills a conhost to make the trigger deterministic, but the same client-side state - console server gone, client alive - arises in ordinary use. Exposed application profile: any long-running Tcl program that reads console stdin via a fileevent - a REPL, a monitor accepting operator commands, a server with console control input - since the trigger is entirely outside the application's control: - **A user kills a hung console window via Task Manager.** Killing "Console Window Host" (conhost.exe) is common folk-advice for a stuck window; TerminateProcess delivers no CTRL_CLOSE_EVENT, so the client survives against a dead console. (Identical mechanism to the scripted repro - verified.) - **conhost.exe crashes.** The host is an ordinary user-mode process; when it dies of its own bug the client is orphaned exactly as above. - **A terminal emulator crashes.** A clean close runs ConPTY/tab teardown that terminates the client tree, but a *crashed* terminal (Windows Terminal or third-party) never runs that cleanup; its console server goes away ungracefully. (Plausible-by-mechanism; untested here - the classic-conhost case is the verified repro.) - **Automation/CI harnesses that kill their console host.** A harness that launches work under a hidden console (Start-Process -WindowStyle Hidden, scheduled tasks, agent runners) and later "cleans up" by killing the launcher or host process - without a job object that covers the clients - leaves the worker tclsh orphaned. This is how the bug was first hit in production use: an interactive shell under a hidden console outlived its host and was found 37 minutes later with ~1550 cpu-seconds accumulated, discovered only because it polluted a test harness's process-liveness checks. - **Session teardown edge cases.** Any path where the session infrastructure tears down the console host before (or without) terminating its clients produces the same state. In every case the failure compounds: each event adds one immortal spinner, and the Observability section explains why nobody notices them. <elided> apnadkarni added on 2026-07-12 11:26:40:
Sounds like something that should be fixed. Since you cannot seem to post the script here, could you post it in some pastebin? So I can verify once it's fixed? juliannoble2 added on 2026-07-13 01:43:41:
full Fable 5 text at: http://paste.tclers.tk/6226 apnadkarni added on 2026-07-13 02:54:01:
Thanks for the paste. I reached pretty much an identical conclusion inspecting the code yesterday. I was able to manually trigger the condition by killing from twapi. Actually, quite impressed with the diagnosis from Fable. I'm now officially redundant :-) apnadkarni added on 2026-07-13 07:59:33:
Proposed fix is in [bug-f10d91c2] branch. However, note that with the fix in place, the process still does not exit though CPU usage is 0. This is by intent as it is not clear (at the driver level) whether process should exit on stdin closure, and secondly, whether errors should be treated as eof. IMO, it is up to the stdin file event handler to catch the error that will be generated on the read in the event callback and take appropriate action (exit or whatever.) apnadkarni added on 2026-07-14 16:28:15:
Fixed in [49925e3365] sebres added on 2026-09-18 17:52:23:
I don't think it is good idea to cover tcl-tests with ps scripts (cannot it be scripted in tcl?)... Then you'd see something like this:
I fixed it in [6128e26dc47a54bd] by skipping the test in case of policy violation, but... | ||||
