[PATCH 1/2] Two bug fixes in mdict_free

Tom Tromey
2025-10-23T17:20:15Z

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.
---
gdb/dictionary.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/gdb/dictionary.c b/gdb/dictionary.c
index f435ad5a47e817dc59087ac2ff5637415a9256d6..9dec7ccb2af5fad1e0cb62b92dc79e41e2fbbc15 100644
--- a/gdb/dictionary.c
+++ b/gdb/dictionary.c
@@ -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;
}
}

--
2.49.0