]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Two bug fixes in mdict_free
authorTom Tromey <tom@tromey.com>
Fri, 17 Oct 2025 17:21:50 +0000 (11:21 -0600)
committerTom Tromey <tom@tromey.com>
Thu, 23 Oct 2025 18:50:23 +0000 (12:50 -0600)
A heap-allocated multidictionary should be freed by calling
mdict_free.  However, while this function does free the contents of
the dictionary, it neglects to free the dictionary itself.

There's also a second bug, which is that if a multidictionary is
created with no dictionaries, gdb will crash on the first line of
mdict_free:

  enum dict_type type = mdict->dictionaries[0]->vector->type;

So, this patch also adds the type to struct multidictionary, avoiding
this problem.  Note that this does not increase the structure size on
x86-64, because the new member fits into the padding.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
gdb/dictionary.c

index f435ad5a47e817dc59087ac2ff5637415a9256d6..ca0d4b5298a03ec86a41da789dcaa4278e11a19d 100644 (file)
@@ -911,6 +911,9 @@ struct multidictionary
   /* The number of language dictionaries currently allocated.
      Only used for expandable dictionaries.  */
   unsigned short n_allocated_dictionaries;
+
+  /* The type of dictionary.  */
+  enum dict_type type;
 };
 
 /* A helper function to collate symbols on the pending list by language.  */
@@ -948,6 +951,7 @@ mdict_create_hashed (struct obstack *obstack,
   retval->dictionaries
     = XOBNEWVEC (obstack, struct dictionary *, nsyms.size ());
   retval->n_allocated_dictionaries = nsyms.size ();
+  retval->type = DICT_HASHED;
 
   int idx = 0;
   for (const auto &[language, symlist] : nsyms)
@@ -969,6 +973,7 @@ mdict_create_hashed_expandable (enum language language)
   retval->n_allocated_dictionaries = 1;
   retval->dictionaries = XNEW (struct dictionary *);
   retval->dictionaries[0] = dict_create_hashed_expandable (language);
+  retval->type = DICT_HASHED_EXPANDABLE;
 
   return retval;
 }
@@ -988,6 +993,7 @@ mdict_create_linear (struct obstack *obstack,
   retval->dictionaries
     = XOBNEWVEC (obstack, struct dictionary *, nsyms.size ());
   retval->n_allocated_dictionaries = nsyms.size ();
+  retval->type = DICT_LINEAR;
 
   int idx = 0;
   for (const auto &[language, symlist] : nsyms)
@@ -1009,6 +1015,7 @@ mdict_create_linear_expandable (enum language language)
   retval->n_allocated_dictionaries = 1;
   retval->dictionaries = XNEW (struct dictionary *);
   retval->dictionaries[0] = dict_create_linear_expandable (language);
+  retval->type = DICT_LINEAR_EXPANDABLE;
 
   return retval;
 }
@@ -1018,15 +1025,12 @@ mdict_create_linear_expandable (enum language language)
 void
 mdict_free (struct multidictionary *mdict)
 {
-  /* Grab the type of dictionary being used.  */
-  enum dict_type type = mdict->dictionaries[0]->vector->type;
-
   /* Loop over all dictionaries and free them.  */
   for (unsigned short idx = 0; idx < mdict->n_allocated_dictionaries; ++idx)
     dict_free (mdict->dictionaries[idx]);
 
   /* Free the dictionary list, if needed.  */
-  switch (type)
+  switch (mdict->type)
     {
     case DICT_HASHED:
     case DICT_LINEAR:
@@ -1036,6 +1040,7 @@ mdict_free (struct multidictionary *mdict)
     case DICT_HASHED_EXPANDABLE:
     case DICT_LINEAR_EXPANDABLE:
       xfree (mdict->dictionaries);
+      xfree (mdict);
       break;
     }
 }
@@ -1067,10 +1072,7 @@ create_new_language_dictionary (struct multidictionary *mdict,
 {
   struct dictionary *retval = nullptr;
 
-  /* We use the first dictionary entry to decide what create function
-     to call.  Not optimal but sufficient.  */
-  gdb_assert (mdict->dictionaries[0] != nullptr);
-  switch (mdict->dictionaries[0]->vector->type)
+  switch (mdict->type)
     {
     case DICT_HASHED:
     case DICT_LINEAR: