[C++ PATCH] demangler fix

2014-05-07 Thread Gary Benson
Hi all,

A patch I committed to libiberty last year [1, 2] caused a regression
that caused the demangler to segfault on certain symbols [3, 4, 5, 6].
The attached patch fixes, and adds regression tests for all symbols
referenced in those bugs.

Ok to commit?

Thanks,
Gary

--
http://gbenson.net/

[1] http://gcc.gnu.org/ml/gcc-patches/2013-09/msg01299.html
[2] http://gcc.gnu.org/ml/gcc-patches/2013-12/msg01755.html
[3] https://sourceware.org/bugzilla/show_bug.cgi?id=14963
[4] https://sourceware.org/bugzilla/show_bug.cgi?id=16593
[5] https://sourceware.org/bugzilla/show_bug.cgi?id=16752
[6] https://sourceware.org/bugzilla/show_bug.cgi?id=16845

2014-05-07  Gary Benson  gben...@redhat.com

* cp-demangle.c (struct d_component_stack): New structure.
(struct d_print_info): New field component_stack.
(d_print_init): Initialize the above.
(d_print_comp_inner): Renamed from d_print_comp.
Do not restore template stack if it would cause a loop.
(d_print_comp): New function.
* testsuite/demangle-expected: New test cases.

diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index bf2ffa9..41c86c7 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -275,6 +275,16 @@ struct d_growable_string
   int allocation_failure;
 };
 
+/* Stack of components, innermost first, used to avoid loops.  */
+
+struct d_component_stack
+{
+  /* This component.  */
+  const struct demangle_component *dc;
+  /* This component's parent.  */
+  const struct d_component_stack *parent;
+};
+
 /* A demangle component and some scope captured when it was first
traversed.  */
 
@@ -327,6 +337,8 @@ struct d_print_info
   int pack_index;
   /* Number of d_print_flush calls so far.  */
   unsigned long int flush_count;
+  /* Stack of components, innermost first, used to avoid loops.  */
+  const struct d_component_stack *component_stack;
   /* Array of saved scopes for evaluating substitutions.  */
   struct d_saved_scope *saved_scopes;
   /* Index of the next unused saved scope in the above array.  */
