[mutter/wip/carlosg/selection-epipe-on-x-error] x11: Handle windowing errors while writing selection INCR data



commit c7debae57f6cc04fd2686e4a62b74e6223be395b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Feb 24 15:33:08 2020 +0100

    x11: Handle windowing errors while writing selection INCR data
    
    This error was just logged but not raised. Do as the code comment said
    and raise a pipe error at that moment, and for subsequent operations
    on the output stream (although none besides close() should be expected
    after propagating the error properly).
    
    Related: https://gitlab.gnome.org/GNOME/mutter/issues/1065

 src/x11/meta-x11-selection-output-stream.c | 62 +++++++++++++++++++++++++++---
 1 file changed, 56 insertions(+), 6 deletions(-)
---
diff --git a/src/x11/meta-x11-selection-output-stream.c b/src/x11/meta-x11-selection-output-stream.c
index 1883bc92a..cd14aa170 100644
--- a/src/x11/meta-x11-selection-output-stream.c
+++ b/src/x11/meta-x11-selection-output-stream.c
@@ -53,6 +53,7 @@ struct _MetaX11SelectionOutputStreamPrivate
 
   guint incr : 1;
   guint delete_pending : 1;
+  guint pipe_error: 1;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (MetaX11SelectionOutputStream,
@@ -167,6 +168,25 @@ get_element_size (int format)
     }
 }
 
+static gboolean
+meta_x11_selection_output_stream_maybe_raise_error (MetaX11SelectionOutputStream  *stream,
+                                                    GError                       **error)
+{
+  MetaX11SelectionOutputStreamPrivate *priv =
+    meta_x11_selection_output_stream_get_instance_private (stream);
+
+  if (priv->pipe_error)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_BROKEN_PIPE,
+                   "Connection with client was broken");
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static void
 meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *stream)
 {
@@ -174,6 +194,7 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
     meta_x11_selection_output_stream_get_instance_private (stream);
   Display *xdisplay;
   size_t element_size, n_elements;
+  int error_code;
 
   g_assert (!priv->delete_pending);
 
@@ -230,18 +251,28 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
   g_cond_broadcast (&priv->cond);
   g_mutex_unlock (&priv->mutex);
 
-  /* XXX: handle failure here and report EPIPE for future operations on the stream? */
-  if (meta_x11_error_trap_pop_with_return (priv->x11_display))
-    g_warning ("Failed to flush selection output stream");
+  error_code = meta_x11_error_trap_pop_with_return (priv->x11_display);
 
-  if (priv->pending_task)
+  if (error_code != Success)
+    {
+      char error_str[100];
+
+      XGetErrorText (xdisplay, error_code, error_str, sizeof (error_str));
+      g_task_return_new_error (priv->pending_task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_BROKEN_PIPE,
+                               "Failed to flush selection output stream: %s",
+                               error_str);
+      g_clear_object (&priv->pending_task);
+      priv->pipe_error = TRUE;
+    }
+  else if (priv->pending_task)
     {
       size_t result;
 
       result = GPOINTER_TO_SIZE (g_task_get_task_data (priv->pending_task));
       g_task_return_int (priv->pending_task, result);
-      g_object_unref (priv->pending_task);
-      priv->pending_task = NULL;
+      g_clear_object (&priv->pending_task);
     }
 }
 
@@ -270,6 +301,9 @@ meta_x11_selection_output_stream_write (GOutputStream  *output_stream,
   MetaX11SelectionOutputStreamPrivate *priv =
     meta_x11_selection_output_stream_get_instance_private (stream);
 
+  if (meta_x11_selection_output_stream_maybe_raise_error (stream, error))
+    return -1;
+
   g_mutex_lock (&priv->mutex);
   g_byte_array_append (priv->data, buffer, count);
   g_mutex_unlock (&priv->mutex);
@@ -297,12 +331,19 @@ meta_x11_selection_output_stream_write_async (GOutputStream       *output_stream
     META_X11_SELECTION_OUTPUT_STREAM (output_stream);
   MetaX11SelectionOutputStreamPrivate *priv =
     meta_x11_selection_output_stream_get_instance_private (stream);
+  GError *error = NULL;
   GTask *task;
 
   task = g_task_new (stream, cancellable, callback, user_data);
   g_task_set_source_tag (task, meta_x11_selection_output_stream_write_async);
   g_task_set_priority (task, io_priority);
 
+  if (meta_x11_selection_output_stream_maybe_raise_error (stream, &error))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
   g_mutex_lock (&priv->mutex);
   g_byte_array_append (priv->data, buffer, count);
   g_mutex_unlock (&priv->mutex);
@@ -369,6 +410,8 @@ meta_x11_selection_output_stream_flush (GOutputStream  *output_stream,
   MetaX11SelectionOutputStreamPrivate *priv =
     meta_x11_selection_output_stream_get_instance_private (stream);
 
+  if (meta_x11_selection_output_stream_maybe_raise_error (stream, error))
+    return FALSE;
   if (!meta_x11_selection_output_request_flush (stream))
     return TRUE;
 
@@ -394,12 +437,19 @@ meta_x11_selection_output_stream_flush_async (GOutputStream       *output_stream
     META_X11_SELECTION_OUTPUT_STREAM (output_stream);
   MetaX11SelectionOutputStreamPrivate *priv =
     meta_x11_selection_output_stream_get_instance_private (stream);
+  GError *error = NULL;
   GTask *task;
 
   task = g_task_new (stream, cancellable, callback, user_data);
   g_task_set_source_tag (task, meta_x11_selection_output_stream_flush_async);
   g_task_set_priority (task, io_priority);
 
+  if (meta_x11_selection_output_stream_maybe_raise_error (stream, &error))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
   if (!meta_x11_selection_output_stream_can_flush (stream))
     {
       if (meta_x11_selection_output_request_flush (stream))


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]