Hi Jeff,

> Can you take care of the minor issues above, retest & repost?

Sure. I removed the whitespace nits, used XDUPVEC instead of XNEWVEC+memcpy, 
and adjusted the growing heuristics of the new array proctypevec. The revised 
patch is attached below. Bootstrapped and regression tested on 
x86_64-pc-linux-gnu and checked PR71696 is resolved.

>> +           for (i = 0; i < work -> nproctypes; i++)
>> +             if (work -> proctypevec [i] == n)
>> +               success = 0;
> So presumably this doesn't happen all that often or this could get expensive
> and we'd want something more efficient for searching, right?

It seems, at least for the cases in the Demangler test suite, the loop executes 
never more than one iteration.

Index: libiberty/ChangeLog
===================================================================
--- libiberty/ChangeLog (revision 239112)
+++ libiberty/ChangeLog (working copy)
@@ -1,3 +1,20 @@
+2016-08-04  Marcel Böhme  <boehme.mar...@gmail.com>
+
+       PR c++/71696
+       * cplus-dem.c: Prevent infinite recursion when there is a cycle
+       in the referencing of remembered mangled types.
+       (work_stuff): New stack to keep track of the remembered mangled
+       types that are currently being processed.
+       (push_processed_type): New method to push currently processed
+       remembered type onto the stack.
+       (pop_processed_type): New method to pop currently processed
+       remembered type from the stack.
+       (work_stuff_copy_to_from): Copy values of new variables.
+       (delete_non_B_K_work_stuff): Free stack memory.
+       (demangle_args): Push/Pop currently processed remembered type.
+       (do_type): Do not demangle a cyclic reference and push/pop
+       referenced remembered type.
+
 2016-07-29  Aldy Hernandez  <al...@redhat.com>
 
        * make-relative-prefix.c (make_relative_prefix_1): Fall back to
@@ -16,7 +33,7 @@
        (d_template_args_1): Split out from d_template_args.
        (d_args_length): New.
 
-2016-07-13  Marcel BÃhme  <boehme.mar...@gmail.com>
+2016-07-13  Marcel Böhme  <boehme.mar...@gmail.com>
 
        PR c++/70926
        * cplus-dem.c: Handle large values and overflow when demangling
Index: libiberty/cplus-dem.c
===================================================================
--- libiberty/cplus-dem.c       (revision 239112)
+++ libiberty/cplus-dem.c       (working copy)
@@ -144,6 +144,9 @@ struct work_stuff
   string* previous_argument; /* The last function argument demangled.  */
   int nrepeats;         /* The number of times to repeat the previous
                           argument.  */
+  int *proctypevec;     /* Indices of currently processed remembered typevecs. 
 */
+  int proctypevec_size;
+  int nproctypes;
 };
 
 #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -436,6 +439,10 @@ iterate_demangle_function (struct work_stuff *,
 
 static void remember_type (struct work_stuff *, const char *, int);
 
+static void push_processed_type (struct work_stuff *, int);
+
+static void pop_processed_type (struct work_stuff *);
+
 static void remember_Btype (struct work_stuff *, const char *, int, int);
 
 static int register_Btype (struct work_stuff *);
@@ -1302,6 +1309,10 @@ work_stuff_copy_to_from (struct work_stuff *to, st
       memcpy (to->btypevec[i], from->btypevec[i], len);
     }
 
+  if (from->proctypevec)
+    to->proctypevec =
+      XDUPVEC (int, from->proctypevec, from->proctypevec_size);
+
   if (from->ntmpl_args)
     to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args);
 
