diff options
author | Denis Kenzior <denkenz@gmail.com> | 2009-10-16 16:25:19 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-10-19 12:42:50 +0200 |
commit | 57ec42233cb80772563de634b6b22922112fbe76 (patch) | |
tree | 89770ef4e8530fab0c92115915c37e6d41fe6d7c /gatchat | |
parent | 98d3ef3a0c395916eac8acff3cdd085c9081be9b (diff) | |
download | connman-57ec42233cb80772563de634b6b22922112fbe76.tar.gz connman-57ec42233cb80772563de634b6b22922112fbe76.tar.bz2 connman-57ec42233cb80772563de634b6b22922112fbe76.zip |
Stop crashing when unrefing chat in callback
Diffstat (limited to 'gatchat')
-rw-r--r-- | gatchat/gatchat.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c index c4de1471..66874e29 100644 --- a/gatchat/gatchat.c +++ b/gatchat/gatchat.c @@ -87,6 +87,7 @@ struct _GAtChat { guint wakeup_timeout; /* How long to wait for resp */ GTimer *wakeup_timer; /* Keep track of elapsed time */ GAtSyntax *syntax; + gboolean destroyed; /* Re-entrancy guard */ }; static gint at_notify_node_compare_by_id(gconstpointer a, gconstpointer b) @@ -259,6 +260,9 @@ static void read_watcher_destroy_notify(GAtChat *chat) if (chat->user_disconnect) chat->user_disconnect(chat->user_disconnect_data); + + if (chat->destroyed) + g_free(chat); } static void write_watcher_destroy_notify(GAtChat *chat) @@ -587,7 +591,9 @@ static void new_bytes(GAtChat *p) GAtSyntaxResult result; - while (p->read_so_far < len) { + g_at_chat_ref(p); + + while (p->channel && (p->read_so_far < len)) { gsize rbytes = MIN(len - p->read_so_far, wrap - p->read_so_far); result = p->syntax->feed(p->syntax, (char *)buf, &rbytes); @@ -628,8 +634,10 @@ static void new_bytes(GAtChat *p) } /* We're overflowing the buffer, shutdown the socket */ - if (ring_buffer_avail(p->buf) == 0) + if (p->buf && ring_buffer_avail(p->buf) == 0) g_source_remove(p->read_watch); + + g_at_chat_unref(p); } static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len) @@ -982,7 +990,16 @@ void g_at_chat_unref(GAtChat *chat) return; g_at_chat_shutdown(chat); - g_free(chat); + + /* glib delays the destruction of the watcher until it exits, this + * means we can't free the data just yet, even though we've been + * destroyed already. We have to wait until the read_watcher + * destroy function gets called + */ + if (chat->read_watch != 0) + chat->destroyed = TRUE; + else + g_free(chat); } gboolean g_at_chat_shutdown(GAtChat *chat) |