Révision | d81bf7ddc2ad497037fbfde5d15cfa8d81a9e959 (tree) |
---|---|
l'heure | 2015-11-29 01:39:29 |
Auteur | Mikhail Maltsev <maltsevm@gmai...> |
Commiter | Pedro Alves |
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
@@ -52,6 +52,19 @@ | ||
52 | 52 | |
53 | 53 | * configure: Regenerated. |
54 | 54 | |
55 | +2015-07-13 Mikhail Maltsev <maltsevm@gmail.com> | |
56 | + | |
57 | + * cp-demangle.c (d_dump): Fix syntax error. | |
58 | + (d_identifier): Adjust type of len to match d_source_name. | |
59 | + (d_expression_1): Fix out-of-bounds access. Check code variable for | |
60 | + NULL before dereferencing it. | |
61 | + (d_find_pack): Do not recurse for FIXED_TYPE, DEFAULT_ARG and NUMBER. | |
62 | + (d_print_comp_inner): Add NULL pointer check. | |
63 | + * cp-demangle.h (d_peek_next_char): Define as inline function when | |
64 | + CHECK_DEMANGLER is defined. | |
65 | + (d_advance): Likewise. | |
66 | + * testsuite/demangle-expected: Add new testcases. | |
67 | + | |
55 | 68 | 2015-07-09 Uros Bizjak <ubizjak@gmail.com> |
56 | 69 | |
57 | 70 | * getruntime.c (RUSAGE_SELF): Define if not already defined. |
@@ -93,7 +93,11 @@ | ||
93 | 93 | CP_DEMANGLE_DEBUG |
94 | 94 | If defined, turns on debugging mode, which prints information on |
95 | 95 | stdout about the mangled string. This is not generally useful. |
96 | -*/ | |
96 | + | |
97 | + CHECK_DEMANGLER | |
98 | + If defined, additional sanity checks will be performed. It will | |
99 | + cause some slowdown, but will allow to catch out-of-bound access | |
100 | + errors earlier. This macro is intended for testing and debugging. */ | |
97 | 101 | |
98 | 102 | #if defined (_AIX) && !defined (__GNUC__) |
99 | 103 | #pragma alloca |
@@ -419,7 +423,7 @@ static struct demangle_component *d_source_name (struct d_info *); | ||
419 | 423 | |
420 | 424 | static long d_number (struct d_info *); |
421 | 425 | |
422 | -static struct demangle_component *d_identifier (struct d_info *, int); | |
426 | +static struct demangle_component *d_identifier (struct d_info *, long); | |
423 | 427 | |
424 | 428 | static struct demangle_component *d_operator_name (struct d_info *); |
425 | 429 |
@@ -715,7 +719,7 @@ d_dump (struct demangle_component *dc, int indent) | ||
715 | 719 | case DEMANGLE_COMPONENT_FIXED_TYPE: |
716 | 720 | printf ("fixed-point type, accum? %d, sat? %d\n", |
717 | 721 | dc->u.s_fixed.accum, dc->u.s_fixed.sat); |
718 | - d_dump (dc->u.s_fixed.length, indent + 2) | |
722 | + d_dump (dc->u.s_fixed.length, indent + 2); | |
719 | 723 | break; |
720 | 724 | case DEMANGLE_COMPONENT_ARGLIST: |
721 | 725 | printf ("argument list\n"); |
@@ -1664,7 +1668,7 @@ d_number_component (struct d_info *di) | ||
1664 | 1668 | /* identifier ::= <(unqualified source code identifier)> */ |
1665 | 1669 | |
1666 | 1670 | static struct demangle_component * |
1667 | -d_identifier (struct d_info *di, int len) | |
1671 | +d_identifier (struct d_info *di, long len) | |
1668 | 1672 | { |
1669 | 1673 | const char *name; |
1670 | 1674 |
@@ -1685,7 +1689,7 @@ d_identifier (struct d_info *di, int len) | ||
1685 | 1689 | /* Look for something which looks like a gcc encoding of an |
1686 | 1690 | anonymous namespace, and replace it with a more user friendly |
1687 | 1691 | name. */ |
1688 | - if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 | |
1692 | + if (len >= (long) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 | |
1689 | 1693 | && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX, |
1690 | 1694 | ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0) |
1691 | 1695 | { |
@@ -3174,6 +3178,8 @@ d_expression_1 (struct d_info *di) | ||
3174 | 3178 | struct demangle_component *type = NULL; |
3175 | 3179 | if (peek == 't') |
3176 | 3180 | type = cplus_demangle_type (di); |
3181 | + if (!d_peek_next_char (di)) | |
3182 | + return NULL; | |
3177 | 3183 | d_advance (di, 2); |
3178 | 3184 | return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, |
3179 | 3185 | type, d_exprlist (di, 'E')); |
@@ -3248,6 +3254,8 @@ d_expression_1 (struct d_info *di) | ||
3248 | 3254 | struct demangle_component *left; |
3249 | 3255 | struct demangle_component *right; |
3250 | 3256 | |
3257 | + if (code == NULL) | |
3258 | + return NULL; | |
3251 | 3259 | if (op_is_new_cast (op)) |
3252 | 3260 | left = cplus_demangle_type (di); |
3253 | 3261 | else |
@@ -3275,7 +3283,9 @@ d_expression_1 (struct d_info *di) | ||
3275 | 3283 | struct demangle_component *second; |
3276 | 3284 | struct demangle_component *third; |
3277 | 3285 | |
3278 | - if (!strcmp (code, "qu")) | |
3286 | + if (code == NULL) | |
3287 | + return NULL; | |
3288 | + else if (!strcmp (code, "qu")) | |
3279 | 3289 | { |
3280 | 3290 | /* ?: expression. */ |
3281 | 3291 | first = d_expression_1 (di); |
@@ -4204,6 +4214,9 @@ d_find_pack (struct d_print_info *dpi, | ||
4204 | 4214 | case DEMANGLE_COMPONENT_CHARACTER: |
4205 | 4215 | case DEMANGLE_COMPONENT_FUNCTION_PARAM: |
4206 | 4216 | case DEMANGLE_COMPONENT_UNNAMED_TYPE: |
4217 | + case DEMANGLE_COMPONENT_FIXED_TYPE: | |
4218 | + case DEMANGLE_COMPONENT_DEFAULT_ARG: | |
4219 | + case DEMANGLE_COMPONENT_NUMBER: | |
4207 | 4220 | return NULL; |
4208 | 4221 | |
4209 | 4222 | case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: |
@@ -4439,6 +4452,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options, | ||
4439 | 4452 | local_name = d_right (typed_name); |
4440 | 4453 | if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) |
4441 | 4454 | local_name = local_name->u.s_unary_num.sub; |
4455 | + if (local_name == NULL) | |
4456 | + { | |
4457 | + d_print_error (dpi); | |
4458 | + return; | |
4459 | + } | |
4442 | 4460 | while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS |
4443 | 4461 | || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS |
4444 | 4462 | || local_name->type == DEMANGLE_COMPONENT_CONST_THIS |
@@ -135,12 +135,37 @@ struct d_info | ||
135 | 135 | - call d_check_char(di, '\0') |
136 | 136 | Everything else is safe. */ |
137 | 137 | #define d_peek_char(di) (*((di)->n)) |
138 | -#define d_peek_next_char(di) ((di)->n[1]) | |
139 | -#define d_advance(di, i) ((di)->n += (i)) | |
138 | +#ifndef CHECK_DEMANGLER | |
139 | +# define d_peek_next_char(di) ((di)->n[1]) | |
140 | +# define d_advance(di, i) ((di)->n += (i)) | |
141 | +#endif | |
140 | 142 | #define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0) |
141 | 143 | #define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++)) |
142 | 144 | #define d_str(di) ((di)->n) |
143 | 145 | |
146 | +#ifdef CHECK_DEMANGLER | |
147 | +static inline char | |
148 | +d_peek_next_char (const struct d_info *di) | |
149 | +{ | |
150 | + if (!di->n[0]) | |
151 | + abort (); | |
152 | + return di->n[1]; | |
153 | +} | |
154 | + | |
155 | +static inline void | |
156 | +d_advance (struct d_info *di, int i) | |
157 | +{ | |
158 | + if (i < 0) | |
159 | + abort (); | |
160 | + while (i--) | |
161 | + { | |
162 | + if (!di->n[0]) | |
163 | + abort (); | |
164 | + di->n++; | |
165 | + } | |
166 | +} | |
167 | +#endif | |
168 | + | |
144 | 169 | /* Functions and arrays in cp-demangle.c which are referenced by |
145 | 170 | functions in cp-demint.c. */ |
146 | 171 | #ifdef IN_GLIBCPP_V3 |
@@ -4091,6 +4091,36 @@ void g<1>(A<1>&, B<static_cast<bool>(1)>&) | ||
4091 | 4091 | _ZNKSt7complexIiE4realB5cxx11Ev |
4092 | 4092 | std::complex<int>::real[abi:cxx11]() const |
4093 | 4093 | # |
4094 | +# Some more crashes revealed by fuzz-testing: | |
4095 | +# Check for NULL pointer when demangling trinary operators | |
4096 | +--format=gnu-v3 | |
4097 | +_Z1fAv32_f | |
4098 | +_Z1fAv32_f | |
4099 | +# Do not overflow when decoding identifier length | |
4100 | +--format=gnu-v3 | |
4101 | +_Z11111111111 | |
4102 | +_Z11111111111 | |
4103 | +# Check out-of-bounds access when decoding braced initializer list | |
4104 | +--format=gnu-v3 | |
4105 | +_ZDTtl | |
4106 | +_ZDTtl | |
4107 | +# Check for NULL pointer when demangling DEMANGLE_COMPONENT_LOCAL_NAME | |
4108 | +--format=gnu-v3 | |
4109 | +_ZZN1fEEd_lEv | |
4110 | +_ZZN1fEEd_lEv | |
4111 | +# Handle DEMANGLE_COMPONENT_FIXED_TYPE in d_find_pack | |
4112 | +--format=gnu-v3 | |
4113 | +_Z1fDpDFT_ | |
4114 | +_Z1fDpDFT_ | |
4115 | +# Likewise, DEMANGLE_COMPONENT_DEFAULT_ARG | |
4116 | +--format=gnu-v3 | |
4117 | +_Z1fIDpZ1fEd_E | |
4118 | +_Z1fIDpZ1fEd_E | |
4119 | +# Likewise, DEMANGLE_COMPONENT_NUMBER | |
4120 | +--format=gnu-v3 | |
4121 | +_Z1fDpDv1_c | |
4122 | +f((char __vector(1))...) | |
4123 | +# | |
4094 | 4124 | # Ada (GNAT) tests. |
4095 | 4125 | # |
4096 | 4126 | # Simple test. |