Add a recursion limit to libiberty's demangling code. The limit is enabled by defaul...
authorNick Clifton <nickc@redhat.com>
Fri, 7 Dec 2018 10:33:30 +0000 (10:33 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Fri, 7 Dec 2018 10:33:30 +0000 (10:33 +0000)
include * demangle.h (DMGL_NO_RECURSE_LIMIT): Define.
        (DEMANGLE_RECURSION_LIMIT): Define

PR 87681
PR 87675
PR 87636
PR 87350
PR 87335
libiberty * cp-demangle.h (struct d_info): Add recursion_level field.
* cp-demangle.c (d_function_type): Add recursion counter.
If the recursion limit is reached and the check is not disabled,
then return with a failure result.
(cplus_demangle_init_info): Initialise the recursion_level field.
        (d_demangle_callback): If the recursion limit is enabled, check
for a mangled string that is so long that there is not enough
stack space for the local arrays.
        * cplus-dem.c (struct work): Add recursion_level field.
(squangle_mop_up): Set the numb and numk fields to zero.
(work_stuff_copy_to_from): Handle the case where a btypevec or
ktypevec field is NULL.
(demangle_nested_args): Add recursion counter.  If
the recursion limit is not disabled and reached, return with a
failure result.

From-SVN: r266886

include/ChangeLog
include/demangle.h
libiberty/ChangeLog
libiberty/cp-demangle.c
libiberty/cp-demangle.h
libiberty/cplus-dem.c

index d52f998b9b2a751d0d408458d8d0851e995d0cf5..c26ddf4b4e33e5cbc917fc393dce1600ad72de4b 100644 (file)
@@ -1,3 +1,8 @@
+2018-12-07  Nick Clifton  <nickc@redhat.com>
+
+       * demangle.h (DMGL_NO_RECURSE_LIMIT): Define.
+        (DEMANGLE_RECURSION_LIMIT): Define
+
 2018-11-08  Jakub Jelinek  <jakub@redhat.com>
 
        * gomp-constants.h (GOMP_TASK_FLAG_REDUCTION,
index 4f920f2b7f597d4e952c27c4647086e13aea77fa..1e67fe2fb349da386abc6cf6264617339854f8db 100644 (file)
@@ -68,6 +68,17 @@ extern "C" {
 /* If none of these are set, use 'current_demangling_style' as the default. */
 #define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST)
 
+/* Disable a limit on the depth of recursion in mangled strings.
+   Note if this limit is disabled then stack exhaustion is possible when
+   demangling pathologically complicated strings.  Bug reports about stack
+   exhaustion when the option is enabled will be rejected.  */  
+#define DMGL_NO_RECURSE_LIMIT (1 << 18)        
+
+/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as
+   the maximum depth of recursion allowed.  It should be enough for any
+   real-world mangled name.  */
+#define DEMANGLE_RECURSION_LIMIT 1024
+  
 /* Enumeration of possible demangling styles.
 
    Lucid and ARM styles are still kept logically distinct, even though
index 91211c87e7ddca3c458a625619904b2616ba5cbe..5772008976ed59ed08cd5a58330686df00dcd8a7 100644 (file)
@@ -1,3 +1,26 @@
+2018-12-07  Nick Clifton  <nickc@redhat.com>
+
+       PR 87681
+       PR 87675
+       PR 87636
+       PR 87350
+       PR 87335
+       * cp-demangle.h (struct d_info): Add recursion_level field.
+       * cp-demangle.c (d_function_type): Add recursion counter.
+       If the recursion limit is reached and the check is not disabled,
+       then return with a failure result.
+       (cplus_demangle_init_info): Initialise the recursion_level field.
+        (d_demangle_callback): If the recursion limit is enabled, check
+       for a mangled string that is so long that there is not enough
+       stack space for the local arrays.
+        * cplus-dem.c (struct work): Add recursion_level field.
+       (squangle_mop_up): Set the numb and numk fields to zero.
+       (work_stuff_copy_to_from): Handle the case where a btypevec or
+       ktypevec field is NULL.
+       (demangle_nested_args): Add recursion counter.  If
+       the recursion limit is not disabled and reached, return with a
+       failure result.
+
 2018-10-23  Jason Merrill  <jason@redhat.com>
 
        Implement P0732R2, class types in non-type template parameters.
index a1f74a51c9c8aa2e8801c5a30b606dc68e054887..47bbc947f143d132c29ec71c5676ccfa4bdf6ff5 100644 (file)
@@ -2852,21 +2852,35 @@ d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
 static struct demangle_component *
 d_function_type (struct d_info *di)
 {
-  struct demangle_component *ret;
+  struct demangle_component *ret = NULL;
 
-  if (! d_check_char (di, 'F'))
-    return NULL;
-  if (d_peek_char (di) == 'Y')
+  if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0)
     {
-      /* Function has C linkage.  We don't print this information.
-        FIXME: We should print it in verbose mode.  */
-      d_advance (di, 1);
+      if (di->recursion_level > DEMANGLE_RECURSION_LIMIT)
+       /* FIXME: There ought to be a way to report
+          that the recursion limit has been reached.  */
+       return NULL;
+
+      di->recursion_level ++;
     }
-  ret = d_bare_function_type (di, 1);
-  ret = d_ref_qualifier (di, ret);
 
-  if (! d_check_char (di, 'E'))
-    return NULL;
+  if (d_check_char (di, 'F'))
+    {
+      if (d_peek_char (di) == 'Y')
+       {
+         /* Function has C linkage.  We don't print this information.
+            FIXME: We should print it in verbose mode.  */
+         d_advance (di, 1);
+       }
+      ret = d_bare_function_type (di, 1);
+      ret = d_ref_qualifier (di, ret);
+      
+      if (! d_check_char (di, 'E'))
+       ret = NULL;
+    }
+
+  if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0)
+    di->recursion_level --;
   return ret;
 }
 
