summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Sales de Andrade <qulogic@pidgin.im>2019-11-05 20:27:32 -0500
committerElliott Sales de Andrade <qulogic@pidgin.im>2019-11-05 20:27:32 -0500
commit043371096cbd109ba485edeb43134fb24fcfed76 (patch)
treea410ef71b92e25e96e4bf109079bbc33d8976c33
parent3290d7924ed03670c3810f84bb01592f75274313 (diff)
downloadpidgin-043371096cbd109ba485edeb43134fb24fcfed76.tar.gz
Re-write remove_prefs to not use recursion.
This also fixes the possible use-after-free that scan-build seems to think is there.
-rw-r--r--libpurple/prefs.c72
1 files changed, 50 insertions, 22 deletions
diff --git a/libpurple/prefs.c b/libpurple/prefs.c
index f3f7cd1ccc..a0387a268a 100644
--- a/libpurple/prefs.c
+++ b/libpurple/prefs.c
@@ -758,35 +758,16 @@ purple_prefs_add_path_list(const char *name, GList *value)
g_strdup(tmp->data));
}
-
static void
-remove_pref(struct purple_pref *pref)
+free_pref(struct purple_pref *pref)
{
char *name;
- if(!pref)
- return;
-
- while(pref->first_child)
- remove_pref(pref->first_child);
-
- if(pref == &prefs)
- return;
-
- if(pref->parent->first_child == pref) {
- pref->parent->first_child = pref->sibling;
- } else {
- struct purple_pref *sib = pref->parent->first_child;
- while(sib && sib->sibling != pref)
- sib = sib->sibling;
- if(sib)
- sib->sibling = pref->sibling;
- }
-
name = pref_full_name(pref);
- if (prefs_loaded)
+ if (prefs_loaded) {
purple_debug_info("prefs", "removing pref %s\n", name);
+ }
g_hash_table_remove(prefs_hash, name);
g_free(name);
@@ -798,6 +779,53 @@ remove_pref(struct purple_pref *pref)
g_free(pref);
}
+static void
+remove_pref(struct purple_pref *pref)
+{
+ struct purple_pref *child;
+
+ if (!pref) {
+ return;
+ }
+
+ child = pref->first_child;
+ while (child) {
+ struct purple_pref *next;
+ if (child->first_child) {
+ next = child->first_child;
+ } else if (child->sibling) {
+ next = child->sibling;
+ free_pref(child);
+ } else {
+ if (child->parent != pref) {
+ next = child->parent;
+ } else {
+ next = NULL;
+ }
+ free_pref(child);
+ }
+ child = next;
+ }
+
+ if (pref == &prefs) {
+ return;
+ }
+
+ if (pref->parent->first_child == pref) {
+ pref->parent->first_child = pref->sibling;
+ } else {
+ child = pref->parent->first_child;
+ while (child && child->sibling != pref) {
+ child = child->sibling;
+ }
+ if (child) {
+ child->sibling = pref->sibling;
+ }
+ }
+
+ free_pref(pref);
+}
+
void
purple_prefs_remove(const char *name)
{