From aeb781acd65795fbb7e8c425174a07cb98119691 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 24 Feb 2020 15:33:08 +0100 Subject: [PATCH] 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 (cherry picked from commit 2ecbf6d74637508203290c0e324d736de10a9174) --- 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 86615364a..cd7b83a15 100644 --- a/src/x11/meta-x11-selection-output-stream.c +++ b/src/x11/meta-x11-selection-output-stream.c @@ -57,6 +57,7 @@ struct _MetaX11SelectionOutputStreamPrivate guint incr : 1; guint delete_pending : 1; + guint pipe_error : 1; }; G_DEFINE_TYPE_WITH_PRIVATE (MetaX11SelectionOutputStream, @@ -171,6 +172,25 @@ get_element_size (int format) } } +static gboolean +meta_x11_selection_output_stream_check_pipe (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 FALSE; + } + + return TRUE; +} + static void meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *stream) { @@ -178,6 +198,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); @@ -234,18 +255,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); } } @@ -274,6 +305,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_check_pipe (stream, error)) + return -1; + g_mutex_lock (&priv->mutex); g_byte_array_append (priv->data, buffer, count); g_mutex_unlock (&priv->mutex); @@ -301,12 +335,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_check_pipe (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); @@ -373,6 +414,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_check_pipe (stream, error)) + return FALSE; if (!meta_x11_selection_output_request_flush (stream)) return TRUE; @@ -398,12 +441,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_check_pipe (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))