libiberty: Initialize d_printing in all cplus_demangle_* functions.
Commit Message
On 03/13/2017 08:35 PM, Mark Wielaard wrote:
> Switching mailinglist from gcc to gdb.
>
> On Mon, 2017-03-13 at 18:54 +0000, Pedro Alves wrote:
>> On 03/13/2017 06:29 PM, Mark Wielaard wrote:
>>
>> Should gdb be memsetting instead to avoid having to know about
>> libiberty's "internals"?
>
> Maybe. But I went with the version I tested.
Thanks, this restores master to a working state quickly.
> Basically none of this would be needed if gdb only used the
> cplus_demangle_fill_* functions to initialize the data structures
> (although that is where there was a bug, but that is now fixed).
>
> cp-name-parser.y however sometimes uses the cplus_demangle_fill
> functions, but other times fills in the data structures by hand (using
> its own partial fill function make_empty). I know too little of this
> code to know why. Maybe the set of cplus_demangle_fill functions isn't
> complete enough or maybe the way the parser works not all information
> needed is there yet to call cplus_demangle_fill or maybe doing it by
> hand just felt more efficient?
I don't know either. I have never had to look much deeply into this file.
Git blame points at the commit that added the parser in the first
place (git fb4c6eba):
https://sourceware.org/ml/gdb-patches/2005-03/msg00182.html
But that doesn't include any comment about this either.
Seems like all uses of GDB's make_empty are followed by referring to
the "s_binary" union member via these two macros:
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
"s_binary" is documented as being "for other types":
struct demangle_component
{
...
/* For other types. */
struct
{
/* Left (or only) subtree. */
struct demangle_component *left;
/* Right subtree. */
struct demangle_component *right;
} s_binary;
And there's a cplus_demangle_fill_component function to fill
these in. It's already used by cp-name-parser.y in other
cases, via the fill_comp wrapper function.
Using that seems to work, testing the patch below on x86_64 Fedora 23
shows no regressions.
From e55453c67bbe772ce001ea15b152f8dc44b8945e Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 13 Mar 2017 22:54:09 +0000
Subject: [PATCH] gdb/cp-name-parser.y: Eliminate make_empty, use
cplus_demangle_fill_component
The demangler exports the cplus_demangle_fill_component function that
clients should use to initialize demangle_component components that
use the "s_binary" union member. cp-name-parser.y uses it in some
places, via the fill_comp wrapper, but not all. Several places
instead use a GDB-specific "make_empty" function. Because this
function does not call any of the demangler "fill" functions, we had
to patch it recently to clear the allocated demangle_component's
"d_printing" field, which is supposedly a "private" demangler field.
To avoid such problems in the future, this commit switches those
places to use "fill_comp" instead, and eliminates the "make_empty"
function.
gdb/ChangeLog:
2017-03-13 Pedro Alves <palves@redhat.com>
* cp-name-parser.y (make_empty): Delete.
(demangler_special, nested_name, ptr_operator, array_indicator)
(direct_declarator, declarator_1): Use fill_comp instead of
make_empty.
---
gdb/cp-name-parser.y | 57 ++++++++++++----------------------------------------
1 file changed, 13 insertions(+), 44 deletions(-)
Comments
On Tue, 2017-03-14 at 01:26 +0000, Pedro Alves wrote:
> And there's a cplus_demangle_fill_component function to fill
> these in. It's already used by cp-name-parser.y in other
> cases, via the fill_comp wrapper function.
>
> Using that seems to work, testing the patch below on x86_64 Fedora 23
> shows no regressions.
>
> From e55453c67bbe772ce001ea15b152f8dc44b8945e Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Mon, 13 Mar 2017 22:54:09 +0000
> Subject: [PATCH] gdb/cp-name-parser.y: Eliminate make_empty, use
> cplus_demangle_fill_component
>
> The demangler exports the cplus_demangle_fill_component function that
> clients should use to initialize demangle_component components that
> use the "s_binary" union member. cp-name-parser.y uses it in some
> places, via the fill_comp wrapper, but not all. Several places
> instead use a GDB-specific "make_empty" function. Because this
> function does not call any of the demangler "fill" functions, we had
> to patch it recently to clear the allocated demangle_component's
> "d_printing" field, which is supposedly a "private" demangler field.
> To avoid such problems in the future, this commit switches those
> places to use "fill_comp" instead, and eliminates the "make_empty"
> function.
That looks good. But note that there is one behavioral change.
cplus_demangle_fill_component is defined as:
/* Fill in most component types with a left subtree and a right
subtree. Returns non-zero on success, zero on failure, such as an
unrecognized or inappropriate component type. */
And gdb/cp-name-parser.y fill_comp does:
i = cplus_demangle_fill_component (ret, d_type, lhs, rhs);
gdb_assert (i);
So you have an extra sanity check. Where before you might have silently
created a bogus demangle_component. Which I assume is what you want. But
it might depend on what gdb_assert precisely does and if the parser
input is normally "sane" or not.
Cheers,
Mark
On 03/14/2017 09:04 AM, Mark Wielaard wrote:
> That looks good. But note that there is one behavioral change.
> cplus_demangle_fill_component is defined as:
>
> /* Fill in most component types with a left subtree and a right
> subtree. Returns non-zero on success, zero on failure, such as an
> unrecognized or inappropriate component type. */
>
> And gdb/cp-name-parser.y fill_comp does:
>
> i = cplus_demangle_fill_component (ret, d_type, lhs, rhs);
> gdb_assert (i);
>
> So you have an extra sanity check. Where before you might have silently
> created a bogus demangle_component. Which I assume is what you want.
Indeed, and I think it is.
> But it might depend on what gdb_assert precisely does
gdb_assert triggers the infamous:
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
> and if the parser input is normally "sane" or not.
The only thing that is validated is that we don't create
a component with a left/right subtree when that doesn't make sense
for the component type. I think trying to create such a component
would be a parser/grammar/production bug, even with invalid input.
I had run into that assert in fill_comp yesterday actually, with a slightly
different/larger patch. At first I saw the cplus_demangle_fill_component
declaration in demangle.h, but didn't see the implementation in cp-demangle.c, and
thought that was just some oversight/left over. So I though I'd add one. I factored
out a cplus_demangle_fill_component out of cp-demangle.c:d_make_comp, following the
same pattern used by the other cplus_demangle_fill* / d_make* function pairs.
Only after did I notice that actually, there's an implementation of
cplus_demangle_fill_component in cplus-demint.c... AFAICS, that's only
used by GDB. No other tool in the binutils-gdb repo, nor GCC's repo uses it, AFAICS.
So I figured that I'd remove the cplus-demint.c implementation, in favor of
the new implementation in cp-demangle.c based on d_make_comp. And _that_ ran into the
assertion, because the implementations are exactly the same. GDB fills in some types with
NULL left components and fills them in later. For example, for DEMANGLE_COMPONENT_POINTER:
ptr_operator : '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_POINTER);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_POINTER, NULL, NULL);
$$.last = &d_left ($$.comp);
$$.comp = d_qualify ($$.comp, $2, 0); }
Note how cp-demangle.c:d_make_comp's validations are stricter than
cp-demint.c:cplus_demangle_fill_component's. The former only allows
lazy-filling for a few cases:
[...]
/* These are allowed to have no parameters--in some cases they
will be filled in later. */
case DEMANGLE_COMPONENT_FUNCTION_TYPE:
[...]
While cp-demint.c:cplus_demangle_fill_component, the version that
GDB uses, allows that in all cases. IOW, passing in a NULL left/right subtree
to cplus_demangle_fill_component when the component type expects one is OK, assuming
that the caller will fill them in afterwards. I crossed checked the types in
the new fill_comp calls with the checks inside cplus_demangle_fill_component now,
and I believe they're all OK.
Maybe it'd be possible to avoid this lazy filling in, but I didn't
bother trying.
Thanks,
Pedro Alves
@@ -197,15 +197,6 @@ fill_comp (enum demangle_component_type d_type, struct demangle_component *lhs,
}
static struct demangle_component *
-make_empty (enum demangle_component_type d_type)
-{
- struct demangle_component *ret = d_grab ();
- ret->type = d_type;
- ret->d_printing = 0;
- return ret;
-}
-
-static struct demangle_component *
make_operator (const char *name, int args)
{
struct demangle_component *ret = d_grab ();
@@ -433,9 +424,7 @@ function
demangler_special
: DEMANGLER_SPECIAL start
- { $$ = make_empty ((enum demangle_component_type) $1);
- d_left ($$) = $2;
- d_right ($$) = NULL; }
+ { $$ = fill_comp ((enum demangle_component_type) $1, $2, NULL); }
| CONSTRUCTION_VTABLE start CONSTRUCTION_IN start
{ $$ = fill_comp (DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, $2, $4); }
;
@@ -600,30 +589,22 @@ ext_only_name : nested_name unqualified_name
;
nested_name : NAME COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $1, NULL);
$$.last = $$.comp;
}
| nested_name NAME COLONCOLON
{ $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_right ($1.last) = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $2, NULL);
$$.last = d_right ($1.last);
- d_left ($$.last) = $2;
- d_right ($$.last) = NULL;
}
| templ COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $1, NULL);
$$.last = $$.comp;
}
| nested_name templ COLONCOLON
{ $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_right ($1.last) = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $2, NULL);
$$.last = d_right ($1.last);
- d_left ($$.last) = $2;
- d_right ($$.last) = NULL;
}
;
@@ -761,41 +742,31 @@ builtin_type : int_seq
;
ptr_operator : '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_POINTER);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_POINTER, NULL, NULL);
$$.last = &d_left ($$.comp);
$$.comp = d_qualify ($$.comp, $2, 0); }
/* g++ seems to allow qualifiers after the reference? */
| '&'
- { $$.comp = make_empty (DEMANGLE_COMPONENT_REFERENCE);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_REFERENCE, NULL, NULL);
$$.last = &d_left ($$.comp); }
| nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $1.comp;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_PTRMEM_TYPE, $1.comp, NULL);
/* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
*$1.last = *d_left ($1.last);
- $$.comp->u.s_binary.right = NULL;
$$.last = &d_right ($$.comp);
$$.comp = d_qualify ($$.comp, $3, 0); }
| COLONCOLON nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $2.comp;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_PTRMEM_TYPE, $2.comp, NULL);
/* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
*$2.last = *d_left ($2.last);
- $$.comp->u.s_binary.right = NULL;
$$.last = &d_right ($$.comp);
$$.comp = d_qualify ($$.comp, $4, 0); }
;
array_indicator : '[' ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = NULL;
- }
+ { $$ = fill_comp (DEMANGLE_COMPONENT_ARRAY_TYPE, NULL, NULL); }
| '[' INT ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = $2;
- }
+ { $$ = fill_comp (DEMANGLE_COMPONENT_ARRAY_TYPE, $2, NULL); }
;
/* Details of this approach inspired by the G++ < 3.4 parser. */
@@ -948,8 +919,7 @@ direct_declarator
$$.last = &d_right ($2);
}
| colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, NULL);
$$.last = &d_right ($$.comp);
}
;
@@ -965,8 +935,7 @@ declarator_1 : ptr_operator declarator_1
$$.last = $1.last;
*$2.last = $1.comp; }
| colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, NULL);
$$.last = &d_right ($$.comp);
}
| direct_declarator_1