summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclIO.c19
-rw-r--r--tests/io.test84
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.