[rhythmbox] podcast: reference count RBPodcastChannel structures
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] podcast: reference count RBPodcastChannel structures
- Date: Tue, 26 Jan 2021 10:11:30 +0000 (UTC)
commit 7d383c89a28ac214721ce18d9e2b69441364761e
Author: Jonathan Matthew <jonathan d14n org>
Date: Tue Jan 26 18:34:33 2021 +1000
podcast: reference count RBPodcastChannel structures
Search results can be deleted from the podcast add dialog while still being
parsed, which presents the opportunity for a use after free. Rather than
making the main thread wait for parsing to hit a cancellation point before
freeing the data structure, it's easier to reference count it.
Closes: #1846
podcast/rb-podcast-add-dialog.c | 15 ++++++++-------
podcast/rb-podcast-manager.c | 2 +-
podcast/rb-podcast-parse.c | 30 +++++++++++++++++++++++++-----
podcast/rb-podcast-parse.h | 6 +++++-
podcast/rb-podcast-search-itunes.c | 2 +-
5 files changed, 40 insertions(+), 15 deletions(-)
---
diff --git a/podcast/rb-podcast-add-dialog.c b/podcast/rb-podcast-add-dialog.c
index 0180b00b9..c46807410 100644
--- a/podcast/rb-podcast-add-dialog.c
+++ b/podcast/rb-podcast-add-dialog.c
@@ -125,7 +125,7 @@ remove_all_feeds_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
{
RBPodcastChannel *channel;
gtk_tree_model_get (model, iter, FEED_COLUMN_PARSED_FEED, &channel, -1);
- rb_podcast_parse_channel_free (channel);
+ rb_podcast_parse_channel_unref (channel);
return FALSE;
}
@@ -304,7 +304,7 @@ parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
if (data->reset_count != data->dialog->priv->reset_count) {
rb_debug ("dialog reset while parsing");
- rb_podcast_parse_channel_free (data->channel);
+ rb_podcast_parse_channel_unref (data->channel);
g_object_unref (data->dialog);
g_clear_error (&data->error);
g_free (data);
@@ -327,14 +327,14 @@ parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
RBPodcastItem *item;
item = l->data;
- channel = g_new0 (RBPodcastChannel, 1);
+ channel = rb_podcast_parse_channel_new ();
channel->url = g_strdup (item->url);
channel->title = g_strdup (item->title);
/* none of the other fields get populated anyway */
insert_search_result (data->dialog, channel, FALSE);
}
update_feed_status (data->dialog);
- rb_podcast_parse_channel_free (data->channel);
+ rb_podcast_parse_channel_unref (data->channel);
} else if (data->existing) {
GtkTreeIter iter;
gboolean found = FALSE;
@@ -355,7 +355,7 @@ parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
/* if the row is selected, create entries for the channel contents */
if (found == FALSE) {
- rb_podcast_parse_channel_free (data->channel);
+ rb_podcast_parse_channel_unref (data->channel);
} else if (data->dialog->priv->have_selection) {
GtkTreePath *a;
GtkTreePath *b;
@@ -375,6 +375,7 @@ parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
update_feed_status (data->dialog);
}
+ rb_podcast_parse_channel_unref (data->channel);
g_object_unref (data->dialog);
g_clear_error (&data->error);
g_free (data);
@@ -386,7 +387,7 @@ parse_search_text (RBPodcastAddDialog *dialog, const char *text)
ParseData *data;
RBPodcastChannel *channel;
- channel = g_new0 (RBPodcastChannel, 1);
+ channel = rb_podcast_parse_channel_new ();
channel->url = g_strdup (text);
data = g_new0 (ParseData, 1);
@@ -406,7 +407,7 @@ parse_search_result (RBPodcastAddDialog *dialog, RBPodcastChannel *channel)
data = g_new0 (ParseData, 1);
data->dialog = g_object_ref (dialog);
- data->channel = channel;
+ data->channel = rb_podcast_parse_channel_ref (channel);
data->existing = TRUE;
data->single = FALSE;
data->reset_count = dialog->priv->reset_count;
diff --git a/podcast/rb-podcast-manager.c b/podcast/rb-podcast-manager.c
index a34b2aaae..59c95a111 100644
--- a/podcast/rb-podcast-manager.c
+++ b/podcast/rb-podcast-manager.c
@@ -670,7 +670,7 @@ podcast_update_free (RBPodcastUpdate *update)
g_object_unref (pd);
g_clear_error (&update->error);
- rb_podcast_parse_channel_free (update->channel);
+ rb_podcast_parse_channel_unref (update->channel);
g_free (update);
}
diff --git a/podcast/rb-podcast-parse.c b/podcast/rb-podcast-parse.c
index 25307d5bf..19b9f865a 100644
--- a/podcast/rb-podcast-parse.c
+++ b/podcast/rb-podcast-parse.c
@@ -37,6 +37,7 @@
#include <glib/gprintf.h>
#include "rb-debug.h"
+#include "rb-util.h"
#include "rb-podcast-parse.h"
#include "rb-file-helpers.h"
@@ -219,11 +220,19 @@ rb_podcast_parse_load_feed (RBPodcastChannel *channel,
totem_pl_parser_parse_async (plparser, channel->url, FALSE, cancellable, parse_cb, data);
}
+RBPodcastChannel *
+rb_podcast_parse_channel_new (void)
+{
+ RBPodcastChannel *data;
+ data = g_new0 (RBPodcastChannel, 1);
+ data->refcount = 1;
+ return data;
+}
+
RBPodcastChannel *
rb_podcast_parse_channel_copy (RBPodcastChannel *data)
{
- RBPodcastChannel *copy;
- copy = g_new0 (RBPodcastChannel, 1);
+ RBPodcastChannel *copy = rb_podcast_parse_channel_new ();
copy->url = g_strdup (data->url);
copy->title = g_strdup (data->title);
copy->lang = g_strdup (data->lang);
@@ -250,10 +259,22 @@ rb_podcast_parse_channel_copy (RBPodcastChannel *data)
return copy;
}
+RBPodcastChannel *
+rb_podcast_parse_channel_ref (RBPodcastChannel *data)
+{
+ data->refcount++;
+ return data;
+}
+
void
-rb_podcast_parse_channel_free (RBPodcastChannel *data)
+rb_podcast_parse_channel_unref (RBPodcastChannel *data)
{
g_return_if_fail (data != NULL);
+ g_assert (rb_is_main_thread ());
+
+ if (--data->refcount > 0) {
+ return;
+ }
g_list_foreach (data->posts, (GFunc) rb_podcast_parse_item_free, NULL);
g_list_free (data->posts);
@@ -269,7 +290,6 @@ rb_podcast_parse_channel_free (RBPodcastChannel *data)
g_free (data->copyright);
g_free (data);
- data = NULL;
}
RBPodcastItem *
@@ -307,7 +327,7 @@ rb_podcast_channel_get_type (void)
if (G_UNLIKELY (type == 0)) {
type = g_boxed_type_register_static ("RBPodcastChannel",
(GBoxedCopyFunc)rb_podcast_parse_channel_copy,
- (GBoxedFreeFunc)rb_podcast_parse_channel_free);
+ (GBoxedFreeFunc)rb_podcast_parse_channel_unref);
}
return type;
}
diff --git a/podcast/rb-podcast-parse.h b/podcast/rb-podcast-parse.h
index c2acc9613..31b564d4c 100644
--- a/podcast/rb-podcast-parse.h
+++ b/podcast/rb-podcast-parse.h
@@ -55,6 +55,8 @@ typedef struct
typedef struct
{
+ int refcount;
+
char* url;
char* title;
char* lang;
@@ -83,9 +85,11 @@ void rb_podcast_parse_load_feed (RBPodcastChannel *data,
RBPodcastParseCallback callback,
gpointer user_data);
+RBPodcastChannel *rb_podcast_parse_channel_new (void);
RBPodcastChannel *rb_podcast_parse_channel_copy (RBPodcastChannel *data);
RBPodcastItem *rb_podcast_parse_item_copy (RBPodcastItem *data);
-void rb_podcast_parse_channel_free (RBPodcastChannel *data);
+RBPodcastChannel *rb_podcast_parse_channel_ref (RBPodcastChannel *data);
+void rb_podcast_parse_channel_unref (RBPodcastChannel *data);
void rb_podcast_parse_item_free (RBPodcastItem *data);
#endif /* RB_PODCAST_PARSE_H */
diff --git a/podcast/rb-podcast-search-itunes.c b/podcast/rb-podcast-search-itunes.c
index bfae276c6..f66859a31 100644
--- a/podcast/rb-podcast-search-itunes.c
+++ b/podcast/rb-podcast-search-itunes.c
@@ -93,7 +93,7 @@ process_results (RBPodcastSearchITunes *search, JsonParser *parser)
rb_debug ("got result %s (%s)", channel->title, channel->url);
rb_podcast_search_result (RB_PODCAST_SEARCH (search), channel);
- rb_podcast_parse_channel_free (channel);
+ rb_podcast_parse_channel_unref (channel);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]