+2006-12-20 Geoffrey Keating <geoffk@apple.com>
+
+ * cp-demangle.h: Add comment explaining what to do to avoid
+ overrunning string.
+ (d_check_char): New.
+ (d_next_char): Don't advance past trailing '\0'.
+ * cp-demangle.c (cplus_demangle_mangled_name): Use d_check_char.
+ (d_nested_name): Likewise.
+ (d_special_name): Likewise.
+ (d_call_offset): Likewise.
+ (d_function_type): Likewise.
+ (d_array_type): Likewise.
+ (d_pointer_to_member_type): Likewise.
+ (d_template_param): Likewise.
+ (d_template_args): Likewise.
+ (d_template_arg): Likewise.
+ (d_expr_primary): Likewise.
+ (d_local_name): Likewise.
+ (d_substitution): Likewise.
+ (d_ctor_dtor_name): Use d_advance rather than d_next_char.
+ * testsuite/test-demangle.c: Include sys/mman.h.
+ (MAP_ANONYMOUS): Define.
+ (protect_end): New.
+ (main): Use protect_end.
+ * testsuite/demangle-expected: Add testcases for overrunning
+ the end of the string.
+
2006-11-30 Andrew Stubbs <andrew.stubbs@st.com>
J"orn Rennecke <joern.rennecke@st.com>
struct demangle_component *
cplus_demangle_mangled_name (struct d_info *di, int top_level)
{
- if (d_next_char (di) != '_')
+ if (! d_check_char (di, '_'))
return NULL;
- if (d_next_char (di) != 'Z')
+ if (! d_check_char (di, 'Z'))
return NULL;
return d_encoding (di, top_level);
}
struct demangle_component *ret;
struct demangle_component **pret;
- if (d_next_char (di) != 'N')
+ if (! d_check_char (di, 'N'))
return NULL;
pret = d_cv_qualifiers (di, &ret, 1);
if (*pret == NULL)
return NULL;
- if (d_next_char (di) != 'E')
+ if (! d_check_char (di, 'E'))
return NULL;
return ret;
static struct demangle_component *
d_special_name (struct d_info *di)
{
- char c;
-
di->expansion += 20;
- c = d_next_char (di);
- if (c == 'T')
+ if (d_check_char (di, 'T'))
{
switch (d_next_char (di))
{
offset = d_number (di);
if (offset < 0)
return NULL;
- if (d_next_char (di) != '_')
+ if (! d_check_char (di, '_'))
return NULL;
base_type = cplus_demangle_type (di);
/* We don't display the offset. FIXME: We should display
return NULL;
}
}
- else if (c == 'G')
+ else if (d_check_char (di, 'G'))
{
switch (d_next_char (di))
{
else if (c == 'v')
{
d_number (di);
- if (d_next_char (di) != '_')
+ if (! d_check_char (di, '_'))
return 0;
d_number (di);
}
else
return 0;
- if (d_next_char (di) != '_')
+ if (! d_check_char (di, '_'))
return 0;
return 1;
else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD)
di->expansion += di->last_name->u.s_string.len;
}
- switch (d_next_char (di))
+ switch (d_peek_char (di))
{
case 'C':
{
enum gnu_v3_ctor_kinds kind;
- switch (d_next_char (di))
+ switch (d_peek_next_char (di))
{
case '1':
kind = gnu_v3_complete_object_ctor;
default:
return NULL;
}
+ d_advance (di, 2);
return d_make_ctor (di, kind, di->last_name);
}
{
enum gnu_v3_dtor_kinds kind;
- switch (d_next_char (di))
+ switch (d_peek_next_char (di))
{
case '0':
kind = gnu_v3_deleting_dtor;
default:
return NULL;
}
+ d_advance (di, 2);
return d_make_dtor (di, kind, di->last_name);
}
{
struct demangle_component *ret;
- if (d_next_char (di) != 'F')
+ if (! d_check_char (di, 'F'))
return NULL;
if (d_peek_char (di) == 'Y')
{
d_advance (di, 1);
}
ret = d_bare_function_type (di, 1);
- if (d_next_char (di) != 'E')
+ if (! d_check_char (di, 'E'))
return NULL;
return ret;
}
char peek;
struct demangle_component *dim;
- if (d_next_char (di) != 'A')
+ if (! d_check_char (di, 'A'))
return NULL;
peek = d_peek_char (di);
return NULL;
}
- if (d_next_char (di) != '_')
+ if (! d_check_char (di, '_'))
return NULL;
return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim,
struct demangle_component *mem;
struct demangle_component **pmem;
- if (d_next_char (di) != 'M')
+ if (! d_check_char (di, 'M'))
return NULL;
cl = cplus_demangle_type (di);
{
long param;
- if (d_next_char (di) != 'T')
+ if (! d_check_char (di, 'T'))
return NULL;
if (d_peek_char (di) == '_')
param += 1;
}
- if (d_next_char (di) != '_')
+ if (! d_check_char (di, '_'))
return NULL;
++di->did_subs;
constructor or destructor. */
hold_last_name = di->last_name;
- if (d_next_char (di) != 'I')
+ if (! d_check_char (di, 'I'))
return NULL;
al = NULL;
case 'X':
d_advance (di, 1);
ret = d_expression (di);
- if (d_next_char (di) != 'E')
+ if (! d_check_char (di, 'E'))
return NULL;
return ret;
{
struct demangle_component *ret;
- if (d_next_char (di) != 'L')
+ if (! d_check_char (di, 'L'))
return NULL;
if (d_peek_char (di) == '_')
ret = cplus_demangle_mangled_name (di, 0);
}
ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
}
- if (d_next_char (di) != 'E')
+ if (! d_check_char (di, 'E'))
return NULL;
return ret;
}
{
struct demangle_component *function;
- if (d_next_char (di) != 'Z')
+ if (! d_check_char (di, 'Z'))
return NULL;
function = d_encoding (di, 0);
- if (d_next_char (di) != 'E')
+ if (! d_check_char (di, 'E'))
return NULL;
if (d_peek_char (di) == 's')
{
char c;
- if (d_next_char (di) != 'S')
+ if (! d_check_char (di, 'S'))
return NULL;
c = d_next_char (di);
buf->alloced = alloc;
}
+/* If we have mmap() and mprotect(), copy the string S just before a
+ protected page, so that if the demangler runs over the end of the
+ string we'll get a fault, and return the address of the new string.
+ If no mmap, or it fails, or it looks too hard, just return S. */
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#if defined(MAP_ANON) && ! defined (MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+static const char *
+protect_end (const char * s)
+{
+#if defined(HAVE_MMAP) && defined (MAP_ANONYMOUS)
+ size_t pagesize = getpagesize();
+ static char * buf;
+ size_t s_len = strlen (s);
+ char * result;
+
+ /* Don't try if S is too long. */
+ if (s_len >= pagesize)
+ return s;
+
+ /* Allocate one page of allocated space followed by an unmapped
+ page. */
+ if (buf == NULL)
+ {
+ buf = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (! buf)
+ return s;
+ munmap (buf + pagesize, pagesize);
+ }
+
+ result = buf + (pagesize - s_len - 1);
+ memcpy (result, s, s_len + 1);
+ return result;
+#else
+ return s;
+#endif
+}
+
static void
fail (lineno, opts, in, out, exp)
int lineno;
for (;;)
{
+ const char *inp;
+
getline (&format);
if (feof (stdin))
break;
getline (&input);
getline (&expect);
+ inp = protect_end (input.data);
+
tests++;
no_params = 0;
{
enum gnu_v3_ctor_kinds kc;
- kc = is_gnu_v3_mangled_ctor (input.data);
+ kc = is_gnu_v3_mangled_ctor (inp);
sprintf (buf, "%d", (int) kc);
}
else
{
enum gnu_v3_dtor_kinds kd;
- kd = is_gnu_v3_mangled_dtor (input.data);
+ kd = is_gnu_v3_mangled_dtor (inp);
sprintf (buf, "%d", (int) kd);
}
cplus_demangle_set_style (style);
- result = cplus_demangle (input.data,
+ result = cplus_demangle (inp,
DMGL_PARAMS|DMGL_ANSI|DMGL_TYPES
|(ret_postfix ? DMGL_RET_POSTFIX : 0));
if (no_params)
{
getline (&expect);
- result = cplus_demangle (input.data, DMGL_ANSI|DMGL_TYPES);
+ result = cplus_demangle (inp, DMGL_ANSI|DMGL_TYPES);
if (result
? strcmp (result, expect.data)