Fix several crashes of C++ demangler on fuzzed input.
libiberty/ * cp-demangle.c (d_dump): Fix syntax error. (d_identifier): Adjust type of len to match d_source_name. (d_expression_1): Fix out-of-bounds access. Check code variable for NULL before dereferencing it. (d_find_pack): Do not recurse for FIXED_TYPE, DEFAULT_ARG and NUMBER. (d_print_comp_inner): Add NULL pointer check. * cp-demangle.h (d_peek_next_char): Define as inline function when CHECK_DEMANGLER is defined. (d_advance): Likewise. * testsuite/demangle-expected: Add new testcases. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@225727 138bc75d-0d04-0410-961f-82ee72b054a4
This commit is contained in:
parent
6a8796db36
commit
d81bf7ddc2
4 changed files with 94 additions and 8 deletions
|
@ -52,6 +52,19 @@
|
||||||
|
|
||||||
* configure: Regenerated.
|
* configure: Regenerated.
|
||||||
|
|
||||||
|
2015-07-13 Mikhail Maltsev <maltsevm@gmail.com>
|
||||||
|
|
||||||
|
* cp-demangle.c (d_dump): Fix syntax error.
|
||||||
|
(d_identifier): Adjust type of len to match d_source_name.
|
||||||
|
(d_expression_1): Fix out-of-bounds access. Check code variable for
|
||||||
|
NULL before dereferencing it.
|
||||||
|
(d_find_pack): Do not recurse for FIXED_TYPE, DEFAULT_ARG and NUMBER.
|
||||||
|
(d_print_comp_inner): Add NULL pointer check.
|
||||||
|
* cp-demangle.h (d_peek_next_char): Define as inline function when
|
||||||
|
CHECK_DEMANGLER is defined.
|
||||||
|
(d_advance): Likewise.
|
||||||
|
* testsuite/demangle-expected: Add new testcases.
|
||||||
|
|
||||||
2015-07-09 Uros Bizjak <ubizjak@gmail.com>
|
2015-07-09 Uros Bizjak <ubizjak@gmail.com>
|
||||||
|
|
||||||
* getruntime.c (RUSAGE_SELF): Define if not already defined.
|
* getruntime.c (RUSAGE_SELF): Define if not already defined.
|
||||||
|
|
|
@ -93,7 +93,11 @@
|
||||||
CP_DEMANGLE_DEBUG
|
CP_DEMANGLE_DEBUG
|
||||||
If defined, turns on debugging mode, which prints information on
|
If defined, turns on debugging mode, which prints information on
|
||||||
stdout about the mangled string. This is not generally useful.
|
stdout about the mangled string. This is not generally useful.
|
||||||
*/
|
|
||||||
|
CHECK_DEMANGLER
|
||||||
|
If defined, additional sanity checks will be performed. It will
|
||||||
|
cause some slowdown, but will allow to catch out-of-bound access
|
||||||
|
errors earlier. This macro is intended for testing and debugging. */
|
||||||
|
|
||||||
#if defined (_AIX) && !defined (__GNUC__)
|
#if defined (_AIX) && !defined (__GNUC__)
|
||||||
#pragma alloca
|
#pragma alloca
|
||||||
|
@ -419,7 +423,7 @@ static struct demangle_component *d_source_name (struct d_info *);
|
||||||
|
|
||||||
static long d_number (struct d_info *);
|
static long d_number (struct d_info *);
|
||||||
|
|
||||||
static struct demangle_component *d_identifier (struct d_info *, int);
|
static struct demangle_component *d_identifier (struct d_info *, long);
|
||||||
|
|
||||||
static struct demangle_component *d_operator_name (struct d_info *);
|
static struct demangle_component *d_operator_name (struct d_info *);
|
||||||
|
|
||||||
|
@ -715,7 +719,7 @@ d_dump (struct demangle_component *dc, int indent)
|
||||||
case DEMANGLE_COMPONENT_FIXED_TYPE:
|
case DEMANGLE_COMPONENT_FIXED_TYPE:
|
||||||
printf ("fixed-point type, accum? %d, sat? %d\n",
|
printf ("fixed-point type, accum? %d, sat? %d\n",
|
||||||
dc->u.s_fixed.accum, dc->u.s_fixed.sat);
|
dc->u.s_fixed.accum, dc->u.s_fixed.sat);
|
||||||
d_dump (dc->u.s_fixed.length, indent + 2)
|
d_dump (dc->u.s_fixed.length, indent + 2);
|
||||||
break;
|
break;
|
||||||
case DEMANGLE_COMPONENT_ARGLIST:
|
case DEMANGLE_COMPONENT_ARGLIST:
|
||||||
printf ("argument list\n");
|
printf ("argument list\n");
|
||||||
|
@ -1664,7 +1668,7 @@ d_number_component (struct d_info *di)
|
||||||
/* identifier ::= <(unqualified source code identifier)> */
|
/* identifier ::= <(unqualified source code identifier)> */
|
||||||
|
|
||||||
static struct demangle_component *
|
static struct demangle_component *
|
||||||
d_identifier (struct d_info *di, int len)
|
d_identifier (struct d_info *di, long len)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
@ -1685,7 +1689,7 @@ d_identifier (struct d_info *di, int len)
|
||||||
/* Look for something which looks like a gcc encoding of an
|
/* Look for something which looks like a gcc encoding of an
|
||||||
anonymous namespace, and replace it with a more user friendly
|
anonymous namespace, and replace it with a more user friendly
|
||||||
name. */
|
name. */
|
||||||
if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
|
if (len >= (long) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
|
||||||
&& memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
|
&& memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
|
||||||
ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
|
ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
|
||||||
{
|
{
|
||||||
|
@ -3174,6 +3178,8 @@ d_expression_1 (struct d_info *di)
|
||||||
struct demangle_component *type = NULL;
|
struct demangle_component *type = NULL;
|
||||||
if (peek == 't')
|
if (peek == 't')
|
||||||
type = cplus_demangle_type (di);
|
type = cplus_demangle_type (di);
|
||||||
|
if (!d_peek_next_char (di))
|
||||||
|
return NULL;
|
||||||
d_advance (di, 2);
|
d_advance (di, 2);
|
||||||
return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
|
return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
|
||||||
type, d_exprlist (di, 'E'));
|
type, d_exprlist (di, 'E'));
|
||||||
|
@ -3248,6 +3254,8 @@ d_expression_1 (struct d_info *di)
|
||||||
struct demangle_component *left;
|
struct demangle_component *left;
|
||||||
struct demangle_component *right;
|
struct demangle_component *right;
|
||||||
|
|
||||||
|
if (code == NULL)
|
||||||
|
return NULL;
|
||||||
if (op_is_new_cast (op))
|
if (op_is_new_cast (op))
|
||||||
left = cplus_demangle_type (di);
|
left = cplus_demangle_type (di);
|
||||||
else
|
else
|
||||||
|
@ -3275,7 +3283,9 @@ d_expression_1 (struct d_info *di)
|
||||||
struct demangle_component *second;
|
struct demangle_component *second;
|
||||||
struct demangle_component *third;
|
struct demangle_component *third;
|
||||||
|
|
||||||
if (!strcmp (code, "qu"))
|
if (code == NULL)
|
||||||
|
return NULL;
|
||||||
|
else if (!strcmp (code, "qu"))
|
||||||
{
|
{
|
||||||
/* ?: expression. */
|
/* ?: expression. */
|
||||||
first = d_expression_1 (di);
|
first = d_expression_1 (di);
|
||||||
|
@ -4204,6 +4214,9 @@ d_find_pack (struct d_print_info *dpi,
|
||||||
case DEMANGLE_COMPONENT_CHARACTER:
|
case DEMANGLE_COMPONENT_CHARACTER:
|
||||||
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
|
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
|
||||||
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
|
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
|
||||||
|
case DEMANGLE_COMPONENT_FIXED_TYPE:
|
||||||
|
case DEMANGLE_COMPONENT_DEFAULT_ARG:
|
||||||
|
case DEMANGLE_COMPONENT_NUMBER:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
|
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
|
||||||
|
@ -4439,6 +4452,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
||||||
local_name = d_right (typed_name);
|
local_name = d_right (typed_name);
|
||||||
if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
|
if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
|
||||||
local_name = local_name->u.s_unary_num.sub;
|
local_name = local_name->u.s_unary_num.sub;
|
||||||
|
if (local_name == NULL)
|
||||||
|
{
|
||||||
|
d_print_error (dpi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||||
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||||
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS
|
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||||
|
|
|
@ -135,12 +135,37 @@ struct d_info
|
||||||
- call d_check_char(di, '\0')
|
- call d_check_char(di, '\0')
|
||||||
Everything else is safe. */
|
Everything else is safe. */
|
||||||
#define d_peek_char(di) (*((di)->n))
|
#define d_peek_char(di) (*((di)->n))
|
||||||
#define d_peek_next_char(di) ((di)->n[1])
|
#ifndef CHECK_DEMANGLER
|
||||||
#define d_advance(di, i) ((di)->n += (i))
|
# define d_peek_next_char(di) ((di)->n[1])
|
||||||
|
# define d_advance(di, i) ((di)->n += (i))
|
||||||
|
#endif
|
||||||
#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
|
#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
|
||||||
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
|
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
|
||||||
#define d_str(di) ((di)->n)
|
#define d_str(di) ((di)->n)
|
||||||
|
|
||||||
|
#ifdef CHECK_DEMANGLER
|
||||||
|
static inline char
|
||||||
|
d_peek_next_char (const struct d_info *di)
|
||||||
|
{
|
||||||
|
if (!di->n[0])
|
||||||
|
abort ();
|
||||||
|
return di->n[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
d_advance (struct d_info *di, int i)
|
||||||
|
{
|
||||||
|
if (i < 0)
|
||||||
|
abort ();
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
if (!di->n[0])
|
||||||
|
abort ();
|
||||||
|
di->n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Functions and arrays in cp-demangle.c which are referenced by
|
/* Functions and arrays in cp-demangle.c which are referenced by
|
||||||
functions in cp-demint.c. */
|
functions in cp-demint.c. */
|
||||||
#ifdef IN_GLIBCPP_V3
|
#ifdef IN_GLIBCPP_V3
|
||||||
|
|
|
@ -4091,6 +4091,36 @@ void g<1>(A<1>&, B<static_cast<bool>(1)>&)
|
||||||
_ZNKSt7complexIiE4realB5cxx11Ev
|
_ZNKSt7complexIiE4realB5cxx11Ev
|
||||||
std::complex<int>::real[abi:cxx11]() const
|
std::complex<int>::real[abi:cxx11]() const
|
||||||
#
|
#
|
||||||
|
# Some more crashes revealed by fuzz-testing:
|
||||||
|
# Check for NULL pointer when demangling trinary operators
|
||||||
|
--format=gnu-v3
|
||||||
|
_Z1fAv32_f
|
||||||
|
_Z1fAv32_f
|
||||||
|
# Do not overflow when decoding identifier length
|
||||||
|
--format=gnu-v3
|
||||||
|
_Z11111111111
|
||||||
|
_Z11111111111
|
||||||
|
# Check out-of-bounds access when decoding braced initializer list
|
||||||
|
--format=gnu-v3
|
||||||
|
_ZDTtl
|
||||||
|
_ZDTtl
|
||||||
|
# Check for NULL pointer when demangling DEMANGLE_COMPONENT_LOCAL_NAME
|
||||||
|
--format=gnu-v3
|
||||||
|
_ZZN1fEEd_lEv
|
||||||
|
_ZZN1fEEd_lEv
|
||||||
|
# Handle DEMANGLE_COMPONENT_FIXED_TYPE in d_find_pack
|
||||||
|
--format=gnu-v3
|
||||||
|
_Z1fDpDFT_
|
||||||
|
_Z1fDpDFT_
|
||||||
|
# Likewise, DEMANGLE_COMPONENT_DEFAULT_ARG
|
||||||
|
--format=gnu-v3
|
||||||
|
_Z1fIDpZ1fEd_E
|
||||||
|
_Z1fIDpZ1fEd_E
|
||||||
|
# Likewise, DEMANGLE_COMPONENT_NUMBER
|
||||||
|
--format=gnu-v3
|
||||||
|
_Z1fDpDv1_c
|
||||||
|
f((char __vector(1))...)
|
||||||
|
#
|
||||||
# Ada (GNAT) tests.
|
# Ada (GNAT) tests.
|
||||||
#
|
#
|
||||||
# Simple test.
|
# Simple test.
|
||||||
|
|
Loading…
Reference in a new issue