Tcl Source Code

View Ticket
Login
Ticket UUID: d48728e10b820296e45fa73202e135f90952cb46
Title: Blocking [gets] on a [chan push] transformed channel waits for 4096 bytes or EOF
Type: Bug Created on: 2026-10-17 10:51:11
Submitter: serhiy.storchaka Assigned to:
Subsystem: 26. Channel Transforms Severity: Important
Priority: 5 Medium Last modified: 2026-10-20 18:11:28
Status: Open Closed by:
Resolution: None Closed on:
Version: 8.6.18, 9.0.5, 9.1.0
Description:

A blocking [gets] (or [read $ch $n]) on a channel with a reflected transform ([chan push]) does not return while complete lines are available. It waits until the transform has filled the whole 4096-byte input buffer or the other side closes the channel. Without the transform the same [gets] returns at once.

Repro with a pipe (a socket behaves the same):

proc xform {cmd handle args} {
    switch -- $cmd {
        initialize {return {initialize finalize read write}}
        finalize {}
        read - write {return [lindex $args 0]}
    }
}
# child writes three lines and keeps its stdout open for 3 seconds
set f [open [list | [info nameofexecutable] << {
    puts -nonewline "one\ntwo\nthree\n"; flush stdout; after 3000
}] r]
chan push $f xform
after 500
set t0 [clock milliseconds]
set line [gets $f]
puts "gets -> $line after [expr {[clock milliseconds]-$t0}] ms"

Actual: gets -> one after 2500 ms (returns only when the child exits).

Expected: gets -> one after 0 ms, as without the [chan push].

Cause: ReflectInput() in generic/tclIORTrans.c loops "until the request is satisfied" and calls Tcl_ReadRaw() on the parent channel again after it already has data. In blocking mode that second read blocks. Only the non-blocking case returns a short read (when Tcl_InputBlocked() reports it). A plain channel driver returns what one read gives, so ReflectInput() could stop reading from the parent once it has some data.

The loop dates from the TIP #230 implementation [057ba9eab5]. Reproduced with 8.6.0 through 8.6.18, 9.0.5 and main (Linux, pipes and sockets).

User Comments:
serhiy.storchaka added on 2026-10-17 11:39:03:

Proposed fix in branch transform-short-read: ReflectInput() returns a short read once it has data, as other channel drivers do; [gets] and [read] ask again if they need more. Test iortrans-bug-d48728e10b.