binutils-gdb/libiberty/cp-demint.c

238 lines
7.0 KiB
C
Raw Normal View History

2004-01-13 05:24:38 +08:00
/* Demangler component interface functions.
Copyright (C) 2004-2019 Free Software Foundation, Inc.
2004-01-13 05:24:38 +08:00
Written by Ian Lance Taylor <ian@wasabisystems.com>.
This file is part of the libiberty library, which is part of GCC.
This file 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 2 of the License, or
(at your option) any later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combined
executable.)
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, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
2004-01-13 05:24:38 +08:00
*/
/* This file implements a few interface functions which are provided
for use with struct demangle_component trees. These functions are
declared in demangle.h. These functions are closely tied to the
demangler code in cp-demangle.c, and other interface functions can
be found in that file. We put these functions in a separate file
because they are not needed by the demangler, and so we avoid
having them pulled in by programs which only need the
demangler. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "ansidecl.h"
#include "libiberty.h"
#include "demangle.h"
#include "cp-demangle.h"
/* Fill in most component types. */
int
2005-03-27 13:28:42 +08:00
cplus_demangle_fill_component (struct demangle_component *p,
enum demangle_component_type type,
struct demangle_component *left,
struct demangle_component *right)
2004-01-13 05:24:38 +08:00
{
if (p == NULL)
return 0;
switch (type)
{
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
case DEMANGLE_COMPONENT_TYPED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE:
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
2004-01-13 05:24:38 +08:00
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_FUNCTION_TYPE:
case DEMANGLE_COMPONENT_ARRAY_TYPE:
case DEMANGLE_COMPONENT_PTRMEM_TYPE:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
case DEMANGLE_COMPONENT_UNARY:
case DEMANGLE_COMPONENT_BINARY:
case DEMANGLE_COMPONENT_BINARY_ARGS:
case DEMANGLE_COMPONENT_TRINARY:
case DEMANGLE_COMPONENT_TRINARY_ARG1:
case DEMANGLE_COMPONENT_TRINARY_ARG2:
case DEMANGLE_COMPONENT_LITERAL:
case DEMANGLE_COMPONENT_LITERAL_NEG:
break;
/* These component types only have one subtree. */
case DEMANGLE_COMPONENT_VTABLE:
case DEMANGLE_COMPONENT_VTT:
case DEMANGLE_COMPONENT_TYPEINFO:
case DEMANGLE_COMPONENT_TYPEINFO_NAME:
case DEMANGLE_COMPONENT_TYPEINFO_FN:
case DEMANGLE_COMPONENT_THUNK:
case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
case DEMANGLE_COMPONENT_COVARIANT_THUNK:
case DEMANGLE_COMPONENT_JAVA_CLASS:
case DEMANGLE_COMPONENT_GUARD:
case DEMANGLE_COMPONENT_REFTEMP:
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_REFERENCE:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
2004-01-13 05:24:38 +08:00
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_IMAGINARY:
case DEMANGLE_COMPONENT_VENDOR_TYPE:
case DEMANGLE_COMPONENT_CAST:
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<int> struct A {}; template <typename Y> void function_temp(A<sizeof ((Y)(999))>) {} template void function_temp<int>(A<sizeof (int)>); The 'function_temp<int>' 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 "<sizeof (int)>"), 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 <typename U> 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/ 2015-11-27 Pedro Alves <palves@redhat.com> PR other/61321 PR other/61233 * demangle.h (enum demangle_component_type) <DEMANGLE_COMPONENT_CONVERSION>: 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@231020 138bc75d-0d04-0410-961f-82ee72b054a4
2015-11-29 00:39:31 +08:00
case DEMANGLE_COMPONENT_CONVERSION:
2004-01-13 05:24:38 +08:00
if (right != NULL)
return 0;
break;
default:
/* Other types do not use subtrees. */
return 0;
}
p->type = type;
p->u.s_binary.left = left;
p->u.s_binary.right = right;
p->d_printing = 0;
2004-01-13 05:24:38 +08:00
return 1;
}
/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE. */
int
2005-03-27 13:28:42 +08:00
cplus_demangle_fill_builtin_type (struct demangle_component *p,
2005-05-25 05:01:33 +08:00
const char *type_name)
2004-01-13 05:24:38 +08:00
{
int len;
unsigned int i;
2005-05-25 05:01:33 +08:00
if (p == NULL || type_name == NULL)
2004-01-13 05:24:38 +08:00
return 0;
2005-05-25 05:01:33 +08:00
len = strlen (type_name);
2004-01-13 05:24:38 +08:00
for (i = 0; i < D_BUILTIN_TYPE_COUNT; ++i)
{
if (len == cplus_demangle_builtin_types[i].len
2005-05-25 05:01:33 +08:00
&& strcmp (type_name, cplus_demangle_builtin_types[i].name) == 0)
2004-01-13 05:24:38 +08:00
{
p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE;
p->u.s_builtin.type = &cplus_demangle_builtin_types[i];
p->d_printing = 0;
2004-01-13 05:24:38 +08:00
return 1;
}
}
return 0;
}
/* Fill in a DEMANGLE_COMPONENT_OPERATOR. */
int
2005-03-27 13:28:42 +08:00
cplus_demangle_fill_operator (struct demangle_component *p,
const char *opname, int args)
2004-01-13 05:24:38 +08:00
{
int len;
unsigned int i;
if (p == NULL || opname == NULL)
return 0;
len = strlen (opname);
for (i = 0; cplus_demangle_operators[i].name != NULL; ++i)
{
if (len == cplus_demangle_operators[i].len
&& args == cplus_demangle_operators[i].args
&& strcmp (opname, cplus_demangle_operators[i].name) == 0)
{
p->type = DEMANGLE_COMPONENT_OPERATOR;
p->u.s_operator.op = &cplus_demangle_operators[i];
p->d_printing = 0;
2004-01-13 05:24:38 +08:00
return 1;
}
}
return 0;
}
/* Translate a mangled name into components. */
struct demangle_component *
2005-03-27 13:28:42 +08:00
cplus_demangle_v3_components (const char *mangled, int options, void **mem)
2004-01-13 05:24:38 +08:00
{
size_t len;
int type;
struct d_info di;
struct demangle_component *dc;
len = strlen (mangled);
if (mangled[0] == '_' && mangled[1] == 'Z')
type = 0;
else
{
if ((options & DMGL_TYPES) == 0)
return NULL;
type = 1;
}
cplus_demangle_init_info (mangled, options, len, &di);
di.comps = ((struct demangle_component *)
malloc (di.num_comps * sizeof (struct demangle_component)));
di.subs = ((struct demangle_component **)
malloc (di.num_subs * sizeof (struct demangle_component *)));
if (di.comps == NULL || di.subs == NULL)
{
2011-04-21 03:06:46 +08:00
free (di.comps);
free (di.subs);
2004-01-13 05:24:38 +08:00
return NULL;
}
if (! type)
dc = cplus_demangle_mangled_name (&di, 1);
else
dc = cplus_demangle_type (&di);
/* If DMGL_PARAMS is set, then if we didn't consume the entire
mangled string, then we didn't successfully demangle it. */
if ((options & DMGL_PARAMS) != 0 && d_peek_char (&di) != '\0')
dc = NULL;
free (di.subs);
if (dc != NULL)
*mem = di.comps;
else
free (di.comps);
return dc;
}