From: jerrywang1201 <[email protected]>

PR demangler/123988 shows that __cxa_demangle can fail for long but
valid names.  The callback-based demangler still needs the recursion-
limit guard because it puts its temporary component arrays on the
stack, but d_demangle prints into an allocated string and does not need
to fail for that reason.

Parse d_demangle input using heap-backed comps/subs arrays instead of
reusing the stack-sensitive callback path.  Keep the callback-only path
unchanged, and add a libstdc++ regression test using the long
Type<std::type_identity<...>>::bar() name from PR123988.
---
 libiberty/cp-demangle.c                       | 144 ++++++++++++++----
 .../abi/demangle/regression/123988.cc         |  55 +++++++
 2 files changed, 167 insertions(+), 32 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/abi/demangle/regression/123988.cc

diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 5e6571d419b..13484e03d56 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -6839,18 +6839,20 @@ cplus_demangle_init_info (const char *mangled, int 
options, size_t len,
    name.  OPTIONS is the usual libiberty demangler options.  On success,
    this returns 1.  On failure, returns 0.  */
 
+enum d_demangle_top_level_type
+  {
+    DCT_INVALID,
+    DCT_MANGLED,
+    DCT_GLOBAL_CTORS,
+    DCT_GLOBAL_DTORS,
+    DCT_TYPE
+  };
+
 static int
 d_demangle_callback (const char *mangled, int options,
-                     demangle_callbackref callback, void *opaque)
+                    demangle_callbackref callback, void *opaque)
 {
-  enum
-    {
-      DCT_TYPE,
-      DCT_MANGLED,
-      DCT_GLOBAL_CTORS,
-      DCT_GLOBAL_DTORS
-    }
-  type;
+  enum d_demangle_top_level_type type;
   struct d_info di;
   struct demangle_component *dc;
   int status;
@@ -6874,25 +6876,26 @@ d_demangle_callback (const char *mangled, int options,
  again:
   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];
     __extension__ struct demangle_component *subs[di.num_subs];
 
+    /* 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;
+      }
+
     di.comps = comps;
     di.subs = subs;
 #else
@@ -6959,22 +6962,99 @@ d_demangle_callback (const char *mangled, int options,
 static char *
 d_demangle (const char *mangled, int options, size_t *palc)
 {
-  struct d_growable_string dgs;
-  int status;
+  enum d_demangle_top_level_type type;
+  struct d_info di;
+  struct demangle_component *dc;
+  struct demangle_component *comps;
+  struct demangle_component **subs;
+  char *demangled;
+
+  if (mangled[0] == '_' && mangled[1] == 'Z')
+    type = DCT_MANGLED;
+  else if (strncmp (mangled, "_GLOBAL_", 8) == 0
+          && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$')
+          && (mangled[9] == 'D' || mangled[9] == 'I')
+          && mangled[10] == '_')
+    type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS;
+  else
+    {
+      if ((options & DMGL_TYPES) == 0)
+       {
+         *palc = 0;
+         return NULL;
+       }
+      type = DCT_TYPE;
+    }
 
-  d_growable_string_init (&dgs, 0);
+  cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
 
-  status = d_demangle_callback (mangled, options,
-                                d_growable_string_callback_adapter, &dgs);
-  if (status == 0)
+  comps = ((struct demangle_component *)
+          malloc (di.num_comps * sizeof (*comps)));
+  subs = ((struct demangle_component **)
+         malloc (di.num_subs * sizeof (*subs)));
+  if (comps == NULL || subs == NULL)
     {
-      free (dgs.buf);
+      free (comps);
+      free (subs);
+      *palc = 1;
+      return NULL;
+    }
+
+  di.unresolved_name_state = 1;
+
+ again:
+  cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
+  di.comps = comps;
+  di.subs = subs;
+
+  switch (type)
+    {
+    case DCT_TYPE:
+      dc = cplus_demangle_type (&di);
+      break;
+    case DCT_MANGLED:
+      dc = cplus_demangle_mangled_name (&di, 1);
+      break;
+    case DCT_GLOBAL_CTORS:
+    case DCT_GLOBAL_DTORS:
+      d_advance (&di, 11);
+      dc = d_make_comp (&di,
+                       (type == DCT_GLOBAL_CTORS
+                        ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
+                        : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
+                       d_make_demangle_mangled_name (&di, d_str (&di)),
+                       NULL);
+      d_advance (&di, strlen (d_str (&di)));
+      break;
+    default:
+      abort (); /* We have listed all the cases.  */
+    }
+
+  if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
+    dc = NULL;
+
+  if (dc == NULL && di.unresolved_name_state == -1)
+    {
+      di.unresolved_name_state = 0;
+      goto again;
+    }
+
+  if (dc == NULL)
+    {
+      free (subs);
+      free (comps);
       *palc = 0;
       return NULL;
     }
 
-  *palc = dgs.allocation_failure ? 1 : dgs.alc;
-  return dgs.buf;
+#ifdef CP_DEMANGLE_DEBUG
+  d_dump (dc, 0);
+#endif
+
+  demangled = cplus_demangle_print (options, dc, 0, palc);
+  free (subs);
+  free (comps);
+  return demangled;
 }
 
 #if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
diff --git a/libstdc++-v3/testsuite/abi/demangle/regression/123988.cc 
b/libstdc++-v3/testsuite/abi/demangle/regression/123988.cc
new file mode 100644
index 00000000000..3eedf103e93
--- /dev/null
+++ b/libstdc++-v3/testsuite/abi/demangle/regression/123988.cc
@@ -0,0 +1,55 @@
+// { dg-do run }
+
+// Copyright (C) 2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+#include <string>
+#include <testsuite_hooks.h>
+
+static std::string
+expected_name (int depth)
+{
+  std::string name("Type<");
+
+  for (int i = 0; i < depth; ++i)
+    name += "std::type_identity<";
+
+  name += "void>";
+
+  for (int i = 0; i < depth; ++i)
+    name += " >";
+
+  name += "::bar()";
+  return name;
+}
+
+// demangler/123988
+int main()
+{
+  using namespace __gnu_test;
+
+  const char longer[] = 
"_ZN4TypeISt13type_identityIS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS0_IS"
+    "0_IS0_IS0_IS0_IS0_IS0_IS0_IvEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
+    "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
+    "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
+    "EEEEEEEEEEEE3barEv";
+
+  const std::string longer_expected = expected_name(199);
+
+  verify_demangle(longer, longer_expected.c_str());
+}
-- 
2.51.0

Reply via email to