gst/tcp/gstfdset.c: Make sure the pollfds are not changed when the poll call is runni...
authorWim Taymans <wim.taymans@gmail.com>
Mon, 16 Aug 2004 16:45:52 +0000 (16:45 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 16 Aug 2004 16:45:52 +0000 (16:45 +0000)
Original commit message from CVS:
* gst/tcp/gstfdset.c: (ensure_size), (gst_fdset_new),
(gst_fdset_add_fd), (gst_fdset_remove_fd),
(gst_fdset_fd_has_closed), (gst_fdset_fd_has_error),
(gst_fdset_fd_can_read), (gst_fdset_fd_can_write),
(gst_fdset_wait):
Make sure the pollfds are not changed when the poll call is
running. Protect against array out of bounds.

ChangeLog
gst/tcp/gstfdset.c

index ef74156..e226005 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2004-08-16  Wim Taymans  <wim@fluendo.com>
 
+       * gst/tcp/gstfdset.c: (ensure_size), (gst_fdset_new),
+       (gst_fdset_add_fd), (gst_fdset_remove_fd),
+       (gst_fdset_fd_has_closed), (gst_fdset_fd_has_error),
+       (gst_fdset_fd_can_read), (gst_fdset_fd_can_write),
+       (gst_fdset_wait):
+
+2004-08-16  Wim Taymans  <wim@fluendo.com>
+
        * ext/theora/theoraenc.c: (gst_border_mode_get_type),
        (gst_theora_enc_class_init), (theora_enc_sink_link),
        (theora_buffer_from_packet), (theora_enc_chain):
index b394caf..12b5ae4 100644 (file)
@@ -54,10 +54,12 @@ struct _GstFDSet
   GstFDSetMode mode;
 
   /* for poll */
+  struct pollfd *testpollfds;
   struct pollfd *pollfds;
   gint last_pollfds;
   gint size;
   gint free;
+  GMutex *poll_lock;
 
   /* for select */
   fd_set readfds, writefds;     /* input */
@@ -85,6 +87,7 @@ ensure_size (GstFDSet * set, gint len)
     need = MAX (need, MIN_POLLFDS * sizeof (struct pollfd));
 
     set->pollfds = g_realloc (set->pollfds, need);
+    set->testpollfds = g_realloc (set->testpollfds, need);
 
     set->size = need;
   }
@@ -105,8 +108,10 @@ gst_fdset_new (GstFDSetMode mode)
       break;
     case GST_FDSET_MODE_POLL:
       nset->pollfds = NULL;
+      nset->testpollfds = NULL;
       nset->free = 0;
       nset->last_pollfds = 0;
+      nset->poll_lock = g_mutex_new ();
       ensure_size (nset, MIN_POLLFDS);
       break;
     case GST_FDSET_MODE_EPOLL:
@@ -161,6 +166,8 @@ gst_fdset_add_fd (GstFDSet * set, GstFD * fd)
       struct pollfd *nfd;
       gint idx;
 
+      g_mutex_lock (set->poll_lock);
+
       ensure_size (set, set->last_pollfds + 1);
 
       idx = set->free;
@@ -182,6 +189,8 @@ gst_fdset_add_fd (GstFDSet * set, GstFD * fd)
       set->last_pollfds = MAX (idx + 1, set->last_pollfds);
       fd->idx = idx;
       set->free = -1;
+      g_mutex_unlock (set->poll_lock);
+
       break;
     }
     case GST_FDSET_MODE_EPOLL:
@@ -200,6 +209,7 @@ gst_fdset_remove_fd (GstFDSet * set, GstFD * fd)
       break;
     case GST_FDSET_MODE_POLL:
     {
+      g_mutex_lock (set->poll_lock);
       set->pollfds[fd->idx].fd = -1;
       set->pollfds[fd->idx].events = 0;
       set->pollfds[fd->idx].revents = 0;
@@ -215,6 +225,7 @@ gst_fdset_remove_fd (GstFDSet * set, GstFD * fd)
       } else {
         set->free = MIN (set->free, fd->idx);
       }
+      g_mutex_unlock (set->poll_lock);
       break;
     }
     case GST_FDSET_MODE_EPOLL:
@@ -272,8 +283,13 @@ gst_fdset_fd_has_closed (GstFDSet * set, GstFD * fd)
       res = FALSE;
       break;
     case GST_FDSET_MODE_POLL:
-      res = (set->pollfds[fd->idx].revents & POLLHUP) != 0;
+    {
+      gint idx = fd->idx;
+
+      if (idx > 0)
+        res = (set->testpollfds[idx].revents & POLLHUP) != 0;
       break;
+    }
     case GST_FDSET_MODE_EPOLL:
       break;
   }
@@ -290,8 +306,13 @@ gst_fdset_fd_has_error (GstFDSet * set, GstFD * fd)
       res = FALSE;
       break;
     case GST_FDSET_MODE_POLL:
-      res = (set->pollfds[fd->idx].revents & (POLLERR | POLLNVAL)) != 0;
+    {
+      gint idx = fd->idx;
+
+      if (idx > 0)
+        res = (set->testpollfds[idx].revents & (POLLERR | POLLNVAL)) != 0;
       break;
+    }
     case GST_FDSET_MODE_EPOLL:
       break;
   }
@@ -308,8 +329,13 @@ gst_fdset_fd_can_read (GstFDSet * set, GstFD * fd)
       res = FD_ISSET (fd->fd, &set->testreadfds);
       break;
     case GST_FDSET_MODE_POLL:
-      res = (set->pollfds[fd->idx].revents & (POLLIN | POLLPRI)) != 0;
+    {
+      gint idx = fd->idx;
+
+      if (idx > 0)
+        res = (set->testpollfds[idx].revents & (POLLIN | POLLPRI)) != 0;
       break;
+    }
     case GST_FDSET_MODE_EPOLL:
       break;
   }
@@ -326,8 +352,13 @@ gst_fdset_fd_can_write (GstFDSet * set, GstFD * fd)
       res = FD_ISSET (fd->fd, &set->testwritefds);
       break;
     case GST_FDSET_MODE_POLL:
-      res = (set->pollfds[fd->idx].revents & POLLOUT) != 0;
+    {
+      gint idx = fd->idx;
+
+      if (idx > 0)
+        res = (set->testpollfds[idx].revents & POLLOUT) != 0;
       break;
+    }
     case GST_FDSET_MODE_EPOLL:
       break;
   }
@@ -360,11 +391,18 @@ gst_fdset_wait (GstFDSet * set, int timeout)
       break;
     }
     case GST_FDSET_MODE_POLL:
-      /* we do not make a copy here. The polfds could change while
-       * executing this call but even if this should happen and cause
-       * problems, we can recover from it */
-      res = poll (set->pollfds, set->last_pollfds, timeout);
+    {
+      gint last_pollfds;
+
+      g_mutex_lock (set->poll_lock);
+      last_pollfds = set->last_pollfds;
+      memcpy (set->testpollfds, set->pollfds,
+          sizeof (struct pollfd) * last_pollfds);
+      g_mutex_unlock (set->poll_lock);
+
+      res = poll (set->testpollfds, last_pollfds, timeout);
       break;
+    }
     case GST_FDSET_MODE_EPOLL:
       break;
   }