[PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
The fix for bug 59195: [C++ demangler handles conversion operator incorrectly] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195 unfortunately makes the demangler crash due to infinite recursion, in case of casts in template parameters. For example, with: template struct A {}; template void function_temp(A) {} template void function_temp(A); The 'function_temp' instantiation above mangles to: _Z13function_tempIiEv1AIXszcvT_Li999EEE The demangler parses this as: typed name template name 'function_temp' template argument list builtin type int function type builtin type void argument list template (*) name 'A' template argument list unary operator operator sizeof unary operator cast template parameter 0(**) literal builtin type int name '999' And after the fix for 59195, due to: static void d_print_cast (struct d_print_info *dpi, int options, const struct demangle_component *dc) { ... /* For a cast operator, we need the template parameters from the enclosing template in scope for processing the type. */ if (dpi->current_template != NULL) { dpt.next = dpi->templates; dpi->templates = &dpt; dpt.template_decl = dpi->current_template; } when printing the template argument list of A (what should be ""), the template parameter 0 (that is, "T_", the '**' above) now refers to the first parameter of the the template argument list of the 'A' template (the '*' above), exactly what we were already trying to print. This leads to infinite recursion, and stack exaustion. The template parameter 0 should actually refer to the first parameter of the 'function_temp' template. Where it reads "for the cast operator" in the comment in d_print_cast (above), it's really talking about a conversion operator, like: struct A { template explicit operator U(); }; We don't want to inject the template parameters from the enclosing template in scope when processing a cast _expression_, only when handling a conversion operator. The problem is that DEMANGLE_COMPONENT_CAST is currently ambiguous, and means _both_ 'conversion operator' and 'cast expression'. Fix this by adding a new DEMANGLE_COMPONENT_CONVERSION component type, which does what DEMANGLE_COMPONENT_CAST does today, and making DEMANGLE_COMPONENT_CAST just simply print its component subtree. I think we could instead reuse DEMANGLE_COMPONENT_CAST and in d_print_comp_inner still do: @@ -5001,9 +5013,9 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_print_comp (dpi, options, dc->u.s_extended_operator.name); return; case DEMANGLE_COMPONENT_CAST: d_append_string (dpi, "operator "); - d_print_cast (dpi, options, dc); + d_print_conversion (dpi, options, dc); return; leaving the unary cast case below calling d_print_cast, but seems to me that spliting the component types makes it easier to reason about the code. g++'s testsuite actually generates three symbols that crash the demangler in the same way. I've added those as tests in the demangler testsuite as well. And then this fixes PR other/61233 too, which happens to be a demangler crash originally reported to GDB, at: https://sourceware.org/bugzilla/show_bug.cgi?id=16957 Bootstrapped and regtested on x86_64 Fedora 20. Also ran this through GDB's testsuite. GDB will require a small update to use DEMANGLE_COMPONENT_CONVERSION in one place it's using DEMANGLE_COMPONENT_CAST in its sources. libiberty/ 2014-05-27 Pedro Alves PR other/61321 PR other/61233 * demangle.h (enum demangle_component_type) : New value. * cp-demangle.c (d_demangle_callback, d_make_comp): Handle DEMANGLE_COMPONENT_CONVERSION. (is_ctor_dtor_or_conversion): Handle DEMANGLE_COMPONENT_CONVERSION instead of DEMANGLE_COMPONENT_CAST. (d_operator_name): Return a DEMANGLE_COMPONENT_CONVERSION component if handling a conversion. (d_count_templates_scopes, d_print_comp_inner): Handle DEMANGLE_COMPONENT_CONVERSION. (d_print_comp_inner): Handle DEMANGLE_COMPONENT_CONVERSION instead of DEMANGLE_COMPONENT_CAST. (d_print_cast): Rename as ... (d_print_conversion): ... this. Adjust comments. (d_print_cast): Rewrite - simply print the left subcomponent. * cp-demint.c (cplus_demangle_fill_component): Handle DEMANGLE_COMPONENT_CONVERSION. * testsuite/demangle-expected: Add tests. --- include/demangle.h| 4 libiberty/cp-demangle.c | 37 +++ libiberty/cp-demint.c | 1 + libiberty/testsuite/demangle-expected | 23 ++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
Ping. Jason, do you still think the special-case for conversion ops is inappropriate? -cary On Fri, Jul 25, 2014 at 2:16 AM, Pedro Alves wrote: > On 07/24/2014 11:35 PM, Cary Coutant wrote: >>> It seems that the problem here is more general; a template argument list is >>> not in scope within that same template argument list. Can't we fix that >>> without special-casing conversion ops? >> >> I think conversion ops really are a special case. > > Thanks Cary. FWIW, I agree. > > (GDB 7.8 hasn't been released yet, though it's close. If this > patch is approved as is, we'll be able to have the crash > fixed there. If this requires a significant rewrite though, > I'm afraid I might not be able to do it myself anytime soon.) > >> It's the only case >> where the template parameters refer to the template argument list from >> the cast operator's enclosing template. In a cast expression, like >> anywhere else you might have a template parameter, the template >> parameter refers to the template argument list of the immediately >> enclosing template. >> >> I think this note from Section 5.1.3 (Operator Encodings) of the ABI >> is what makes this a special case (it's an informative comment in the >> document, but seems to me to be normative): >> >> "For a user-defined conversion operator the result type (i.e., the >> type to which the operator converts) is part of the mangled name of >> the function. If the conversion operator is a member template, the >> result type will appear before the template parameters. There may be >> forward references in the result type to the template parameters." >> > > -- > Thanks, > Pedro Alves >
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
> It seems that the problem here is more general; a template argument list is > not in scope within that same template argument list. Can't we fix that > without special-casing conversion ops? I think conversion ops really are a special case. It's the only case where the template parameters refer to the template argument list from the cast operator's enclosing template. In a cast expression, like anywhere else you might have a template parameter, the template parameter refers to the template argument list of the immediately enclosing template. I think this note from Section 5.1.3 (Operator Encodings) of the ABI is what makes this a special case (it's an informative comment in the document, but seems to me to be normative): "For a user-defined conversion operator the result type (i.e., the type to which the operator converts) is part of the mangled name of the function. If the conversion operator is a member template, the result type will appear before the template parameters. There may be forward references in the result type to the template parameters." -cary
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
On 07/24/2014 11:35 PM, Cary Coutant wrote: >> It seems that the problem here is more general; a template argument list is >> not in scope within that same template argument list. Can't we fix that >> without special-casing conversion ops? > > I think conversion ops really are a special case. Thanks Cary. FWIW, I agree. (GDB 7.8 hasn't been released yet, though it's close. If this patch is approved as is, we'll be able to have the crash fixed there. If this requires a significant rewrite though, I'm afraid I might not be able to do it myself anytime soon.) > It's the only case > where the template parameters refer to the template argument list from > the cast operator's enclosing template. In a cast expression, like > anywhere else you might have a template parameter, the template > parameter refers to the template argument list of the immediately > enclosing template. > > I think this note from Section 5.1.3 (Operator Encodings) of the ABI > is what makes this a special case (it's an informative comment in the > document, but seems to me to be normative): > > "For a user-defined conversion operator the result type (i.e., the > type to which the operator converts) is part of the mangled name of > the function. If the conversion operator is a member template, the > result type will appear before the template parameters. There may be > forward references in the result type to the template parameters." > -- Thanks, Pedro Alves
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
> Fix this by adding a new DEMANGLE_COMPONENT_CONVERSION component type, > which does what DEMANGLE_COMPONENT_CAST does today, and making > DEMANGLE_COMPONENT_CAST just simply print its component subtree. > > I think we could instead reuse DEMANGLE_COMPONENT_CAST and in > d_print_comp_inner still do: > > @@ -5001,9 +5013,9 @@ d_print_comp_inner (struct d_print_info *dpi, int > options, > d_print_comp (dpi, options, dc->u.s_extended_operator.name); > return; > > case DEMANGLE_COMPONENT_CAST: >d_append_string (dpi, "operator "); > - d_print_cast (dpi, options, dc); > + d_print_conversion (dpi, options, dc); >return; > > leaving the unary cast case below calling d_print_cast, but seems to > me that spliting the component types makes it easier to reason about > the code. I agree. > libiberty/ > 2014-05-27 Pedro Alves > > PR other/61321 > PR other/61233 > * demangle.h (enum demangle_component_type) > : New value. > * cp-demangle.c (d_demangle_callback, d_make_comp): Handle > DEMANGLE_COMPONENT_CONVERSION. > (is_ctor_dtor_or_conversion): Handle DEMANGLE_COMPONENT_CONVERSION > instead of DEMANGLE_COMPONENT_CAST. > (d_operator_name): Return a DEMANGLE_COMPONENT_CONVERSION > component if handling a conversion. > (d_count_templates_scopes, d_print_comp_inner): Handle > DEMANGLE_COMPONENT_CONVERSION. > (d_print_comp_inner): Handle DEMANGLE_COMPONENT_CONVERSION instead > of DEMANGLE_COMPONENT_CAST. > (d_print_cast): Rename as ... > (d_print_conversion): ... this. Adjust comments. > (d_print_cast): Rewrite - simply print the left subcomponent. > * cp-demint.c (cplus_demangle_fill_component): Handle > DEMANGLE_COMPONENT_CONVERSION. > > * testsuite/demangle-expected: Add tests. Looks good to me. Thanks! Ian, does this look good to you? -cary
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
On Fri, May 30, 2014 at 10:37 AM, Cary Coutant wrote: >> Fix this by adding a new DEMANGLE_COMPONENT_CONVERSION component type, >> which does what DEMANGLE_COMPONENT_CAST does today, and making >> DEMANGLE_COMPONENT_CAST just simply print its component subtree. >> >> I think we could instead reuse DEMANGLE_COMPONENT_CAST and in >> d_print_comp_inner still do: >> >> @@ -5001,9 +5013,9 @@ d_print_comp_inner (struct d_print_info *dpi, int >> options, >> d_print_comp (dpi, options, dc->u.s_extended_operator.name); >> return; >> >> case DEMANGLE_COMPONENT_CAST: >>d_append_string (dpi, "operator "); >> - d_print_cast (dpi, options, dc); >> + d_print_conversion (dpi, options, dc); >>return; >> >> leaving the unary cast case below calling d_print_cast, but seems to >> me that spliting the component types makes it easier to reason about >> the code. > > I agree. > >> libiberty/ >> 2014-05-27 Pedro Alves >> >> PR other/61321 >> PR other/61233 >> * demangle.h (enum demangle_component_type) >> : New value. >> * cp-demangle.c (d_demangle_callback, d_make_comp): Handle >> DEMANGLE_COMPONENT_CONVERSION. >> (is_ctor_dtor_or_conversion): Handle DEMANGLE_COMPONENT_CONVERSION >> instead of DEMANGLE_COMPONENT_CAST. >> (d_operator_name): Return a DEMANGLE_COMPONENT_CONVERSION >> component if handling a conversion. >> (d_count_templates_scopes, d_print_comp_inner): Handle >> DEMANGLE_COMPONENT_CONVERSION. >> (d_print_comp_inner): Handle DEMANGLE_COMPONENT_CONVERSION instead >> of DEMANGLE_COMPONENT_CAST. >> (d_print_cast): Rename as ... >> (d_print_conversion): ... this. Adjust comments. >> (d_print_cast): Rewrite - simply print the left subcomponent. >> * cp-demint.c (cplus_demangle_fill_component): Handle >> DEMANGLE_COMPONENT_CONVERSION. >> >> * testsuite/demangle-expected: Add tests. > > Looks good to me. Thanks! > > Ian, does this look good to you? I tend to defer to Jason on this sort of newfangled mangling nuttiness, but I can take a look if he doesn't have time. Ian
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
On 05/30/2014 07:05 PM, Ian Lance Taylor wrote: >> > Looks good to me. Thanks! Thanks Cary! >> > Ian, does this look good to you? > I tend to defer to Jason on this sort of newfangled mangling > nuttiness, but I can take a look if he doesn't have time. Thanks! FWIW, it'd be great to have this approved/rejected, as I'd like to get this fixed in gdb 7.8, and we're just about to branch. Thanks, -- Pedro Alves
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
On 05/27/2014 07:57 AM, Pedro Alves wrote: And after the fix for 59195, due to: static void d_print_cast (struct d_print_info *dpi, int options, const struct demangle_component *dc) { ... /* For a cast operator, we need the template parameters from the enclosing template in scope for processing the type. */ if (dpi->current_template != NULL) { dpt.next = dpi->templates; dpi->templates = &dpt; dpt.template_decl = dpi->current_template; } when printing the template argument list of A (what should be ""), the template parameter 0 (that is, "T_", the '**' above) now refers to the first parameter of the the template argument list of the 'A' template (the '*' above), exactly what we were already trying to print. This leads to infinite recursion, and stack exaustion. The template parameter 0 should actually refer to the first parameter of the 'function_temp' template. It seems that the problem here is more general; a template argument list is not in scope within that same template argument list. Can't we fix that without special-casing conversion ops? Jason
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
Ping. I'm getting more reports of this bug internally, and it would be nice to have the fix upstream. -cary On Mon, Oct 13, 2014 at 11:43 AM, Cary Coutant wrote: > Ping. Jason, do you still think the special-case for conversion ops is > inappropriate? > > -cary > > > On Fri, Jul 25, 2014 at 2:16 AM, Pedro Alves wrote: >> On 07/24/2014 11:35 PM, Cary Coutant wrote: It seems that the problem here is more general; a template argument list is not in scope within that same template argument list. Can't we fix that without special-casing conversion ops? >>> >>> I think conversion ops really are a special case. >> >> Thanks Cary. FWIW, I agree. >> >> (GDB 7.8 hasn't been released yet, though it's close. If this >> patch is approved as is, we'll be able to have the crash >> fixed there. If this requires a significant rewrite though, >> I'm afraid I might not be able to do it myself anytime soon.) >> >>> It's the only case >>> where the template parameters refer to the template argument list from >>> the cast operator's enclosing template. In a cast expression, like >>> anywhere else you might have a template parameter, the template >>> parameter refers to the template argument list of the immediately >>> enclosing template. >>> >>> I think this note from Section 5.1.3 (Operator Encodings) of the ABI >>> is what makes this a special case (it's an informative comment in the >>> document, but seems to me to be normative): >>> >>> "For a user-defined conversion operator the result type (i.e., the >>> type to which the operator converts) is part of the mangled name of >>> the function. If the conversion operator is a member template, the >>> result type will appear before the template parameters. There may be >>> forward references in the result type to the template parameters." >>> >> >> -- >> Thanks, >> Pedro Alves >>
Re: [PATCH 2/3] PR other/61321 - demangler crash on casts in template parameters
Sorry I forgot about this for so long. The patch is OK. Jason