[gvfs/gnome-3-8] Fix daemon crash when cancelling channel operations



commit d667f6fe956d8661710f9fe5ad3e54d9b24aa04a
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Apr 4 10:25:29 2013 +0200

    Fix daemon crash when cancelling channel operations
    
    The error handling in gvfschannel.c:start_queued_request() when
    there was an error creating the job or when the request was cancelled
    caused problems. It didn't set current_job, yet it called
    g_vfs_channel_send_error() which eventually resulted in a
    call to send_reply_cb which crashed as it assumed current_job
    was set.
    
    Also, not returning TRUE for started_job when we sent an error
    is problematic as we then could start the next job which caused
    us to have two outstanding jobs on the same channel mixing things up
    badly.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=675181

 daemon/Makefile.am    |    1 +
 daemon/gvfsbackend.h  |    1 +
 daemon/gvfschannel.c  |   52 ++++++++++++------------
 daemon/gvfsjoberror.c |  110 +++++++++++++++++++++++++++++++++++++++++++++++++
 daemon/gvfsjoberror.h |   61 +++++++++++++++++++++++++++
 5 files changed, 199 insertions(+), 26 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 71b8ad6..e53bd85 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -170,6 +170,7 @@ libdaemon_la_SOURCES = \
        gvfsjobpollmountable.c gvfsjobpollmountable.h \
        gvfsjobopenforread.c gvfsjobopenforread.h \
        gvfsjobopeniconforread.c gvfsjobopeniconforread.h \
+       gvfsjoberror.c gvfsjoberror.h \
        gvfsjobread.c gvfsjobread.h \
        gvfsjobseekread.c gvfsjobseekread.h \
        gvfsjobcloseread.c gvfsjobcloseread.h \
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index a69912b..e340cb9 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -74,6 +74,7 @@ typedef struct _GVfsJobPull             GVfsJobPull;
 typedef struct _GVfsJobSetAttribute     GVfsJobSetAttribute;
 typedef struct _GVfsJobQueryAttributes  GVfsJobQueryAttributes;
 typedef struct _GVfsJobCreateMonitor    GVfsJobCreateMonitor;
+typedef struct _GVfsJobError            GVfsJobError;
 
 typedef gpointer GVfsBackendHandle;
 
diff --git a/daemon/gvfschannel.c b/daemon/gvfschannel.c
index 7a4ace6..ec87cb9 100644
--- a/daemon/gvfschannel.c
+++ b/daemon/gvfschannel.c
@@ -40,6 +40,7 @@
 #include <gvfsdaemonutils.h>
 #include <gvfsjobcloseread.h>
 #include <gvfsjobclosewrite.h>
+#include <gvfsjoberror.h>
 #include <gvfsfileinfo.h>
 
 static void g_vfs_channel_job_source_iface_init (GVfsJobSourceIface *iface);
@@ -312,39 +313,38 @@ start_queued_request (GVfsChannel *channel)
       channel->priv->queued_requests =
        g_list_delete_link (channel->priv->queued_requests,
                            channel->priv->queued_requests);
-      
+
       error = NULL;
-      job = NULL;
-      if (req->cancelled)
+      /* This passes on ownership of req->data */
+      job = class->handle_request (channel,
+                                  req->command, req->seq_nr,
+                                  req->arg1, req->arg2,
+                                  req->data, req->data_len,
+                                  &error);
+      if (job == NULL)
+       {
+         job = g_vfs_job_error_new (channel, error);
+         g_error_free (error);
+       }
+
+
+      if (job != NULL && req->cancelled)
        {
+         /* Ignore the job, although we need to create it to rely
+            on handle_request side effects like seek generations, etc */
+         g_object_unref (job);
          error =
            g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
                                 _("Operation was cancelled"));
-         g_free (req->data); /* Did no pass ownership */
-       }
-      else
-       {
-         /* This passes on ownership of req->data */
-         job = class->handle_request (channel,
-                                      req->command, req->seq_nr,
-                                      req->arg1, req->arg2,
-                                      req->data, req->data_len, 
-                                      &error);
-       }
-      
-      if (job)
-       {
-         channel->priv->current_job = job;
-         channel->priv->current_job_seq_nr = req->seq_nr;
-         g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job);
-         started_job = TRUE;
-       }
-      else
-       {
-         g_vfs_channel_send_error (channel, error);
+         job = g_vfs_job_error_new (channel, error);
          g_error_free (error);
        }