@@ -6203,6 +6217,7 @@ cplus_demangle_init_info (const char *mangled, int options, size_t len,
   di->expansion = 0;
   di->is_expression = 0;
   di->is_conversion = 0;
+  di->recursion_level = 0;
 }
 
 /* Internal implementation for the demangler.  If MANGLED is a g++ v3 ABI
@@ -6242,6 +6257,20 @@ d_demangle_callback (const char *mangled, int options,
 
   cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
 
+  /* PR 87675 - Check for a mangled string that is so long
+     that we do not have enough stack space to demangle it.  */
+  if (((options & DMGL_NO_RECURSE_LIMIT) == 0)
+      /* This check is a bit arbitrary, since what we really want to do is to
+        compare the sizes of the di.comps and di.subs arrays against the
+        amount of stack space remaining.  But there is no portable way to do
+        this, so instead we use the recursion limit as a guide to the maximum
+        size of the arrays.  */
+      && (unsigned long) di.num_comps > DEMANGLE_RECURSION_LIMIT)
+    {
+      /* FIXME: We need a way to indicate that a stack limit has been reached.  */
+      return 0;
+    }
+
   {
 #ifdef CP_DYNAMIC_ARRAYS
     __extension__ struct demangle_component comps[di.num_comps];
index 51b8a243e0ea303c4c477a7d3d2e052f9de8ea11..d87a830bb3155c87a1b91d36c87fcd33173d331f 100644 (file)
@@ -122,6 +122,9 @@ struct d_info
   /* Non-zero if we are parsing the type operand of a conversion
      operator, but not when in an expression.  */
   int is_conversion;
+  /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
+     the current recursion level.  */
+  unsigned int recursion_level;
 };
 
 /* To avoid running past the ending '\0', don't:
index 4f29d54d089783e137c4dfb77d2e8631ad5d0b6a..48c0cfd848a081220d7cf4422eb2e6f4bf4ed89d 100644 (file)
@@ -146,6 +146,7 @@ struct work_stuff
   int *proctypevec;     /* Indices of currently processed remembered typevecs.  */
   int proctypevec_size;
   int nproctypes;
+  unsigned int recursion_level;
 };
 
 #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -1292,12 +1293,14 @@ squangle_mop_up (struct work_stuff *work)
       free ((char *) work -> btypevec);
       work->btypevec = NULL;
       work->bsize = 0;
+      work->numb = 0;
     }
   if (work -> ktypevec != NULL)
     {
       free ((char *) work -> ktypevec);
       work->ktypevec = NULL;
       work->ksize = 0;
+      work->numk = 0;
     }
 }
 
@@ -1331,8 +1334,15 @@ work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
 
   for (i = 0; i < from->numk; i++)
     {
-      int len = strlen (from->ktypevec[i]) + 1;
+      int len;
+
+      if (from->ktypevec[i] == NULL)
+       {
+         to->ktypevec[i] = NULL;
+         continue;
+       }
 
+      len = strlen (from->ktypevec[i]) + 1;
       to->ktypevec[i] = XNEWVEC (char, len);
       memcpy (to->ktypevec[i], from->ktypevec[i], len);
     }
@@ -1342,8 +1352,15 @@ work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
 
   for (i = 0; i < from->numb; i++)
     {
-      int len = strlen (from->btypevec[i]) + 1;
+      int len;
+
+      if (from->btypevec[i] == NULL)
+       {
+         to->btypevec[i] = NULL;
+         continue;
+       }
 
+      len = strlen (from->btypevec[i]) + 1;
       to->btypevec[i] = XNEWVEC (char , len);
       memcpy (to->btypevec[i], from->btypevec[i], len);
     }
@@ -1401,6 +1418,7 @@ delete_non_B_K_work_stuff (struct work_stuff *work)
 
       free ((char*) work->tmpl_argvec);
       work->tmpl_argvec = NULL;
+      work->ntmpl_args = 0;
     }
   if (work->previous_argument)
     {
@@ -4478,6 +4496,7 @@ remember_Btype (struct work_stuff *work, const char *start,
 }
 
 /* Lose all the info related to B and K type codes. */
+
 static void
 forget_B_and_K_types (struct work_stuff *work)
 {
@@ -4503,6 +4522,7 @@ forget_B_and_K_types (struct work_stuff *work)
        }
     }
 }
+
 /* Forget the remembered types, but not the type vector itself.  */
 
 static void
@@ -4697,6 +4717,16 @@ demangle_nested_args (struct work_stuff *work, const char **mangled,
   int result;
   int saved_nrepeats;
 
+  if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0)
+    {
+      if (work->recursion_level > DEMANGLE_RECURSION_LIMIT)
+       /* FIXME: There ought to be a way to report
+          that the recursion limit has been reached.  */
+       return 0;
+
+      work->recursion_level ++;
+    }
+
   /* The G++ name-mangling algorithm does not remember types on nested
      argument lists, unless -fsquangling is used, and in that case the
      type vector updated by remember_type is not used.  So, we turn
@@ -4723,6 +4753,9 @@ demangle_nested_args (struct work_stuff *work, const char **mangled,
   --work->forgetting_types;
   work->nrepeats = saved_nrepeats;
 
+  if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0)
+    --work->recursion_level;
+
   return result;
 }