aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbtypes.c
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2023-05-31 16:14:47 +0100
committerAndrew Burgess <aburgess@redhat.com>2023-07-07 15:20:28 +0100
commitbde240e7f83f208568254574082df12c871dcbc8 (patch)
tree4858ae4013c6cdaecdd9c5d358ad446bfcbb5887 /gdb/gdbtypes.c
parenteae2847fbff56657a5d14909b574ab8ea718ee08 (diff)
downloadgdb-bde240e7f83f208568254574082df12c871dcbc8.zip
gdb-bde240e7f83f208568254574082df12c871dcbc8.tar.gz
gdb-bde240e7f83f208568254574082df12c871dcbc8.tar.bz2
gdb: fix printf of wchar_t early in a gdb session
Given this test program: #include <wchar.h> const wchar_t wide_str[] = L"wide string"; int main (void) { return 0; } I observed this GDB behaviour: $ gdb -q /tmp/printf-wchar_t Reading symbols from /tmp/printf-wchar_t... (gdb) start Temporary breakpoint 1 at 0x40110a: file /tmp/printf-wchar_t.c, line 8. Starting program: /tmp/printf-wchar_t Temporary breakpoint 1, main () at /tmp/printf-wchar_t.c:8 25 return 0; (gdb) printf "%ls\n", wide_str (gdb) Notice that the printf results in a blank line rather than the expected 'wide string' output. I tracked the problem down to printf_wide_c_string (in printcmd.c), in this function we do this: struct type *wctype = lookup_typename (current_language, "wchar_t", NULL, 0); int wcwidth = wctype->length (); the problem here is that 'wchar_t' is a typedef. If we look at the comment on type::length() we see this: /* Note that if thistype is a TYPEDEF type, you have to call check_typedef. But check_typedef does set the TYPE_LENGTH of the TYPEDEF type, so you only have to call check_typedef once. Since value::allocate calls check_typedef, X->type ()->length () is safe. */ What this means is that after calling lookup_typename we should call check_typedef in order to ensure that the length of the typedef has been setup correctly. We are not doing this in printf_wide_c_string, and so wcwidth is incorrectly calculated as 0. This is what leads GDB to print an empty string. We can see in c_string_operation::evaluate (in c-lang.c) an example of calling check_typedef specifically to fix this exact issue. Initially I did fix this problem by adding a check_typedef call into printf_wide_c_string, but then I figured why not move the check_typedef call up into lookup_typename itself, that feels like it should be harmless when looking up a non-typedef type, but will avoid bugs like this when looking up a typedef. So that's what I did. I can then remove the extra check_typedef call from c-lang.c, I don't see any other places where we had extra check_typedef calls. This doesn't mean we definitely had bugs -- so long as we never checked the length, or, if we knew that check_typedef had already been called, then we would be fine. I don't see any test regressions after this change, and my new test case is now passing. Reviewed-By: Tom Tromey <tom@tromey.com>
Diffstat (limited to 'gdb/gdbtypes.c')
-rw-r--r--gdb/gdbtypes.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 9aa644b..c527297 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1648,9 +1648,7 @@ type_name_or_error (struct type *type)
objfile ? objfile_name (objfile) : "<arch>");
}
-/* Lookup a typedef or primitive type named NAME, visible in lexical
- block BLOCK. If NOERR is nonzero, return zero if NAME is not
- suitably defined. */
+/* See gdbtypes.h. */
struct type *
lookup_typename (const struct language_defn *language,
@@ -1662,7 +1660,12 @@ lookup_typename (const struct language_defn *language,
sym = lookup_symbol_in_language (name, block, VAR_DOMAIN,
language->la_language, NULL).symbol;
if (sym != NULL && sym->aclass () == LOC_TYPEDEF)
- return sym->type ();
+ {
+ struct type *type = sym->type ();
+ /* Ensure the length of TYPE is valid. */
+ check_typedef (type);
+ return type;
+ }
if (noerr)
return NULL;