Re: [PATCH] gatmux: Remove finalized watches from the list

2017-10-23 Thread Denis Kenzior

Hi Slava,

On 10/23/2017 04:17 AM, Slava Monich wrote:

Leaving them there may result in invalid reads like this:

==2312== Invalid read of size 4
==2312==at 0xAB8C0: dispatch_sources (gatmux.c:134)
==2312==by 0xAC5D3: channel_close (gatmux.c:479)
==2312==by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523)
==2312==by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240)
==2312==by 0xAC423: watch_finalize (gatmux.c:426)
==2312==by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048)
==2312==by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230)
==2312==by 0x4AF44E1: g_source_destroy (gmain.c:1256)
==2312==by 0x4AF5257: g_source_remove (gmain.c:2282)
==2312==by 0xAB5CB: io_shutdown (gatio.c:325)
==2312==by 0xAB667: g_at_io_unref (gatio.c:345)
==2312==by 0xA72C7: at_chat_unref (gatchat.c:972)
==2312==by 0xA829B: g_at_chat_unref (gatchat.c:1446)
==2312==  Address 0x51420f0 is 56 bytes inside a block of size 60 free'd
==2312==at 0x4840B28: free (vg_replace_malloc.c:530)
==2312==by 0x4AF2D33: g_source_unref_internal (gmain.c:2075)
==2312==by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230)
==2312==by 0x4AF44E1: g_source_destroy (gmain.c:1256)
==2312==by 0x4AF5257: g_source_remove (gmain.c:2282)
==2312==by 0xAB46B: g_at_io_set_write_handler (gatio.c:283)
==2312==by 0xA713F: at_chat_suspend (gatchat.c:938)
==2312==by 0xA72B7: at_chat_unref (gatchat.c:971)
==2312==by 0xA829B: g_at_chat_unref (gatchat.c:1446)
==2312==  Block was alloc'd at
==2312==at 0x4841BF0: calloc (vg_replace_malloc.c:711)
==2312==by 0x4AFB117: g_malloc0 (gmem.c:124)
==2312==by 0x4AF401F: g_source_new (gmain.c:892)
==2312==by 0xAC6A7: channel_create_watch (gatmux.c:506)
==2312==by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649)
==2312==by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297)
==2312==by 0xA7103: chat_wakeup_writer (gatchat.c:931)
==2312==by 0xA753F: at_chat_send_common (gatchat.c:1045)
==2312==by 0xA850F: g_at_chat_send (gatchat.c:1502)

It's also necessary to add additional references to the sources
for the duration of the dispatch_sources loop because any source
can be removed when any callback is invoked (and not necessarily
the one being dispatched).
---
  gatchat/gatmux.c | 109 +++
  1 file changed, 77 insertions(+), 32 deletions(-)



Applied, thanks.

Regards,
-Denis

___
ofono mailing list
ofono@ofono.org
https://lists.ofono.org/mailman/listinfo/ofono


[PATCH] gatmux: Remove finalized watches from the list

2017-10-23 Thread Slava Monich
Leaving them there may result in invalid reads like this:

