From: Aditya Vidyadhar Kamath <akamath996@gmail.com>
To: ulrich.weigand@de.ibm.com, simon.marchi@polymtl.ca, tom@tromey.com
Cc: gdb-patches@sourceware.org, Aditya.Kamath1@ibm.com,
sangamesh.swamy@in.ibm.com,
Aditya Vidyadhar Kamath <aditya.kamath1@ibm.com>
Subject: [PATCH] Fix crash when target-wide-charset doesn't match wchar_t size
Date: Fri, 16 Oct 2026 17:35:03 +0530 [thread overview]
Message-ID: <20261016120502.88374-2-akamath996@gmail.com> (raw)
From: Aditya Vidyadhar Kamath <aditya.kamath1@ibm.com>
Tom asked a question [1] which is valid: can setting
target-wide-charset to an encoding with the wrong unit size crash GDB?
First I compiled gdb/testsuite/gdb.base/wchar.c
gcc -g -maix64 -o /tmp/wchar64 gdb/testsuite/gdb.base/wchar.c
Then debug with GDB and we get the crash
(gdb) b wchar.c:44
(gdb) run
(gdb) set target-wide-charset UTF-16
(gdb) print single
Fatal signal: Segmentation fault
----- Backtrace -----
This patch checks the width implied by the charset name against
wchar_bit in validate(), and gives an error if they differ. Since the
set command stores the new value before calling the sfunc, restore the
old value when the check fails.
With the patch, the same session now
gives:
(gdb) set target-wide-charset UTF-16
Character set `UTF-16' has a 2-byte character width but `wchar_t' on this target is 4 bytes wide.
Use `set target-wide-charset auto' to let GDB choose the correct encoding automatically.
(gdb) print single
$1 = 48879 L'\xbeef'
Add tests to wchar.exp for this.
[1]: https://sourceware.org/pipermail/gdb-patches/2026-October/231110.html
---
gdb/charset.c | 49 +++++++++++++++++++++++++++++++-
gdb/testsuite/gdb.base/wchar.exp | 31 ++++++++++++++++++++
2 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/gdb/charset.c b/gdb/charset.c
index 1b0725b5078..9656e31290b 100644
--- a/gdb/charset.c
+++ b/gdb/charset.c
@@ -256,6 +256,10 @@ show_target_charset_name (struct ui_file *file, int from_tty,
}
static const char *target_wide_charset_name = "auto";
+
+/* Last known-good value of target_wide_charset_name, used to roll back
+ if a new setting fails validation. */
+static const char *target_wide_charset_name_validated = "auto";
static void
show_target_wide_charset_name (struct ui_file *file,
int from_tty,
@@ -336,6 +340,21 @@ set_be_le_names (struct gdbarch *gdbarch)
/* 'Set charset', 'set host-charset', 'set target-charset', 'set
target-wide-charset', 'set charset' sfunc's. */
+/* Return the character width in bytes implied by a wide charset name:
+ 2 for UTF-16/UCS-2, 4 for UTF-32/UCS-4, 0 if unknown. */
+
+static int
+wide_charset_width (const char *name)
+{
+ if (strncasecmp (name, "UTF-16", 6) == 0
+ || strncasecmp (name, "UCS-2", 5) == 0)
+ return 2;
+ if (strncasecmp (name, "UTF-32", 6) == 0
+ || strncasecmp (name, "UCS-4", 5) == 0)
+ return 4;
+ return 0;
+}
+
static void
validate (struct gdbarch *gdbarch)
{
@@ -346,6 +365,23 @@ validate (struct gdbarch *gdbarch)
if (streq (target_wide_cset, "auto"))
target_wide_cset = gdbarch_auto_wide_charset (gdbarch);
+ else
+ {
+ /* Reject charsets whose unit size doesn't match wchar_t.
+ A mismatch (e.g. UTF-16 with a 4-byte wchar_t) makes iconv
+ consume the wrong number of bytes and can crash GDB. */
+ int charset_width = wide_charset_width (target_wide_cset);
+ if (charset_width != 0)
+ {
+ int wchar_bytes = gdbarch_wchar_bit (gdbarch) / 8;
+ if (charset_width != wchar_bytes)
+ error (_ ("Character set `%s' has a %d-byte character width "
+ "but `wchar_t' on this target is %d bytes wide.\n"
+ "Use `set target-wide-charset auto' to let GDB "
+ "choose the correct encoding automatically."),
+ target_wide_cset, charset_width, wchar_bytes);
+ }
+ }
desc = iconv_open (target_wide_cset, host_cset);
if (desc == (iconv_t) -1)
@@ -395,7 +431,18 @@ static void
set_target_wide_charset_sfunc (const char *charset, int from_tty,
struct cmd_list_element *c)
{
- validate (get_current_arch ());
+ /* The setshow framework writes the new value before calling us, so
+ restore the previous setting if validation fails. */
+ try
+ {
+ validate (get_current_arch ());
+ target_wide_charset_name_validated = target_wide_charset_name;
+ }
+ catch (const gdb_exception_error &)
+ {
+ target_wide_charset_name = target_wide_charset_name_validated;
+ throw;
+ }
}
/* sfunc for the 'show charset' command. */
diff --git a/gdb/testsuite/gdb.base/wchar.exp b/gdb/testsuite/gdb.base/wchar.exp
index b02f4a78336..baa5c60a31d 100644
--- a/gdb/testsuite/gdb.base/wchar.exp
+++ b/gdb/testsuite/gdb.base/wchar.exp
@@ -75,3 +75,34 @@ gdb_test "printf \"%ls\\n\", 0" "\\(null\\)"
# From PR exp/33124 - a bug when converting escapes.
set wbs {L'\\'}
gdb_test "print $wbs" " = $decimal [string_to_regexp $wbs]"
+
+# A wide charset whose unit size doesn't match wchar_t must be rejected,
+# otherwise printing wide chars can crash GDB.
+# Use the encoding GDB picks for "auto" as the good one.
+set good_cs ""
+gdb_test_multiple "show target-wide-charset" "" {
+ -re "currently (UTF-\[0-9\]+).*$gdb_prompt $" {
+ set good_cs $expect_out(1,string)
+ }
+}
+if { $good_cs == "UTF-16" } {
+ set bad_cs UTF-32
+} elseif { $good_cs == "UTF-32" } {
+ set bad_cs UTF-16
+} else {
+ return
+}
+
+gdb_test "set target-wide-charset $bad_cs" \
+ "Character set `$bad_cs' has a .-byte character width.*" \
+ "reject target-wide-charset $bad_cs"
+
+# The rejected setting must not stick.
+gdb_test "print single" "= 48879 L'\\\\xbeef'" \
+ "print wchar_t after rejected target-wide-charset"
+
+gdb_test_no_output "set target-wide-charset $good_cs" \
+ "accept target-wide-charset $good_cs"
+
+gdb_test "print single" "= 48879 L'\\\\xbeef'" \
+ "print wchar_t with explicit target-wide-charset"
--
2.51.2
next reply other threads:[~2026-10-16 12:05 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 12:05 Aditya Vidyadhar Kamath [this message]
2026-10-16 12:47 ` Simon Marchi
2026-10-16 13:40 ` Aditya Kamath
2026-10-19 15:37 ` Tom Tromey
2026-10-21 9:01 ` Aditya Kamath
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261016120502.88374-2-akamath996@gmail.com \
--to=akamath996@gmail.com \
--cc=Aditya.Kamath1@ibm.com \
--cc=gdb-patches@sourceware.org \
--cc=sangamesh.swamy@in.ibm.com \
--cc=simon.marchi@polymtl.ca \
--cc=tom@tromey.com \
--cc=ulrich.weigand@de.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox