Hi everyone!
Thanks Caroline and Jason for your time!

This patch was approved by Caroline Tice, the maintainer of VTV.
https://gcc.gnu.org/pipermail/gcc-patches/2026-September/730139.html

Improvements were suggested by Jason Merill, and this v3 patch is a response.
https://gcc.gnu.org/pipermail/gcc-patches/2026-September/730609.html

Successfully rebootstrapped with "--enable-vtable-verify".
Have a great evening,

Léo

-- 8< --

vtv: Fix Memory Leak and Other Improvements

Currently, vtable_find_or_create_map_decl, given a class decl,
calls get_mangled_vtable_map_var_name (from mangle.cc) to:

  (1) create a VTV map entry for the given class; and
  (2) return the expected DECL_ASSEMBLER_NAME of its VTV tracker.

Here are some improvements for that logic:

a. (2) was only needed once for each class, and in that case, we
call get_identifier (var_name). Now we only generate the identifier
iff it is needed.

b. Since get_identifier copies data,var_name was always leaked.
This is now done without heap allocation.

c. get_identifier was called twice for the same symbol, which
costs an extra hash table lookup. Now we store it in a variable.

d. "vtable-class-hierarchy" and "mangle" depend on each other.
This is just because (1) is done inside mangle.cc. By moving that
statement to vtable-class-hierarchy, we avoid one extra circular
dependency.

The effect of vtable_find_or_create_map_decl has not changed.
Successfully (re)bootstrapped with "--enable-vtable-verify".

gcc/cp/ChangeLog:

        * cp-tree.h (get_mangled_vtable_map_var_name): Only get the
        name, without side effects.
        (get_mangled_type_name_if_anon): Split off from function above.
        * mangle.cc (get_mangled_type_name_if_anon): Only get the name,
        without side effects.
        (get_mangled_vtable_map_var_name): Split off from function
        above.
        * vtable-class-hierarchy.cc (vtable_find_or_create_map_decl):
        Fix a memory leak.

Signed-off-by: Léo Hardt <[email protected]>
---
 gcc/cp/cp-tree.h                 |  3 +-
 gcc/cp/mangle.cc                 | 53 ++++++++++++++++----------------
 gcc/cp/vtable-class-hierarchy.cc | 22 ++++++++-----
 3 files changed, 42 insertions(+), 36 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 05b0d2ac19f..328c2da138b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9190,7 +9190,8 @@ extern tree mangle_tls_wrapper_fn         (tree);
 extern bool decl_tls_wrapper_p                 (tree);
 extern tree mangle_ref_init_variable           (tree);
 extern tree mangle_template_parm_object                (tree);
-extern char *get_mangled_vtable_map_var_name    (tree);
+extern tree get_mangled_type_name_if_anon      (tree);
+extern tree get_mangled_vtable_map_var_name    (tree);
 extern bool mangle_return_type_p               (tree);
 extern tree mangle_decomp                      (tree, vec<tree> &);
 extern void mangle_module_substitution         (int);
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index b2697f27c32..53f605e48f3 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -48,7 +48,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "target.h"
-#include "vtable-verify.h"
 #include "cp-tree.h"
 #include "stringpool.h"
 #include "cgraph.h"
@@ -5416,41 +5415,41 @@ mangle_template_parm_object (tree expr)
   return finish_mangling_get_identifier ();
 }
 
-/* Given a CLASS_TYPE, such as a record for std::bad_exception this
-   function generates a mangled name for the vtable map variable of
-   the class type.  For example, if the class type is
-   "std::bad_exception", the mangled name for the class is
-   "St13bad_exception".  This function would generate the name
-   "_ZN4_VTVISt13bad_exceptionE12__vtable_mapE", which unmangles as:
-   "_VTV<std::bad_exception>::__vtable_map".  */
+/* Given a CLASS_TYPE, such as a record for std::bad_exception, this
+   function returns NULL_TREE if TYPE_NAME (CLASS_TYPE) is not from an
+   anonymous namespace.  Otherwise, returns the mangled type name.*/

+tree
+get_mangled_type_name_if_anon (tree class_type)
+ {
+  gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+  tree class_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+  bool is_anon = strstr (IDENTIFIER_POINTER (class_id), "<anon>") != NULL;
+  return is_anon ? get_mangled_id (TYPE_NAME (class_type)) : NULL_TREE;
+}

-char *
-get_mangled_vtable_map_var_name (tree class_type)
+/* Given CLASS_TYPE_ASSEMBLER_NAME, the DECL_ASSEMBLER_NAME of the
+   TYPE_NAME of a class, this function generates a mangled
+   identifier for the vtable map variable of the class type.
+   For example, if the class type is "std::bad_exception", the mangled
+   name for the class is "St13bad_exception".  This function would
+   generate the name "_ZN4_VTVISt13bad_exceptionE12__vtable_mapE",
+   which unmangles as "_VTV<std::bad_exception>::__vtable_map". */
+
+tree
+get_mangled_vtable_map_var_name (tree class_type_assembler_name)
 {
-  char *var_name = NULL;
   const char *prefix = "_ZN4_VTVI";
   const char *postfix = "E12__vtable_mapE";

-  gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
-
-  tree class_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
-
-  if (strstr (IDENTIFIER_POINTER (class_id), "<anon>") != NULL)
-    {
-      class_id = get_mangled_id (TYPE_NAME (class_type));
-      vtbl_register_mangled_name (TYPE_NAME (class_type), class_id);
-    }
-
-  unsigned int len = strlen (IDENTIFIER_POINTER (class_id)) +
-                     strlen (prefix) +
-                     strlen (postfix) + 1;
+  const char * class_name =
+    IDENTIFIER_POINTER (class_type_assembler_name);

-  var_name = (char *) xmalloc (len);
+  gcc_assert (strstr (class_name, "<anon>") == NULL);

- sprintf (var_name, "%s%s%s", prefix, IDENTIFIER_POINTER (class_id), postfix);
+  char *var_name = ACONCAT ((prefix, class_name, postfix, NULL));

-  return var_name;
+  return get_identifier (var_name);
 }

 #include "gt-cp-mangle.h"
diff --git a/gcc/cp/vtable-class-hierarchy.cc b/gcc/cp/vtable-class-hierarchy.cc
index 2e52ea3c4a0..e221652a394 100644
--- a/gcc/cp/vtable-class-hierarchy.cc
+++ b/gcc/cp/vtable-class-hierarchy.cc
@@ -1204,7 +1204,6 @@ vtv_generate_init_routine (void)
 struct vtbl_map_node *
 vtable_find_or_create_map_decl (tree base_type)
 {
-  char *var_name = NULL;
   struct vtbl_map_node *vtable_map_node = NULL;

   /* Verify the type has an associated vtable.  */
@@ -1212,7 +1211,15 @@ vtable_find_or_create_map_decl (tree base_type)
     return NULL;

   /* Create map lookup symbol for base class */
-  var_name = get_mangled_vtable_map_var_name (base_type);
+  tree base_type_name = DECL_ASSEMBLER_NAME (TYPE_NAME (base_type));
+  tree mangled_base_type_name = get_mangled_type_name_if_anon (base_type);
+
+  if (mangled_base_type_name != NULL_TREE)
+    {
+      vtbl_register_mangled_name
+       (TYPE_NAME (base_type), mangled_base_type_name);
+      base_type_name = mangled_base_type_name;
+    }

   /* We've already created the variable; just look it.  */
   vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_type));
@@ -1223,17 +1230,16 @@ vtable_find_or_create_map_decl (tree base_type)
          variable for this class, do so now, and add it to the
          varpool, to make sure it gets saved and written out.  */

-      tree var_decl = NULL;
+      tree var_name = get_mangled_vtable_map_var_name (base_type_name);
       tree var_type = build_pointer_type (void_type_node);
-      tree initial_value = integer_zero_node;

-      var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
-                              get_identifier (var_name), var_type);
+      tree var_decl =
+       build_decl (UNKNOWN_LOCATION, VAR_DECL, var_name, var_type);

       DECL_EXTERNAL (var_decl) = 0;
       TREE_STATIC (var_decl) = 1;
       DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
-      SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+      SET_DECL_ASSEMBLER_NAME (var_decl, var_name);
       DECL_ARTIFICIAL (var_decl) = 1;
       /* We cannot mark this variable as read-only because we want to be
          able to write to it at runtime.  */
@@ -1246,7 +1252,7 @@ vtable_find_or_create_map_decl (tree base_type)

       set_decl_section_name (var_decl, ".vtable_map_vars");
       symtab_node::get (var_decl)->implicit_section = true;
-      DECL_INITIAL (var_decl) = initial_value;
+      DECL_INITIAL (var_decl) = integer_zero_node;

       comdat_linkage (var_decl);

--
2.47.3

Reply via email to