-      
+
+      channel->priv->current_job = job;
+      channel->priv->current_job_seq_nr = req->seq_nr;
+      g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (channel), channel->priv->current_job);
+      started_job = TRUE;
+
       g_free (req);
     }
 
diff --git a/daemon/gvfsjoberror.c b/daemon/gvfsjoberror.c
new file mode 100644
index 0000000..c14626f
--- /dev/null
+++ b/daemon/gvfsjoberror.c
@@ -0,0 +1,110 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include "gvfsjoberror.h"
+#include "gvfsdaemonutils.h"
+
+G_DEFINE_TYPE (GVfsJobError, g_vfs_job_error, G_VFS_TYPE_JOB)
+
+static void     run        (GVfsJob *job);
+static gboolean try        (GVfsJob *job);
+static void     send_reply (GVfsJob *job);
+
+static void
+g_vfs_job_error_finalize (GObject *object)
+{
+  GVfsJobError *job;
+
+  job = G_VFS_JOB_ERROR (object);
+  g_object_unref (job->channel);
+  g_error_free (job->error);
+
+  if (G_OBJECT_CLASS (g_vfs_job_error_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_vfs_job_error_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_error_class_init (GVfsJobErrorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+  
+  gobject_class->finalize = g_vfs_job_error_finalize;
+
+  job_class->run = run;
+  job_class->try = try;
+  job_class->send_reply = send_reply;
+}
+
+static void
+g_vfs_job_error_init (GVfsJobError *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_error_new (GVfsChannel *channel,
+                    GError *error)
+{
+  GVfsJobError *job;
+
+  g_print ("g_vfs_job_error_new\n");
+
+  job = g_object_new (G_VFS_TYPE_JOB_ERROR,
+                     NULL);
+  job->channel = g_object_ref (channel);
+  job->error = g_error_copy (error);
+
+  return G_VFS_JOB (job);
+}
+
+/* Might be called on an i/o thread */
+static void
+send_reply (GVfsJob *job)
+{
+  GVfsJobError *op_job = G_VFS_JOB_ERROR (job);
+
+  g_print ("g_vfs_job_error send_reply\n");
+  
+  g_assert (job->failed);
+
+  g_vfs_channel_send_error (G_VFS_CHANNEL (op_job->channel), job->error);
+}
+
+static void
+run (GVfsJob *job)
+{
+}
+
+static gboolean
+try (GVfsJob *job)
+{
+  g_vfs_job_failed_from_error (job, G_VFS_JOB_ERROR (job)->error);
+}
diff --git a/daemon/gvfsjoberror.h b/daemon/gvfsjoberror.h
new file mode 100644
index 0000000..902e9f8
--- /dev/null
+++ b/daemon/gvfsjoberror.h
@@ -0,0 +1,61 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#ifndef __G_VFS_JOB_ERROR_H__
+#define __G_VFS_JOB_ERROR_H__
+
+#include <gvfsjob.h>
+#include <gvfsbackend.h>
+#include <gvfschannel.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_JOB_ERROR         (g_vfs_job_error_get_type ())
+#define G_VFS_JOB_ERROR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_ERROR, GVfsJobError))
+#define G_VFS_JOB_ERROR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_ERROR, GVfsJobErrorClass))
+#define G_VFS_IS_JOB_ERROR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_ERROR))
+#define G_VFS_IS_JOB_ERROR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_ERROR))
+#define G_VFS_JOB_ERROR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_ERROR, 
GVfsJobErrorClass))
+
+typedef struct _GVfsJobErrorClass   GVfsJobErrorClass;
+
+struct _GVfsJobError
+{
+  GVfsJob parent_instance;
+
+  GVfsChannel *channel;
+  GError *error;
+};
+
+struct _GVfsJobErrorClass
+{
+  GVfsJobClass parent_class;
+};
+
+GType g_vfs_job_error_get_type (void) G_GNUC_CONST;
+
+GVfsJob *g_vfs_job_error_new (GVfsChannel   *channel,
+                             GError *error);
+
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_ERROR_H__ */


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