mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:54:41 +08:00
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>
This commit is contained in:
parent
eae2847fbf
commit
bde240e7f8
@ -615,9 +615,6 @@ c_string_operation::evaluate (struct type *expect_type,
|
||||
internal_error (_("unhandled c_string_type"));
|
||||
}
|
||||
|
||||
/* Ensure TYPE_LENGTH is valid for TYPE. */
|
||||
check_typedef (type);
|
||||
|
||||
/* If the caller expects an array of some integral type,
|
||||
satisfy them. If something odder is expected, rely on the
|
||||
caller to cast. */
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
26
gdb/testsuite/gdb.base/printf-wchar_t.c
Normal file
26
gdb/testsuite/gdb.base/printf-wchar_t.c
Normal file
@ -0,0 +1,26 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
const wchar_t wide_str[] = L"wide string";
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
26
gdb/testsuite/gdb.base/printf-wchar_t.exp
Normal file
26
gdb/testsuite/gdb.base/printf-wchar_t.exp
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright 2023 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
standard_testfile
|
||||
|
||||
if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
if {![runto_main]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test {printf "%ls\n", wide_str} "^wide string"
|
Loading…
Reference in New Issue
Block a user