diff options
author | Elliott Sales de Andrade <qulogic@pidgin.im> | 2019-11-05 20:27:32 -0500 |
---|---|---|
committer | Elliott Sales de Andrade <qulogic@pidgin.im> | 2019-11-05 20:27:32 -0500 |
commit | 043371096cbd109ba485edeb43134fb24fcfed76 (patch) | |
tree | a410ef71b92e25e96e4bf109079bbc33d8976c33 | |
parent | 3290d7924ed03670c3810f84bb01592f75274313 (diff) | |
download | pidgin-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.c | 72 |
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) { |