@@ -3934,6 +3946,8 @@ d_print_init (struct d_print_info *dpi, 
demangle_callbackref callback,
 
   dpi-demangle_failure = 0;
 
+  dpi-component_stack = NULL;
+
   dpi-saved_scopes = NULL;
   dpi-next_saved_scope = 0;
   dpi-num_saved_scopes = 0;
@@ -4269,8 +4283,8 @@ d_get_saved_scope (struct d_print_info *dpi,
 /* Subroutine to handle components.  */
 
 static void
-d_print_comp (struct d_print_info *dpi, int options,
-  const struct demangle_component *dc)
+d_print_comp_inner (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
 {
   /* Magic variable to let reference smashing skip over the next modifier
  without needing to modify *dc.  */
@@ -4673,11 +4687,30 @@ d_print_comp (struct d_print_info *dpi, int options,
  }
else
  {
+   const struct d_component_stack *dcse;
+   int found_self_or_parent = 0;
+
/* This traversal is reentering SUB as a substition.
-  Restore the original templates temporarily.  */
-   saved_templates = dpi-templates;
-   dpi-templates = scope-templates;
-   need_template_restore = 1;
+  If we are not beneath SUB or DC in the tree then we
+  need to restore SUB's template stack temporarily.  */
+   for (dcse = dpi-component_stack; dcse != NULL;
+dcse = dcse-parent)
+ {
+   if (dcse-dc == sub
+   || (dcse-dc == dc
+dcse != dpi-component_stack))
+ {
+   found_self_or_parent = 1;
+   break;
+ }
+ }
+
+   if (!found_self_or_parent)
+ {
+   saved_templates = dpi-templates;
+   dpi-templates = scope-templates;
+   need_template_restore = 1;
+ }
  }
 
a = d_lookup_template_argument (dpi, sub);
@@ -5316,6 +5349,21 @@ d_print_comp (struct d_print_info *dpi, int options,
 }
 }
 
+static void
+d_print_comp (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
+{
+  struct d_component_stack self;
+
+  self.dc = dc;
+  self.parent = dpi-component_stack;
+  dpi-component_stack = self;
+
+  d_print_comp_inner (dpi, options, dc);
+
+  dpi-component_stack = self.parent;
+}
+
 /* Print a Java dentifier.  For Java we try to handle encoded extended
Unicode characters.  The C++ ABI doesn't mention Unicode encoding,
so we don't it for C++.  Characters are encoded as
diff --git a/libiberty/testsuite/demangle-expected 
b/libiberty/testsuite/demangle-expected
index 3ff08e6..453f9a3 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ 

Re: [C++ PATCH] demangler fix

2014-05-07 Thread Jason Merrill

OK, thanks.

Jason


Re: [2nd PING] [C++ PATCH] demangler fix (take 2)

2013-10-23 Thread Jason Merrill

On 10/08/2013 05:54 AM, Gary Benson wrote:

diff --git a/test.c b/test.c


I don't think we want to add this to the top level directory.  :)

Other than that, the patch is OK.

Jason



[2nd PING] [C++ PATCH] demangler fix (take 2)

2013-10-08 Thread Gary Benson
Hi all,

This is a resubmission of my previous demangler fix [1] rewritten
to avoid using hashtables and other libiberty features.

From the above referenced email:

d_print_comp maintains a certain amount of scope across calls (namely
a stack of templates) which is used when evaluating references in
template argument lists.  If such a reference is later used from a
subtitution then the scope in force at the time of the substitution is
used.  This appears to be wrong (I say appears because I couldn't find
anything in the API [2] to clarify this).

The attached patch causes the demangler to capture the scope the first
time such a reference is traversed, and to use that captured scope on
subsequent traversals.  This fixes GDB PR 14963 [3] whereby a
reference is resolved against the wrong template, causing an infinite
loop and eventual stack overflow and segmentation fault.

I've added the result to the demangler test suite, but I know of no
way to check the validity of the demangled symbol other than by
inspection (and I am no expert here!)  If anybody knows a way to
check this then please let me know!  Otherwise, I hope this
not-really-checked demangled version is acceptable.

Thanks,
Gary

[1] http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00215.html
[2] http://mentorembedded.github.io/cxx-abi/abi.html#mangling
[3] http://sourceware.org/bugzilla/show_bug.cgi?id=14963

-- 
http://gbenson.net/


diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 89e108a..2ff8216 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,20 @@
+2013-09-17  Gary Benson  gben...@redhat.com
+
+   * cp-demangle.c (struct d_saved_scope): New structure.
+   (struct d_print_info): New fields saved_scopes and
+   num_saved_scopes.
+   (d_print_init): Initialize the above.
+   (d_print_free): New function.
+   (cplus_demangle_print_callback): Call the above.
+   (d_copy_templates): New function.
+   (d_print_comp): New variables saved_templates and
+   need_template_restore.
+   [DEMANGLE_COMPONENT_REFERENCE,
+   DEMANGLE_COMPONENT_RVALUE_REFERENCE]: Capture scope the first
+   time the component is traversed, and use the captured scope for
+   subsequent traversals.
+   * testsuite/demangle-expected: Add regression test.
+
 2013-09-10  Paolo Carlini  paolo.carl...@oracle.com
 
PR bootstrap/58386
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 70f5438..a199f6d 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -275,6 +275,18 @@ struct d_growable_string
   int allocation_failure;
 };
 
+/* A demangle component and some scope captured when it was first
+   traversed.  */
+
+struct d_saved_scope
+{
+  /* The component whose scope this is.  */
+  const struct demangle_component *container;
+  /* The list of templates, if any, that was current when this
+ scope was captured.  */
+  struct d_print_template *templates;
+};
+
 enum { D_PRINT_BUFFER_LENGTH = 256 };
 struct d_print_info
 {
@@ -302,6 +314,10 @@ struct d_print_info
   int pack_index;
   /* Number of d_print_flush calls so far.  */
   unsigned long int flush_count;
+  /* Array of saved scopes for evaluating substitutions.  */
+  struct d_saved_scope *saved_scopes;
+  /* Number of saved scopes in the above array.  */
+  int num_saved_scopes;
 };
 
 #ifdef CP_DEMANGLE_DEBUG
@@ -3665,6 +3681,30 @@ d_print_init (struct d_print_info *dpi, 
demangle_callbackref callback,
   dpi-opaque = opaque;
 
   dpi-demangle_failure = 0;
+
+  dpi-saved_scopes = NULL;
+  dpi-num_saved_scopes = 0;
+}
+
+/* Free a print information structure.  */
+
+static void
+d_print_free (struct d_print_info *dpi)
+{
+  int i;
+
+  for (i = 0; i  dpi-num_saved_scopes; i++)
+{
+  struct d_print_template *ts, *tn;
+
+  for (ts = dpi-saved_scopes[i].templates; ts != NULL; ts = tn)
+   {
+ tn = ts-next;
+ free (ts);
+   }
+}
+
+  free (dpi-saved_scopes);
 }
 
 /* Indicate that an error occurred during printing, and test for error.  */
@@ -3749,6 +3789,7 @@ cplus_demangle_print_callback (int options,
demangle_callbackref callback, void *opaque)
 {
   struct d_print_info dpi;
+  int success;
 
   d_print_init (dpi, callback, opaque);
 
@@ -3756,7 +3797,9 @@ cplus_demangle_print_callback (int options,
 
   d_print_flush (dpi);
 
-  return ! d_print_saw_error (dpi);
+  success = ! d_print_saw_error (dpi);
+  d_print_free (dpi);
+  return success;
 }
 
 /* Turn components into a human readable string.  OPTIONS is the
@@ -3913,6 +3956,36 @@ d_print_subexpr (struct d_print_info *dpi, int options,
 d_append_char (dpi, ')');
 }
 
+/* Return a shallow copy of the current list of templates.
+   On error d_print_error is called and a partial list may
+   be returned.  Whatever is returned must be freed.  */
+
+static struct d_print_template *
+d_copy_templates (struct d_print_info *dpi)
+{
+  struct d_print_template *src, *result, 

[PING] [C++ PATCH] demangler fix (take 2)

2013-09-27 Thread Gary Benson
Gary Benson wrote:
 Hi all,
 
 This is a resubmission of my previous demangler fix [1] rewritten
 to avoid using hashtables and other libiberty features.
 
 From the above referenced email:
 
 d_print_comp maintains a certain amount of scope across calls (namely
 a stack of templates) which is used when evaluating references in
 template argument lists.  If such a reference is later used from a
 subtitution then the scope in force at the time of the substitution is
 used.  This appears to be wrong (I say appears because I couldn't find
 anything in the API [2] to clarify this).
 
 The attached patch causes the demangler to capture the scope the first
 time such a reference is traversed, and to use that captured scope on
 subsequent traversals.  This fixes GDB PR 14963 [3] whereby a
 reference is resolved against the wrong template, causing an infinite
 loop and eventual stack overflow and segmentation fault.
 
 I've added the result to the demangler test suite, but I know of no
 way to check the validity of the demangled symbol other than by
 inspection (and I am no expert here!)  If anybody knows a way to
 check this then please let me know!  Otherwise, I hope this
 not-really-checked demangled version is acceptable.
 
 Thanks,
 Gary
 
 [1] http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00215.html
 [2] http://mentorembedded.github.io/cxx-abi/abi.html#mangling
 [3] http://sourceware.org/bugzilla/show_bug.cgi?id=14963
 
 -- 
 http://gbenson.net/
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 89e108a..2ff8216 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,20 @@
+2013-09-17  Gary Benson  gben...@redhat.com
+
+   * cp-demangle.c (struct d_saved_scope): New structure.
+   (struct d_print_info): New fields saved_scopes and
+   num_saved_scopes.
+   (d_print_init): Initialize the above.
+   (d_print_free): New function.
+   (cplus_demangle_print_callback): Call the above.
+   (d_copy_templates): New function.
+   (d_print_comp): New variables saved_templates and
+   need_template_restore.
+   [DEMANGLE_COMPONENT_REFERENCE,
+   DEMANGLE_COMPONENT_RVALUE_REFERENCE]: Capture scope the first
+   time the component is traversed, and use the captured scope for
+   subsequent traversals.
+   * testsuite/demangle-expected: Add regression test.
+
 2013-09-10  Paolo Carlini  paolo.carl...@oracle.com
 
PR bootstrap/58386
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 70f5438..a199f6d 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -275,6 +275,18 @@ struct d_growable_string
   int allocation_failure;
 };
 
+/* A demangle component and some scope captured when it was first
+   traversed.  */
+
+struct d_saved_scope
+{
+  /* The component whose scope this is.  */
+  const struct demangle_component *container;
+  /* The list of templates, if any, that was current when this
+ scope was captured.  */
+  struct d_print_template *templates;
+};
+
 enum { D_PRINT_BUFFER_LENGTH = 256 };
 struct d_print_info
 {
@@ -302,6 +314,10 @@ struct d_print_info
   int pack_index;
   /* Number of d_print_flush calls so far.  */
   unsigned long int flush_count;
+  /* Array of saved scopes for evaluating substitutions.  */
+  struct d_saved_scope *saved_scopes;
+  /* Number of saved scopes in the above array.  */
+  int num_saved_scopes;
 };
 
 #ifdef CP_DEMANGLE_DEBUG
@@ -3665,6 +3681,30 @@ d_print_init (struct d_print_info *dpi, 
demangle_callbackref callback,
   dpi-opaque = opaque;
 
   dpi-demangle_failure = 0;
+
+  dpi-saved_scopes = NULL;
+  dpi-num_saved_scopes = 0;
+}
+
+/* Free a print information structure.  */
+
+static void
+d_print_free (struct d_print_info *dpi)
+{
+  int i;
+
+  for (i = 0; i  dpi-num_saved_scopes; i++)
+{
+  struct d_print_template *ts, *tn;
+
+  for (ts = dpi-saved_scopes[i].templates; ts != NULL; ts = tn)
+   {
+ tn = ts-next;
+ free (ts);
+   }
+}
+
+  free (dpi-saved_scopes);
 }
 
 /* Indicate that an error occurred during printing, and test for error.  */
@@ -3749,6 +3789,7 @@ cplus_demangle_print_callback (int options,
demangle_callbackref callback, void *opaque)
 {
   struct d_print_info dpi;
+  int success;
 
   d_print_init (dpi, callback, opaque);
 
@@ -3756,7 +3797,9 @@ cplus_demangle_print_callback (int options,
 
   d_print_flush (dpi);
 
-  return ! d_print_saw_error (dpi);
+  success = ! d_print_saw_error (dpi);
+  d_print_free (dpi);
+  return success;
 }
 
 /* Turn components into a human readable string.  OPTIONS is the
@@ -3913,6 +3956,36 @@ d_print_subexpr (struct d_print_info *dpi, int options,
 d_append_char (dpi, ')');
 }
 
+/* Return a shallow copy of the current list of templates.
+   On error d_print_error is called and a partial list may
+   be returned.  Whatever is returned must be freed.  */
+
+static struct d_print_template *
+d_copy_templates (struct 

[C++ PATCH] demangler fix (take 2)

2013-09-17 Thread Gary Benson
Hi all,

This is a resubmission of my previous demangler fix [1] rewritten
to avoid using hashtables and other libiberty features.

From the above referenced email:

d_print_comp maintains a certain amount of scope across calls (namely
a stack of templates) which is used when evaluating references in
template argument lists.  If such a reference is later used from a
subtitution then the scope in force at the time of the substitution is
used.  This appears to be wrong (I say appears because I couldn't find
anything in the API [2] to clarify this).

The attached patch causes the demangler to capture the scope the first
time such a reference is traversed, and to use that captured scope on
subsequent traversals.  This fixes GDB PR 14963 [3] whereby a
reference is resolved against the wrong template, causing an infinite
loop and eventual stack overflow and segmentation fault.

I've added the result to the demangler test suite, but I know of no
way to check the validity of the demangled symbol other than by
inspection (and I am no expert here!)  If anybody knows a way to
check this then please let me know!  Otherwise, I hope this
not-really-checked demangled version is acceptable.

Thanks,
Gary

[1] http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00215.html
[2] http://mentorembedded.github.io/cxx-abi/abi.html#mangling
[3] http://sourceware.org/bugzilla/show_bug.cgi?id=14963

-- 
http://gbenson.net/
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 89e108a..2ff8216 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,20 @@
+2013-09-17  Gary Benson  gben...@redhat.com
+
+   * cp-demangle.c (struct d_saved_scope): New structure.
+   (struct d_print_info): New fields saved_scopes and
+   num_saved_scopes.
+   (d_print_init): Initialize the above.
+   (d_print_free): New function.
+   (cplus_demangle_print_callback): Call the above.
+   (d_copy_templates): New function.
+   (d_print_comp): New variables saved_templates and
+   need_template_restore.
+   [DEMANGLE_COMPONENT_REFERENCE,
+   DEMANGLE_COMPONENT_RVALUE_REFERENCE]: Capture scope the first
+   time the component is traversed, and use the captured scope for
+   subsequent traversals.
+   * testsuite/demangle-expected: Add regression test.
+
 2013-09-10  Paolo Carlini  paolo.carl...@oracle.com
 
PR bootstrap/58386
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 70f5438..a199f6d 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -275,6 +275,18 @@ struct d_growable_string
   int allocation_failure;
 };
 
+/* A demangle component and some scope captured when it was first
+   traversed.  */
+
+struct d_saved_scope
+{
+  /* The component whose scope this is.  */
+  const struct demangle_component *container;
+  /* The list of templates, if any, that was current when this
+ scope was captured.  */
+  struct d_print_template *templates;
+};
+
 enum { D_PRINT_BUFFER_LENGTH = 256 };
 struct d_print_info
 {
@@ -302,6 +314,10 @@ struct d_print_info
   int pack_index;
   /* Number of d_print_flush calls so far.  */
   unsigned long int flush_count;
+  /* Array of saved scopes for evaluating substitutions.  */
+  struct d_saved_scope *saved_scopes;
+  /* Number of saved scopes in the above array.  */
+  int num_saved_scopes;
 };
 
 #ifdef CP_DEMANGLE_DEBUG
@@ -3665,6 +3681,30 @@ d_print_init (struct d_print_info *dpi, 
demangle_callbackref callback,
   dpi-opaque = opaque;
 
   dpi-demangle_failure = 0;
+
+  dpi-saved_scopes = NULL;
+  dpi-num_saved_scopes = 0;
+}
+
+/* Free a print information structure.  */
+
+static void
+d_print_free (struct d_print_info *dpi)
+{
+  int i;
+
+  for (i = 0; i  dpi-num_saved_scopes; i++)
+{
+  struct d_print_template *ts, *tn;
+
+  for (ts = dpi-saved_scopes[i].templates; ts != NULL; ts = tn)
+   {
+ tn = ts-next;
+ free (ts);
+   }
+}
+
+  free (dpi-saved_scopes);
 }
 
 /* Indicate that an error occurred during printing, and test for error.  */
@@ -3749,6 +3789,7 @@ cplus_demangle_print_callback (int options,
demangle_callbackref callback, void *opaque)
 {
   struct d_print_info dpi;
+  int success;
 
   d_print_init (dpi, callback, opaque);
 
@@ -3756,7 +3797,9 @@ cplus_demangle_print_callback (int options,
 
   d_print_flush (dpi);
 
-  return ! d_print_saw_error (dpi);
+  success = ! d_print_saw_error (dpi);
+  d_print_free (dpi);
+  return success;
 }
 
 /* Turn components into a human readable string.  OPTIONS is the
@@ -3913,6 +3956,36 @@ d_print_subexpr (struct d_print_info *dpi, int options,
 d_append_char (dpi, ')');
 }
 
+/* Return a shallow copy of the current list of templates.
+   On error d_print_error is called and a partial list may
+   be returned.  Whatever is returned must be freed.  */
+
+static struct d_print_template *
+d_copy_templates (struct d_print_info *dpi)
+{
+  struct d_print_template *src, *result,