From de49d8ad7387950077730a15732c118155f26742 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Sun, 12 May 2013 18:09:05 +0300 Subject: [PATCH] utils: fix memory leak in sorted GSList insert Some of the callers allocate memory for the data to be inserted in the list. The old code didn't free this if the value was already on the list. Update the API to add a GDestroyNotify parameter which will be called for this case. --- src/core/sipe-buddy.c | 5 ++++- src/core/sipe-chat.c | 9 +++++---- src/core/sipe-conf.c | 6 ++++-- src/core/sipe-group.c | 7 +++++-- src/core/sipe-notify.c | 14 ++++++++------ src/core/sipe-ocs2007.c | 12 +++++++++--- src/core/sipe-utils.c | 23 +++++++++++++---------- src/core/sipe-utils.h | 14 ++++++++------ 8 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/core/sipe-buddy.c b/src/core/sipe-buddy.c index f62cfdec..45117727 100644 --- a/src/core/sipe-buddy.c +++ b/src/core/sipe-buddy.c @@ -214,7 +214,10 @@ void sipe_core_buddy_group(struct sipe_core_public *sipe_public, if (!new_group) { sipe_group_create(SIPE_CORE_PRIVATE, new_group_name, who); } else { - buddy->groups = slist_insert_unique_sorted(buddy->groups, new_group, (GCompareFunc)sipe_group_compare); + buddy->groups = sipe_utils_slist_insert_unique_sorted(buddy->groups, + new_group, + (GCompareFunc)sipe_group_compare, + NULL); sipe_group_update_buddy(SIPE_CORE_PRIVATE, buddy); } } diff --git a/src/core/sipe-chat.c b/src/core/sipe-chat.c index fb4eb42d..d02bc314 100644 --- a/src/core/sipe-chat.c +++ b/src/core/sipe-chat.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2009-11 SIPE Project + * Copyright (C) 2009-2013 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -515,9 +515,10 @@ sipe_invite_to_chat(struct sipe_core_private *sipe_private, } else { SIPE_DEBUG_INFO_NOFORMAT("sipe_invite_to_chat: no RM available"); - session->pending_invite_queue = slist_insert_unique_sorted( - session->pending_invite_queue, g_strdup(who), (GCompareFunc)strcmp); - + session->pending_invite_queue = sipe_utils_slist_insert_unique_sorted(session->pending_invite_queue, + g_strdup(who), + (GCompareFunc)strcmp, + g_free); sipe_election_start(sipe_private, session); } g_free(self); diff --git a/src/core/sipe-conf.c b/src/core/sipe-conf.c index 1ae3cb3c..b139ace2 100644 --- a/src/core/sipe-conf.c +++ b/src/core/sipe-conf.c @@ -709,8 +709,10 @@ process_conf_add_response(struct sipe_core_private *sipe_private, SIPE_DEBUG_INFO("process_conf_add_response: session->focus_uri=%s", session->chat_session->id); - session->pending_invite_queue = slist_insert_unique_sorted( - session->pending_invite_queue, g_strdup(who), (GCompareFunc)strcmp); + session->pending_invite_queue = sipe_utils_slist_insert_unique_sorted(session->pending_invite_queue, + g_strdup(who), + (GCompareFunc)strcmp, + g_free); } sipe_xml_free(xn_response); } diff --git a/src/core/sipe-group.c b/src/core/sipe-group.c index 32f0af10..cc5341b9 100755 --- a/src/core/sipe-group.c +++ b/src/core/sipe-group.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011-12 SIPE Project + * Copyright (C) 2011-2013 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -92,7 +92,10 @@ process_add_group_response(struct sipe_core_private *sipe_private, if (ctx->user_name) { buddy = g_hash_table_lookup(sipe_private->buddies, ctx->user_name); if (buddy) { - buddy->groups = slist_insert_unique_sorted(buddy->groups, group, (GCompareFunc)sipe_group_compare); + buddy->groups = sipe_utils_slist_insert_unique_sorted(buddy->groups, + group, + (GCompareFunc)sipe_group_compare, + NULL); sipe_group_update_buddy(sipe_private, buddy); } } diff --git a/src/core/sipe-notify.c b/src/core/sipe-notify.c index 420cecd6..77f9f7ad 100644 --- a/src/core/sipe-notify.c +++ b/src/core/sipe-notify.c @@ -1190,9 +1190,10 @@ static void add_new_buddy(struct sipe_core_private *sipe_private, buddy = sipe_buddy_add(sipe_private, normalized_uri); - buddy->groups = slist_insert_unique_sorted(buddy->groups, - group, - (GCompareFunc)sipe_group_compare); + buddy->groups = sipe_utils_slist_insert_unique_sorted(buddy->groups, + group, + (GCompareFunc)sipe_group_compare, + NULL); SIPE_DEBUG_INFO("Added buddy %s to group %s", buddy->name, group->name); @@ -1356,9 +1357,10 @@ static gboolean sipe_process_roaming_contacts(struct sipe_core_private *sipe_pri uri, alias, group->name); - buddy->groups = slist_insert_unique_sorted(buddy->groups, - group, - (GCompareFunc) sipe_group_compare); + buddy->groups = sipe_utils_slist_insert_unique_sorted(buddy->groups, + group, + (GCompareFunc) sipe_group_compare, + NULL); SIPE_DEBUG_INFO("Added buddy %s (alias '%s' to group '%s'", uri, alias, group->name); } diff --git a/src/core/sipe-ocs2007.c b/src/core/sipe-ocs2007.c index 1568e696..5e0b80c4 100644 --- a/src/core/sipe-ocs2007.c +++ b/src/core/sipe-ocs2007.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011-12 SIPE Project + * Copyright (C) 2011-2013 SIPE Project * * * This program is free software; you can redistribute it and/or modify @@ -542,7 +542,10 @@ static GSList *get_access_domains(struct sipe_core_private *sipe_private) member = entry2->data; if (sipe_strcase_equal(member->type, "domain")) { - res = slist_insert_unique_sorted(res, g_strdup(member->value), (GCompareFunc)g_ascii_strcasecmp); + res = sipe_utils_slist_insert_unique_sorted(res, + g_strdup(member->value), + (GCompareFunc)g_ascii_strcasecmp, + g_free); } entry2 = entry2->next; } @@ -2058,7 +2061,10 @@ void sipe_ocs2007_process_roaming_self(struct sipe_core_private *sipe_private, /* set list of categories participating in this XML */ for (node = sipe_xml_child(xml, "categories/category"); node; node = sipe_xml_twin(node)) { const gchar *name = sipe_xml_attribute(node, "name"); - category_names = slist_insert_unique_sorted(category_names, (gchar *)name, (GCompareFunc)strcmp); + category_names = sipe_utils_slist_insert_unique_sorted(category_names, + (gchar *)name, + (GCompareFunc)strcmp, + NULL); } SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d", category_names ? (int) g_slist_length(category_names) : -1); diff --git a/src/core/sipe-utils.c b/src/core/sipe-utils.c index e8052b45..82e50190 100644 --- a/src/core/sipe-utils.c +++ b/src/core/sipe-utils.c @@ -607,17 +607,20 @@ sipe_utils_uri_unescape(const gchar *string) return unescaped; } -/** - * Only appends if no such value already stored. - * Like Set in Java. - */ -GSList * -slist_insert_unique_sorted(GSList *list, gpointer data, GCompareFunc func) { - GSList * res = list; - if (!g_slist_find_custom(list, data, func)) { - res = g_slist_insert_sorted(list, data, func); +GSList *sipe_utils_slist_insert_unique_sorted(GSList *list, + gpointer data, + GCompareFunc func, + GDestroyNotify destroy) +{ + if (g_slist_find_custom(list, data, func)) { + /* duplicate */ + if (destroy) + (*destroy)(data); + return(list); + } else { + /* unique: list takes ownership of "data" */ + return(g_slist_insert_sorted(list, data, func)); } - return res; } /* diff --git a/src/core/sipe-utils.h b/src/core/sipe-utils.h index b206ee49..ccc7b3d1 100644 --- a/src/core/sipe-utils.h +++ b/src/core/sipe-utils.h @@ -472,12 +472,14 @@ gchar *sipe_utils_uri_unescape(const gchar *string); /** * Inserts in item in the list only if the value isn't already in that list * - * @param list a singly linked list - * @param data the item to insert - * @param fund function to use to compare the values + * @param list a singly linked list + * @param data the item to insert. Will not be copied. + * @param func function to use to compare the values + * @param destroy if @c NULL call to destroy @c data if is already on list * * @return the new list head */ -GSList * -slist_insert_unique_sorted(GSList *list, gpointer data, GCompareFunc func); - +GSList *sipe_utils_slist_insert_unique_sorted(GSList *list, + gpointer data, + GCompareFunc func, + GDestroyNotify destroy); -- 2.11.4.GIT