@@ -1330,12 +1341,18 @@ delete_non_B_K_work_stuff (struct work_stuff *work
   /* Discard the remembered types, if any.  */
 
   forget_types (work);
-  if (work -> typevec != NULL)
+  if (work->typevec != NULL)
     {
-      free ((char *) work -> typevec);
-      work -> typevec = NULL;
-      work -> typevec_size = 0;
+      free ((char *) work->typevec);
+      work->typevec = NULL;
+      work->typevec_size = 0;
     }
+  if (work->proctypevec != NULL)
+    {
+      free (work->proctypevec);
+      work->proctypevec = NULL;
+      work->proctypevec_size = 0;
+    }
   if (work->tmpl_argvec)
     {
       int i;
@@ -3555,6 +3572,8 @@ static int
 do_type (struct work_stuff *work, const char **mangled, string *result)
 {
   int n;
+  int i;
+  int is_proctypevec;
   int done;
   int success;
   string decl;
@@ -3567,6 +3586,7 @@ do_type (struct work_stuff *work, const char **man
 
   done = 0;
   success = 1;
+  is_proctypevec = 0;
   while (success && !done)
     {
       int member;
@@ -3627,8 +3647,15 @@ do_type (struct work_stuff *work, const char **man
              success = 0;
            }
          else
-           {
-             remembered_type = work -> typevec[n];
+           for (i = 0; i < work->nproctypes; i++)
+             if (work -> proctypevec [i] == n)
+               success = 0;
+
+         if (success)
+           {    
+             is_proctypevec = 1;
+             push_processed_type (work, n);
+             remembered_type = work->typevec[n];
              mangled = &remembered_type;
            }
          break;
@@ -3850,6 +3877,9 @@ do_type (struct work_stuff *work, const char **man
     string_delete (result);
   string_delete (&decl);
 
+  if (is_proctypevec)
+    pop_processed_type (work); 
+
   if (success)
     /* Assume an integral type, if we're not sure.  */
     return (int) ((tk == tk_none) ? tk_integral : tk);
@@ -4263,6 +4293,41 @@ do_arg (struct work_stuff *work, const char **mang
 }
 
 static void
+push_processed_type (struct work_stuff *work, int typevec_index)
+{
+  if (work->nproctypes >= work->proctypevec_size)
+    {
+      if (!work->proctypevec_size)
+       {
+         work->proctypevec_size = 4;
+         work->proctypevec = XNEWVEC (int, work->proctypevec_size);
+       }
+      else 
+       {
+         if (work->proctypevec_size < 16)
+           /* Double when small.  */
+           work->proctypevec_size *= 2;
+         else
+           {
+             /* Grow slower when large.  */
+             if (work->proctypevec_size > (INT_MAX / 3) * 2)
+                xmalloc_failed (INT_MAX);
+              work->proctypevec_size = (work->proctypevec_size * 3 / 2);
+           }   
+          work->proctypevec
+            = XRESIZEVEC (int, work->proctypevec, work->proctypevec_size);
+       }
+    }
+    work->proctypevec [work->nproctypes++] = typevec_index;
+}
+
+static void
+pop_processed_type (struct work_stuff *work)
+{
+  work->nproctypes--;
+}
+
+static void
 remember_type (struct work_stuff *work, const char *start, int len)
 {
   char *tem;
@@ -4526,10 +4591,13 @@ demangle_args (struct work_stuff *work, const char
                {
                  string_append (declp, ", ");
                }
+             push_processed_type (work, t);  
              if (!do_arg (work, &tem, &arg))
                {
+                 pop_processed_type (work);
                  return (0);
                }
+             pop_processed_type (work);
              if (PRINT_ARG_TYPES)
                {
                  string_appends (declp, &arg);
Index: libiberty/testsuite/demangle-expected
===================================================================
--- libiberty/testsuite/demangle-expected       (revision 239112)
+++ libiberty/testsuite/demangle-expected       (working copy)
@@ -4587,3 +4587,8 @@ _Z80800000000000000000000
 
 __t2m05B500000000000000000_
 __t2m05B500000000000000000_
+#
+# Tests stack overflow PR71696
+
+__10%0__S4_0T0T0
+%0<>::%0(%0<>)


Index: libiberty/ChangeLog
===================================================================
--- libiberty/ChangeLog (revision 239112)
+++ libiberty/ChangeLog (working copy)
@@ -1,3 +1,20 @@
+2016-08-04  Marcel Böhme  <boehme.mar...@gmail.com>
+
+       PR c++/71696
+       * cplus-dem.c: Prevent infinite recursion when there is a cycle
+       in the referencing of remembered mangled types.
+       (work_stuff): New stack to keep track of the remembered mangled
+       types that are currently being processed.
+       (push_processed_type): New method to push currently processed
+       remembered type onto the stack.
+       (pop_processed_type): New method to pop currently processed
+       remembered type from the stack.
+       (work_stuff_copy_to_from): Copy values of new variables.
+       (delete_non_B_K_work_stuff): Free stack memory.
+       (demangle_args): Push/Pop currently processed remembered type.
+       (do_type): Do not demangle a cyclic reference and push/pop
+       referenced remembered type.
+
 2016-07-29  Aldy Hernandez  <al...@redhat.com>
 
        * make-relative-prefix.c (make_relative_prefix_1): Fall back to
@@ -16,7 +33,7 @@
        (d_template_args_1): Split out from d_template_args.
        (d_args_length): New.
 
-2016-07-13  Marcel BÃhme  <boehme.mar...@gmail.com>
+2016-07-13  Marcel Böhme  <boehme.mar...@gmail.com>
 
        PR c++/70926
        * cplus-dem.c: Handle large values and overflow when demangling
Index: libiberty/cplus-dem.c
===================================================================
--- libiberty/cplus-dem.c       (revision 239112)
+++ libiberty/cplus-dem.c       (working copy)
@@ -144,6 +144,9 @@ struct work_stuff
   string* previous_argument; /* The last function argument demangled.  */
   int nrepeats;         /* The number of times to repeat the previous
                           argument.  */
+  int *proctypevec;     /* Indices of currently processed remembered typevecs. 
 */
+  int proctypevec_size;
+  int nproctypes;
 };
 
 #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -436,6 +439,10 @@ iterate_demangle_function (struct work_stuff *,
 
 static void remember_type (struct work_stuff *, const char *, int);
 
+static void push_processed_type (struct work_stuff *, int);
+
+static void pop_processed_type (struct work_stuff *);
+
 static void remember_Btype (struct work_stuff *, const char *, int, int);
 
 static int register_Btype (struct work_stuff *);
@@ -1302,6 +1309,10 @@ work_stuff_copy_to_from (struct work_stuff *to, st
       memcpy (to->btypevec[i], from->btypevec[i], len);
     }
 
+  if (from->proctypevec)
+    to->proctypevec =
+      XDUPVEC (int, from->proctypevec, from->proctypevec_size);
+
   if (from->ntmpl_args)
     to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args);
 
@@ -1330,12 +1341,18 @@ delete_non_B_K_work_stuff (struct work_stuff *work
   /* Discard the remembered types, if any.  */
 
   forget_types (work);
-  if (work -> typevec != NULL)
+  if (work->typevec != NULL)
     {
-      free ((char *) work -> typevec);
-      work -> typevec = NULL;
-      work -> typevec_size = 0;
+      free ((char *) work->typevec);
+      work->typevec = NULL;
+      work->typevec_size = 0;
     }
+  if (work->proctypevec != NULL)
+    {
+      free (work->proctypevec);
+      work->proctypevec = NULL;
+      work->proctypevec_size = 0;
+    }
   if (work->tmpl_argvec)
     {
       int i;
@@ -3555,6 +3572,8 @@ static int
 do_type (struct work_stuff *work, const char **mangled, string *result)
 {
   int n;
+  int i;
+  int is_proctypevec;
   int done;
   int success;
   string decl;
@@ -3567,6 +3586,7 @@ do_type (struct work_stuff *work, const char **man
 
   done = 0;
   success = 1;
+  is_proctypevec = 0;
   while (success && !done)
     {
       int member;
@@ -3627,8 +3647,15 @@ do_type (struct work_stuff *work, const char **man
              success = 0;
            }
          else
-           {
-             remembered_type = work -> typevec[n];
+           for (i = 0; i < work->nproctypes; i++)
+             if (work -> proctypevec [i] == n)
+               success = 0;
+
+         if (success)
+           {    
+             is_proctypevec = 1;
+             push_processed_type (work, n);
+             remembered_type = work->typevec[n];
              mangled = &remembered_type;
            }
          break;
@@ -3850,6 +3877,9 @@ do_type (struct work_stuff *work, const char **man
     string_delete (result);
   string_delete (&decl);
 
+  if (is_proctypevec)
+    pop_processed_type (work); 
+
   if (success)
     /* Assume an integral type, if we're not sure.  */
     return (int) ((tk == tk_none) ? tk_integral : tk);
@@ -4263,6 +4293,41 @@ do_arg (struct work_stuff *work, const char **mang
 }
 
 static void
+push_processed_type (struct work_stuff *work, int typevec_index)
+{
+  if (work->nproctypes >= work->proctypevec_size)
+    {
+      if (!work->proctypevec_size)
+       {
+         work->proctypevec_size = 4;
+         work->proctypevec = XNEWVEC (int, work->proctypevec_size);
+       }
+      else 
+       {
+         if (work->proctypevec_size < 16)
+           /* Double when small.  */
+           work->proctypevec_size *= 2;
+         else
+           {
+             /* Grow slower when large.  */
+             if (work->proctypevec_size > (INT_MAX / 3) * 2)
+                xmalloc_failed (INT_MAX);
+              work->proctypevec_size = (work->proctypevec_size * 3 / 2);
+           }   
+          work->proctypevec
+            = XRESIZEVEC (int, work->proctypevec, work->proctypevec_size);
+       }
+    }
+    work->proctypevec [work->nproctypes++] = typevec_index;
+}
+
+static void
+pop_processed_type (struct work_stuff *work)
+{
+  work->nproctypes--;
+}
+
+static void
 remember_type (struct work_stuff *work, const char *start, int len)
 {
   char *tem;
@@ -4526,10 +4591,13 @@ demangle_args (struct work_stuff *work, const char
                {
                  string_append (declp, ", ");
                }
+             push_processed_type (work, t);  
              if (!do_arg (work, &tem, &arg))
                {
+                 pop_processed_type (work);
                  return (0);
                }
+             pop_processed_type (work);
              if (PRINT_ARG_TYPES)
                {
                  string_appends (declp, &arg);
Index: libiberty/testsuite/demangle-expected
===================================================================
--- libiberty/testsuite/demangle-expected       (revision 239112)
+++ libiberty/testsuite/demangle-expected       (working copy)
@@ -4587,3 +4587,8 @@ _Z80800000000000000000000
 
 __t2m05B500000000000000000_
 __t2m05B500000000000000000_
+#
+# Tests stack overflow PR71696
+
+__10%0__S4_0T0T0
+%0<>::%0(%0<>)


Reply via email to