diff options
| -rw-r--r-- | generic/tclIO.c | 19 | ||||
| -rw-r--r-- | tests/io.test | 84 |
2 files changed, 98 insertions, 5 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 6461909..bc1b1c6 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -4749,6 +4749,12 @@ Tcl_GetsObj( ResetFlag(statePtr, CHANNEL_BLOCKED); while (1) { if (dst >= dstEnd) { + /* + * In case of encoding errors, state gets flag + * CHANNEL_ENCODING_ERROR set in the call below. First, the + * EOF/EOL condition is checked, as we may have valid data with + * EOF/EOL before the encoding error. + */ if (FilterInputBytes(chanPtr, &gs) != 0) { goto restore; } @@ -4918,8 +4924,17 @@ Tcl_GetsObj( } goto gotEOL; } else if (gs.bytesWrote == 0 - && GotFlag(statePtr, CHANNEL_ENCODING_ERROR) - && !GotFlag(statePtr, CHANNEL_NONBLOCKING)) { + && GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) { + /* Ticket c4eb46a1 Harald Oehlmann 2023-11-12 debugging session. + * In non blocking mode we loop indifenitly on a decoding error in + * this while-loop. + * Removed the following from the upper condition: + * "&& !GotFlag(statePtr, CHANNEL_NONBLOCKING)" + * In case of an encoding error with leading correct bytes, we pass here + * two times, as gs.bytesWrote is not 0 on the first pass. This feels + * once to much, as the data is anyway not used. + */ + /* Set eol to the position that caused the encoding error, and then * continue to gotEOL, which stores the data that was decoded * without error to objPtr. This allows the caller to do something diff --git a/tests/io.test b/tests/io.test index 9f731ad..7e62e6b 100644 --- a/tests/io.test +++ b/tests/io.test @@ -9193,7 +9193,7 @@ test io-75.5 {invalid utf-8 encoding read is ignored (-profile tcl8)} -setup { removeFile io-75.5 } -result 4181 -test io-75.6 {invalid utf-8 encoding, gets is not ignored (-profile strict)} -setup { +test io-75.6 {incomplete utf-8 encoding, blocking gets is not ignored (-profile strict)} -setup { set fn [makeFile {} io-75.6] set f [open $fn w+] fconfigure $f -encoding binary @@ -9211,6 +9211,84 @@ test io-75.6 {invalid utf-8 encoding, gets is not ignored (-profile strict)} -se } -match glob -returnCodes 1 -result {error reading "file*":\ invalid or incomplete multibyte or wide character} +test io-75.6.1 {invalid utf-8 encoding, blocking gets is not ignored (-profile strict)} -setup { + set fn [makeFile {} io-75.6.1] + set f [open $fn w+] + fconfigure $f -encoding binary + # utf-8: \xC3 requires a 2nd byte > x80, but <x80 is delivered + puts -nonewline $f A\xC3B + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -eofchar {} \ + -translation lf -profile strict +} -body { + gets $f +} -cleanup { + close $f + removeFile io-75.6.1 +} -match glob -returnCodes 1 -result {error reading "file*":\ + invalid or incomplete multibyte or wide character} + +test io-75.6.2 {invalid utf-8 encoding, blocking gets is not ignored (-profile strict), recover functionality} -setup { + set fn [makeFile {} io-75.6.2] + set f [open $fn w+] + fconfigure $f -encoding binary + # utf-8: \xC3 requires a 2nd byte > x80, but <x80 is delivered + puts -nonewline $f A\xC3B + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -eofchar {} \ + -translation lf -profile strict +} -body { + set l {} + lappend l [catch {gets $f}] + lappend l [tell $f] + fconfigure $f -encoding binary + lappend l [expr {[gets $f] eq "A\xC3B"}] +} -cleanup { + close $f + removeFile io-75.6.2 +} -match glob -returnCodes 0 -result {1 0 1} + +# TCL ticket c4eb46a196: non blocking case had endless loop, so test it +test io-75.6.3 {invalid utf-8 encoding, non blocking gets is not ignored (-profile strict)} -setup { + set fn [makeFile {} io-75.6.3] + set f [open $fn w+] + fconfigure $f -encoding binary + # utf-8: \xC3 requires a 2nd byte > x80, but <x80 is delivered + puts -nonewline $f A\xC3B + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -eofchar {} \ + -translation lf -profile strict -blocking 0 +} -body { + gets $f +} -cleanup { + close $f + removeFile io-75.6.3 +} -match glob -returnCodes 1 -result {error reading "file*":\ + invalid or incomplete multibyte or wide character} + +test io-75.6.4 {incomplete utf-8 encoding, non blocking gets is not ignored (-profile strict)} -setup { + set fn [makeFile {} io-75.6.4] + set f [open $fn w+] + fconfigure $f -encoding binary + # \x81 is an incomplete byte sequence in utf-8 + puts -nonewline $f A\x81 + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -eofchar {} \ + -translation lf -profile strict -blocking 0 +} -body { + gets $f + # only the 2nd gets returns the error + gets $f +} -cleanup { + close $f + removeFile io-75.6.4 +} -match glob -returnCodes 1 -result {error reading "file*":\ + invalid or incomplete multibyte or wide character} + test io-75.7 { invalid utf-8 encoding read is not ignored (-profile strict) } -setup { @@ -9232,7 +9310,7 @@ test io-75.7 { } -match glob -result {1 {error reading "file*":\ invalid or incomplete multibyte or wide character}} -test io-75.8 {invalid utf-8 encoding eof handling (-profile strict)} -setup { +test io-75.8 {invalid utf-8 encoding eof first handling (-profile strict)} -setup { set fn [makeFile {} io-75.8] set f [open $fn w+] fconfigure $f -encoding binary @@ -9254,7 +9332,7 @@ test io-75.8 {invalid utf-8 encoding eof handling (-profile strict)} -setup { removeFile io-75.8 } -result {41 1 {}} -test io-75.8.eoflater {invalid utf-8 encoding eof handling (-profile strict)} -setup { +test io-75.8.eoflater {invalid utf-8 encoding eof after handling (-profile strict)} -setup { set fn [makeFile {} io-75.8] set f [open $fn w+] # This also configures the channel encoding profile as strict. |