==2312== Invalid read of size 4
==2312==at 0xAB8C0: dispatch_sources (gatmux.c:134)
==2312==by 0xAC5D3: channel_close (gatmux.c:479)
==2312==by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523)
==2312==by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240)
==2312==by 0xAC423: watch_finalize (gatmux.c:426)
==2312==by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048)
==2312==by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230)
==2312==by 0x4AF44E1: g_source_destroy (gmain.c:1256)
==2312==by 0x4AF5257: g_source_remove (gmain.c:2282)
==2312==by 0xAB5CB: io_shutdown (gatio.c:325)
==2312==by 0xAB667: g_at_io_unref (gatio.c:345)
==2312==by 0xA72C7: at_chat_unref (gatchat.c:972)
==2312==by 0xA829B: g_at_chat_unref (gatchat.c:1446)
==2312==  Address 0x51420f0 is 56 bytes inside a block of size 60 free'd
==2312==at 0x4840B28: free (vg_replace_malloc.c:530)
==2312==by 0x4AF2D33: g_source_unref_internal (gmain.c:2075)
==2312==by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230)
==2312==by 0x4AF44E1: g_source_destroy (gmain.c:1256)
==2312==by 0x4AF5257: g_source_remove (gmain.c:2282)
==2312==by 0xAB46B: g_at_io_set_write_handler (gatio.c:283)
==2312==by 0xA713F: at_chat_suspend (gatchat.c:938)
==2312==by 0xA72B7: at_chat_unref (gatchat.c:971)
==2312==by 0xA829B: g_at_chat_unref (gatchat.c:1446)
==2312==  Block was alloc'd at
==2312==at 0x4841BF0: calloc (vg_replace_malloc.c:711)
==2312==by 0x4AFB117: g_malloc0 (gmem.c:124)
==2312==by 0x4AF401F: g_source_new (gmain.c:892)
==2312==by 0xAC6A7: channel_create_watch (gatmux.c:506)
==2312==by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649)
==2312==by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297)
==2312==by 0xA7103: chat_wakeup_writer (gatchat.c:931)
==2312==by 0xA753F: at_chat_send_common (gatchat.c:1045)
==2312==by 0xA850F: g_at_chat_send (gatchat.c:1502)

It's also necessary to add additional references to the sources
for the duration of the dispatch_sources loop because any source
can be removed when any callback is invoked (and not necessarily
the one being dispatched).
---
 gatchat/gatmux.c | 109 +++
 1 file changed, 77 insertions(+), 32 deletions(-)

diff --git a/gatchat/gatmux.c b/gatchat/gatmux.c
index 0e275b5..909eca6 100644
--- a/gatchat/gatmux.c
+++ b/gatchat/gatmux.c
@@ -116,66 +116,109 @@ static inline void debug(GAtMux *mux, const char 
*format, ...)
 
 static void dispatch_sources(GAtMuxChannel *channel, GIOCondition condition)
 {
-   GAtMuxWatch *source;
GSList *c;
GSList *p;
-   GSList *t;
+   GSList *refs;
+
+   /*
+* Don't reference destroyed sources, they may have zero reference
+* count if this function is invoked from the source's finalize
+* callback, in which case incrementing and then decrementing
+* the count would result in double free (first when we decrement
+* the reference count and then when we return from the finalize
+* callback).
+*/
 
p = NULL;
-   c = channel->sources;
+   refs = NULL;
 
-   while (c) {
-   gboolean destroy = FALSE;
+   for (c = channel->sources; c; c = c->next) {
+   GSource *s = c->data;
+
+   if (!g_source_is_destroyed(s)) {
+   GSList *l = g_slist_append(NULL, g_source_ref(s));
+
+   if (p)
+   p->next = l;
+   else
+   refs = l;
 
-   source = c->data;
+   p = l;
+   }
+   }
 
-   debug(channel->mux, "checking source: %p", source);
+   /*
+* Keep the references to all sources for the duration of the loop.
+* Callbacks may add and remove the sources, i.e. channel->sources
+* may keep changing during the loop.
+*/
 
-   if (condition & source->condition) {
+   for (c = refs; c; c = c->next) {
+   GAtMuxWatch *w = c->data;
+   GSource *s = >source;
+
+   if (g_source_is_destroyed(s))
+   continue;
+
+   debug(channel->mux, "checking source: %p", s);
+
+   if (condition & w->condition) {
gpointer user_data = NULL;
GSourceFunc callback = NULL;
-   GSourceCallbackFuncs *cb_funcs;
-   gpointer cb_data;
-   gboolean (*dispatch) (GSource *, GSourceFunc, gpointer);
-
-   debug(channel->mux, "dispatching source: %p", source);
+   GSourceCallbackFuncs *cb_funcs = s->callback_funcs;
+   gpointer cb_data = s->callback_data;
+   gboolean destroy;
 
-