[gdb/testsuite,Tcl,9] Fix EILSEQ problems for UTF8 related tests

Message ID 20260525051442.2805651-2-kevinb@redhat.com
State New
Headers
Series [gdb/testsuite,Tcl,9] Fix EILSEQ problems for UTF8 related tests |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed

Commit Message

Kevin Buettner May 25, 2026, 5:14 a.m. UTC
  On Fedora 44 and Rawhide (Fedora 45), these tests...

  gdb.ada/non-ascii-utf-8.exp
  gdb.base/utf8-identifiers.exp
  gdb.rust/unicode.exp

...all die due to these errors:

  Running ...gdb/testsuite/gdb.base/utf8-identifiers.exp ...
  ERROR: tcl error sourcing .../gdb/testsuite/gdb.base/utf8-identifiers.exp.
  ERROR: tcl error code POSIX EILSEQ {invalid or incomplete multibyte or wide character}
  error writing "file6": invalid or incomplete multibyte or wide character
  ...

(I've shortened some of the pathnames for brevity.)

These Fedora systems are using Tcl 9 and also an updated version of
dejagnu with this change applied:

  * Thu Apr 16 2026 Jakub Jelinek <jakub@redhat.com> - 1:1.6.3-17
  - Apply full set of Tcl 9 compatibility fixes from upstream PR80674 branch
    (#2448542)

That runtest change is responsible for the POSIX EILSEQ errors on
machines with that change.  The change to runtest causing the change
in behavior for GDB is the addition of these lines near the top of
the runtest script:

  # Ensure that DejaGnu will be run in the POSIX locale
  LC_ALL=C
  export LC_ALL

TCL 8 used a permissive encoding strategy: bytes that could not be
represented in the current encoding were silently mangled or
substituted.  TCL 9 changed this default to a strict profile, which
means that any attempt to write a character that cannot be expressed
in the channel's encoding raises a POSIX EILSEQ error ("invalid or
incomplete multibyte or wide character").

So, together, this Tcl 9 behavior combined with the dejagnu change
to runtest causes the EILSEQ error for the tests mentioned earlier.

Fix it by using "fconfigure $handle -encoding utf-8 -profile replace"
in proc spawn_capture_tty_name, and proc gdb_stdin_log_init.  Also,
the open_logs wrapper has been changed to invoke fconfigure using only
"-encoding utf-8".  Testing showed that "-profile replace" wasn't
necessary there.

Tested on Fedora 28 (Tcl 8.6.8), Fedora 43 (Tcl 9.0.2 / 8.6.16; expect
uses 8.6.16), Fedora 44 (Tcl 9.0.2 / 8.6.17; expect uses 9.0.2), and
Rawhide / Fedora 45 (Tcl 9.0.3 / 8.6.18; expect uses 9.0.3).
---
 gdb/testsuite/lib/gdb.exp | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
  

Comments

Tom de Vries May 26, 2026, 9:22 a.m. UTC | #1
On 5/25/26 7:14 AM, Kevin Buettner wrote:
> On Fedora 44 and Rawhide (Fedora 45), these tests...
> 
>    gdb.ada/non-ascii-utf-8.exp
>    gdb.base/utf8-identifiers.exp
>    gdb.rust/unicode.exp
> 
> ...all die due to these errors:
> 
>    Running ...gdb/testsuite/gdb.base/utf8-identifiers.exp ...
>    ERROR: tcl error sourcing .../gdb/testsuite/gdb.base/utf8-identifiers.exp.
>    ERROR: tcl error code POSIX EILSEQ {invalid or incomplete multibyte or wide character}
>    error writing "file6": invalid or incomplete multibyte or wide character
>    ...
> 
> (I've shortened some of the pathnames for brevity.)
> 
> These Fedora systems are using Tcl 9 and also an updated version of
> dejagnu with this change applied:
> 
>    * Thu Apr 16 2026 Jakub Jelinek <jakub@redhat.com> - 1:1.6.3-17
>    - Apply full set of Tcl 9 compatibility fixes from upstream PR80674 branch
>      (#2448542)
> 
> That runtest change is responsible for the POSIX EILSEQ errors on
> machines with that change.  The change to runtest causing the change
> in behavior for GDB is the addition of these lines near the top of
> the runtest script:
> 
>    # Ensure that DejaGnu will be run in the POSIX locale
>    LC_ALL=C
>    export LC_ALL
> 
> TCL 8 used a permissive encoding strategy: bytes that could not be
> represented in the current encoding were silently mangled or
> substituted.  TCL 9 changed this default to a strict profile, which
> means that any attempt to write a character that cannot be expressed
> in the channel's encoding raises a POSIX EILSEQ error ("invalid or
> incomplete multibyte or wide character").
> 
> So, together, this Tcl 9 behavior combined with the dejagnu change
> to runtest causes the EILSEQ error for the tests mentioned earlier.
> 
> Fix it by using "fconfigure $handle -encoding utf-8 -profile replace"
> in proc spawn_capture_tty_name, and proc gdb_stdin_log_init.  Also,
> the open_logs wrapper has been changed to invoke fconfigure using only
> "-encoding utf-8".  Testing showed that "-profile replace" wasn't
> necessary there.
> 

Hi Kevin,

this LGTM, so:

Reviewed-By: Tom de Vries <tdevries@suse.de>

I also reviewed this using Claude code, and there were two notes:
- using catch for one fconfigure, but not the other two.
- it might be a good idea to add a comment in open_logs to make it
   explicit that unlike elsewhere, "-profile replace" isn't used.

Thanks,
- Tom

> Tested on Fedora 28 (Tcl 8.6.8), Fedora 43 (Tcl 9.0.2 / 8.6.16; expect
> uses 8.6.16), Fedora 44 (Tcl 9.0.2 / 8.6.17; expect uses 9.0.2), and
> Rawhide / Fedora 45 (Tcl 9.0.3 / 8.6.18; expect uses 9.0.3).
> ---
>   gdb/testsuite/lib/gdb.exp | 33 +++++++++++++++++++++++++++++++++
>   1 file changed, 33 insertions(+)
> 
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 28709004570..52e4be9122d 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -166,6 +166,27 @@ proc load_lib { file } {
>       return $result
>   }
>   
> +# Tcl 9.0 changed the default channel encoding profile to "strict".  When
> +# runtest sets LC_ALL=C the system encoding is iso8859-1, so file channels
> +# opened by DejaGNU (gdb.sum, gdb.log) and spawn channels (for GDB and
> +# subprocesses) default to iso8859-1 with strict profile.  Writing
> +# non-Latin-1 characters in test names then raises EILSEQ, and sending them
> +# to GDB truncates the command at the unrepresentable character.
> +#
> +# Fix this by:
> +# 1. Overriding open_logs to reconfigure gdb.sum to utf-8 after DejaGNU
> +#    opens it with the system (iso8859-1) encoding.
> +# 2. Reconfiguring each new spawn channel to utf-8 in
> +#    spawn_capture_tty_name, which wraps every spawn call.
> +# 3. Reconfiguring gdb.in to utf-8 in gdb_stdin_log_init.
> +
> +rename open_logs saved_open_logs
> +proc open_logs {} {
> +    saved_open_logs
> +    global sum_file
> +    fconfigure $sum_file -encoding utf-8
> +}
> +
>   load_lib libgloss.exp
>   load_lib cache.exp
>   load_lib gdb-utils.exp
> @@ -2633,6 +2654,7 @@ proc gdb_file_cmd { arg {kill_flag 1} } {
>   proc spawn_capture_tty_name { args } {
>       set result [uplevel builtin_spawn $args]
>       upvar spawn_out spawn_out
> +    upvar spawn_id spawn_id
>       if { [info exists spawn_out(slave,name)] } {
>   	set ::last_spawn_tty_name $spawn_out(slave,name)
>       } else {
> @@ -2648,6 +2670,12 @@ proc spawn_capture_tty_name { args } {
>   	# use -nocomplain here we would otherwise get an error.
>   	unset -nocomplain ::last_spawn_tty_name
>       }
> +    # Tcl 9.0 defaults spawn channels to iso8859-1/strict, which raises
> +    # EILSEQ when non-Latin-1 characters (e.g. function names with UTF-8
> +    # letters) are written to or read from the channel.  Use utf-8 instead.
> +    if {[tcl_version_at_least 9 0 0]} {
> +	catch {fconfigure $spawn_id -encoding utf-8 -profile replace}
> +    }
>       return $result
>   }
>   
> @@ -10419,6 +10447,11 @@ proc gdb_stdin_log_init { } {
>       set logfile [standard_output_file_with_gdb_instance gdb.in]
>       set in_file [open $logfile w]
>   
> +    if {[tcl_version_at_least 9 0 0]} {
> +	# Tcl 9 strict profile: gdb.in must accept UTF-8 command strings.
> +	fconfigure $in_file -encoding utf-8 -profile replace
> +    }
> +
>       verbose -log ""
>       verbose -log "Starting logfile: $logfile"
>       verbose -log ""
  
Kevin Buettner May 26, 2026, 7:42 p.m. UTC | #2
Hi Tom,

On Tue, 26 May 2026 11:22:19 +0200
Tom de Vries <tdevries@suse.de> wrote:

> Hi Kevin,
> 
> this LGTM, so:
> 
> Reviewed-By: Tom de Vries <tdevries@suse.de>
> 
> I also reviewed this using Claude code, and there were two notes:
> - using catch for one fconfigure, but not the other two.
> - it might be a good idea to add a comment in open_logs to make it
>    explicit that unlike elsewhere, "-profile replace" isn't used.

Thanks for the reviews, both from yourself and from Claude Code.

After discussing it with my own AIs (both Claude and a local Qwen3.6
27B), I've made some documentation changes and a minor unrelated code
tweak, which should address the concerns about the use of "catch" in
one location, but not the others as well as the reason for the lack of
"-profile replace".  (I didn't want to introduce another form of Tcl
version guard in open_logs, which is why I investigated whether I
could dispense with use of "-profile replace".)  In any case, I think
it's now amply documented.

I posted a v2 here:

https://sourceware.org/pipermail/gdb-patches/2026-May/227637.html

Kevin
  
Tom de Vries May 28, 2026, 8:14 a.m. UTC | #3
On 5/26/26 9:42 PM, Kevin Buettner wrote:
> Hi Tom,
> 
> On Tue, 26 May 2026 11:22:19 +0200
> Tom de Vries <tdevries@suse.de> wrote:
> 
>> Hi Kevin,
>>
>> this LGTM, so:
>>
>> Reviewed-By: Tom de Vries <tdevries@suse.de>
>>
>> I also reviewed this using Claude code, and there were two notes:
>> - using catch for one fconfigure, but not the other two.
>> - it might be a good idea to add a comment in open_logs to make it
>>     explicit that unlike elsewhere, "-profile replace" isn't used.
> 
> Thanks for the reviews, both from yourself and from Claude Code.
> 
> After discussing it with my own AIs (both Claude and a local Qwen3.6
> 27B), I've made some documentation changes and a minor unrelated code
> tweak, which should address the concerns about the use of "catch" in
> one location, but not the others as well as the reason for the lack of
> "-profile replace".  (I didn't want to introduce another form of Tcl
> version guard in open_logs, which is why I investigated whether I
> could dispense with use of "-profile replace".)  In any case, I think
> it's now amply documented.
> 
> I posted a v2 here:
> 
> https://sourceware.org/pipermail/gdb-patches/2026-May/227637.html
> 

Hi Kevin,

I've taken a look, no further comments.

Thanks,
- Tom

> Kevin
>
  

Patch

diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 28709004570..52e4be9122d 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -166,6 +166,27 @@  proc load_lib { file } {
     return $result
 }
 
+# Tcl 9.0 changed the default channel encoding profile to "strict".  When
+# runtest sets LC_ALL=C the system encoding is iso8859-1, so file channels
+# opened by DejaGNU (gdb.sum, gdb.log) and spawn channels (for GDB and
+# subprocesses) default to iso8859-1 with strict profile.  Writing
+# non-Latin-1 characters in test names then raises EILSEQ, and sending them
+# to GDB truncates the command at the unrepresentable character.
+#
+# Fix this by:
+# 1. Overriding open_logs to reconfigure gdb.sum to utf-8 after DejaGNU
+#    opens it with the system (iso8859-1) encoding.
+# 2. Reconfiguring each new spawn channel to utf-8 in
+#    spawn_capture_tty_name, which wraps every spawn call.
+# 3. Reconfiguring gdb.in to utf-8 in gdb_stdin_log_init.
+
+rename open_logs saved_open_logs
+proc open_logs {} {
+    saved_open_logs
+    global sum_file
+    fconfigure $sum_file -encoding utf-8
+}
+
 load_lib libgloss.exp
 load_lib cache.exp
 load_lib gdb-utils.exp
@@ -2633,6 +2654,7 @@  proc gdb_file_cmd { arg {kill_flag 1} } {
 proc spawn_capture_tty_name { args } {
     set result [uplevel builtin_spawn $args]
     upvar spawn_out spawn_out
+    upvar spawn_id spawn_id
     if { [info exists spawn_out(slave,name)] } {
 	set ::last_spawn_tty_name $spawn_out(slave,name)
     } else {
@@ -2648,6 +2670,12 @@  proc spawn_capture_tty_name { args } {
 	# use -nocomplain here we would otherwise get an error.
 	unset -nocomplain ::last_spawn_tty_name
     }
+    # Tcl 9.0 defaults spawn channels to iso8859-1/strict, which raises
+    # EILSEQ when non-Latin-1 characters (e.g. function names with UTF-8
+    # letters) are written to or read from the channel.  Use utf-8 instead.
+    if {[tcl_version_at_least 9 0 0]} {
+	catch {fconfigure $spawn_id -encoding utf-8 -profile replace}
+    }
     return $result
 }
 
@@ -10419,6 +10447,11 @@  proc gdb_stdin_log_init { } {
     set logfile [standard_output_file_with_gdb_instance gdb.in]
     set in_file [open $logfile w]
 
+    if {[tcl_version_at_least 9 0 0]} {
+	# Tcl 9 strict profile: gdb.in must accept UTF-8 command strings.
+	fconfigure $in_file -encoding utf-8 -profile replace
+    }
+
     verbose -log ""
     verbose -log "Starting logfile: $logfile"
     verbose -log ""