diff options
author | Andrew Burgess <aburgess@redhat.com> | 2023-05-31 16:14:47 +0100 |
---|---|---|
committer | Andrew Burgess <aburgess@redhat.com> | 2023-07-07 15:20:28 +0100 |
commit | bde240e7f83f208568254574082df12c871dcbc8 (patch) | |
tree | 4858ae4013c6cdaecdd9c5d358ad446bfcbb5887 /gdb/gdbtypes.h | |
parent | eae2847fbff56657a5d14909b574ab8ea718ee08 (diff) | |
download | gdb-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.h')
-rw-r--r-- | gdb/gdbtypes.h | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 8071d6b..aedaf53 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -2586,8 +2586,18 @@ extern void check_stub_method_group (struct type *, int); extern char *gdb_mangle_name (struct type *, int, int); -extern struct type *lookup_typename (const struct language_defn *, - const char *, const struct block *, int); +/* 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. + + If this function finds a suitable type then check_typedef is called on + the type, this ensures that if the type being returned is a typedef + then the length of the type will be correct. The original typedef will + still be returned, not the result of calling check_typedef. */ + +extern struct type *lookup_typename (const struct language_defn *language, + const char *name, + const struct block *block, int noerr); extern struct type *lookup_template_type (const char *, struct type *, const struct block *); |