Hi Bernd,
Thanks for the feedback!
> Patches need to be bootstrapped and regression tested, and patch submissions
> should include which target this was done on.
>
> Ideally you'd also want to include testcases along with your patches,
> although I'm not entirely sure how we can arrange for this type of problem to
> be tested.
Regression tested on x86_64-pc-linux-gnu (make check). Test cases added to
libiberty/testsuite/demangler-expected and checked PR70498 is resolved. Not
sure how to bootstrap the patch.
> Lastly, for this specific patch, I have trouble seeing how it fixes anything.
> I'd need a more detailed explanation of how the problem happens in the first
> place.
In the patched version, the values wrap around when they are parsed in
d_number. Since the mangled string may contain negative numbers, there is
usually proper handling of negative numbers in the clients of d_number. Without
the patch a value can become negative when cast from long to int *after* these
checks.
For instance, in d_source_name the length of the identifier is parsed as long
from the mangled string and checked whether it is negative. Since d_identifier
takes an int as length, d_identifier is called with a negative length after the
implicit cast:
static struct demangle_component *
d_source_name (struct d_info *di)
{
int len;
struct demangle_component *ret;
len = d_number (di);
if (len <= 0)
return NULL;
ret = d_identifier (di, len);
di->last_name = ret;
return ret;
}
--
Index: libiberty/cp-demangle.c
===================================================================
--- libiberty/cp-demangle.c (revision 234663)
+++ libiberty/cp-demangle.c (working copy)
@@ -398,7 +398,7 @@
struct demangle_component *);
static struct demangle_component *
-d_make_template_param (struct d_info *, long);
+d_make_template_param (struct d_info *, int);
static struct demangle_component *
d_make_sub (struct d_info *, const char *, int);
@@ -421,9 +421,9 @@
static struct demangle_component *d_source_name (struct d_info *);
-static long d_number (struct d_info *);
+static int d_number (struct d_info *);
-static struct demangle_component *d_identifier (struct d_info *, long);
+static struct demangle_component *d_identifier (struct d_info *, int);
static struct demangle_component *d_operator_name (struct d_info *);
@@ -1119,7 +1119,7 @@
/* Add a new template parameter. */
static struct demangle_component *
-d_make_template_param (struct d_info *di, long i)
+d_make_template_param (struct d_info *di, int i)
{
struct demangle_component *p;
@@ -1135,7 +1135,7 @@
/* Add a new function parameter. */
static struct demangle_component *
-d_make_function_param (struct d_info *di, long i)
+d_make_function_param (struct d_info *di, int i)
{
struct demangle_component *p;
@@ -1620,7 +1620,7 @@
static struct demangle_component *
d_source_name (struct d_info *di)
{
- long len;
+ int len;
struct demangle_component *ret;
len = d_number (di);
@@ -1633,12 +1633,12 @@
/* number ::= [n] <(non-negative decimal integer)> */
-static long
+static int
d_number (struct d_info *di)
{
int negative;
char peek;
- long ret;
+ int ret;
negative = 0;
peek = d_peek_char (di);
@@ -1681,7 +1681,7 @@
/* identifier ::= <(unqualified source code identifier)> */
static struct demangle_component *
-d_identifier (struct d_info *di, long len)
+d_identifier (struct d_info *di, int len)
{
const char *name;
@@ -1702,7 +1702,7 @@
/* Look for something which looks like a gcc encoding of an
anonymous namespace, and replace it with a more user friendly
name. */
- if (len >= (long) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
+ if (len >= ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
&& memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
{
@@ -1870,7 +1870,7 @@
{
struct demangle_component *p = NULL;
struct demangle_component *next = NULL;
- long len, i;
+ int len, i;
char c;
const char *str;
@@ -2012,7 +2012,7 @@
case 'C':
{
struct demangle_component *derived_type;
- long offset;
+ int offset;
struct demangle_component *base_type;
derived_type = cplus_demangle_type (di);
@@ -2946,10 +2946,10 @@
/* <non-negative number> _ */
-static long
+static int
d_compact_number (struct d_info *di)
{
- long num;
+ int num;
if (d_peek_char (di) == '_')
num = 0;
else if (d_peek_char (di) == 'n')
@@ -2969,7 +2969,7 @@
static struct demangle_component *
d_template_param (struct d_info *di)
{
- long param;
+ int param;
if (! d_check_char (di, 'T'))
return NULL;
@@ -3502,7 +3502,7 @@
static int
d_discriminator (struct d_info *di)
{
- long discrim;
+ int discrim;
if (d_peek_char (di) != '_')
return 1;
@@ -3558,7 +3558,7 @@
d_unnamed_type (struct d_info *di)
{
struct demangle_component *ret;
- long num;
+ int num;
if (! d_check_char (di, 'U'))
return NULL;
@@ -4086,7 +4086,7 @@
}
static inline void
-d_append_num (struct d_print_info *dpi, long l)
+d_append_num (struct d_print_info *dpi, int l)
{
char buf[25];
sprintf (buf,"%ld", l);
Index: libiberty/testsuite/demangle-expected
===================================================================
--- libiberty/testsuite/demangle-expected (revision 234663)
+++ libiberty/testsuite/demangle-expected (working copy)
@@ -4422,12 +4422,17 @@
_Z3fooI1FEN1XIXszdtcl1PclcvT__EEE5arrayEE4TypeEv
X<sizeof ((P(((F)())())).array)>::Type foo<F>()
#
-# Tests a use-after-free problem
+# Tests a use-after-free problem PR70481
_Q.__0
::Q.(void)
#
-# Tests a use-after-free problem
+# Tests a use-after-free problem PR70481
_Q10-__9cafebabe.
cafebabe.::-(void)
+#
+# Tests write access violation PR70498
+
+_Z80800000000000000000000
+_Z80800000000000000000000