a8b23d
From 41c325dfb32269c9aadfeedb4df44656aac4d883 Mon Sep 17 00:00:00 2001
a8b23d
From: fujiwarat <takao.fujiwara1@gmail.com>
a8b23d
Date: Fri, 20 Nov 2020 09:53:54 +0900
a8b23d
Subject: [PATCH] Fix SEGV in bus_panel_proxy_focus_in()
a8b23d
a8b23d
rhbz#1350291 SEGV in BUS_IS_CONNECTION(skip_connection) in
a8b23d
bus_dbus_impl_dispatch_message_by_rule()
a8b23d
check if dbus_connection is closed in bus_dbus_impl_connection_filter_cb().
a8b23d
a8b23d
rhbz#1767976 SEGV in assert(connection != NULL) in
a8b23d
bus_dbus_impl_connection_filter_cb()
a8b23d
call bus_connection_set_filter() in bus_dbus_impl_destroy().
a8b23d
a8b23d
rhbz#1601577 rhbz#1797726 SEGV in ibus_engine_desc_get_layout() in
a8b23d
bus_engine_proxy_new_internal()
a8b23d
WIP: Added a GError to get the error message to check why the SEGV happened.
a8b23d
a8b23d
rhbz#1663528 SEGV in g_mutex_clear() in bus_dbus_impl_destroy()
a8b23d
If the mutex is not unlocked, g_mutex_clear() causes assert.
a8b23d
a8b23d
rhbz#1767691 SEGV in client/x11/main.c:_sighandler().
a8b23d
Do not call atexit functions in _sighandler().
a8b23d
a8b23d
rhbz#1795499 SEGV in ibus_bus_get_bus_address() because of no _bus->priv.
a8b23d
_changed_cb() should not be called after ibus_bus_destroy() is called.
a8b23d
a8b23d
rhbz#1771238 SEGV in assert(m_loop == null) in switcher.vala.
a8b23d
Grabbing keyboard could be failed and switcher received the keyboard
a8b23d
events and m_loop was not released.
a8b23d
a8b23d
rhbz#1797120 SEGV in assert(bus.is_connected()) in panel_binding_construct()
a8b23d
Check m_ibus in extension.vala:bus_name_acquired_cb()
a8b23d
a8b23d
BUG=rhbz#1350291
a8b23d
BUG=rhbz#1601577
a8b23d
BUG=rhbz#1663528
a8b23d
BUG=rhbz#1767691
a8b23d
BUG=rhbz#1795499
a8b23d
BUG=rhbz#1771238
a8b23d
BUG=rhbz#1767976
a8b23d
BUG=rhbz#1797120
a8b23d
---
a8b23d
 bus/dbusimpl.c         | 47 ++++++++++++++++++++++++---
a8b23d
 bus/engineproxy.c      | 51 ++++++++++++++++++++++-------
a8b23d
 client/x11/main.c      |  8 ++++-
a8b23d
 src/ibusbus.c          |  5 +++
a8b23d
 ui/gtk3/extension.vala |  4 +++
a8b23d
 ui/gtk3/switcher.vala  | 73 +++++++++++++++++++++++++-----------------
a8b23d
 6 files changed, 141 insertions(+), 47 deletions(-)
a8b23d
a8b23d
diff --git a/bus/dbusimpl.c b/bus/dbusimpl.c
a8b23d
index 59787a80..af2fbde2 100644
a8b23d
--- a/bus/dbusimpl.c
a8b23d
+++ b/bus/dbusimpl.c
a8b23d
@@ -610,6 +610,7 @@ static void
a8b23d
 bus_dbus_impl_destroy (BusDBusImpl *dbus)
a8b23d
 {
a8b23d
     GList *p;
a8b23d
+    int i;
a8b23d
 
a8b23d
     for (p = dbus->objects; p != NULL; p = p->next) {
a8b23d
         IBusService *object = (IBusService *) p->data;
a8b23d
@@ -633,6 +634,10 @@ bus_dbus_impl_destroy (BusDBusImpl *dbus)
a8b23d
 
a8b23d
     for (p = dbus->connections; p != NULL; p = p->next) {
a8b23d
         BusConnection *connection = BUS_CONNECTION (p->data);
a8b23d
+        /* rhbz#1767976 Fix connection == NULL in
a8b23d
+         * bus_dbus_impl_connection_filter_cb()
a8b23d
+         */
a8b23d
+        bus_connection_set_filter (connection, NULL, NULL, NULL);
a8b23d
         g_signal_handlers_disconnect_by_func (connection,
a8b23d
                 bus_dbus_impl_connection_destroy_cb, dbus);
a8b23d
         ibus_object_destroy (IBUS_OBJECT (connection));
a8b23d
@@ -647,12 +652,39 @@ bus_dbus_impl_destroy (BusDBusImpl *dbus)
a8b23d
     dbus->unique_names = NULL;
a8b23d
     dbus->names = NULL;
a8b23d
 
a8b23d
+    for (i = 0; g_idle_remove_by_data (dbus); i++) {
a8b23d
+        if (i > 1000) {
a8b23d
+            g_warning ("Too many idle threads were generated by " \
a8b23d
+                       "bus_dbus_impl_forward_message_idle_cb and " \
a8b23d
+                       "bus_dbus_impl_dispatch_message_by_rule_idle_cb");
a8b23d
+            break;
a8b23d
+        }
a8b23d
+    }
a8b23d
     g_list_free_full (dbus->start_service_calls,
a8b23d
                       (GDestroyNotify) bus_method_call_free);
a8b23d
     dbus->start_service_calls = NULL;
a8b23d
 
a8b23d
-    g_mutex_clear (&dbus->dispatch_lock);
a8b23d
-    g_mutex_clear (&dbus->forward_lock);
a8b23d
+   /* rhbz#1663528 Call g_mutex_trylock() before g_mutex_clear()
a8b23d
+    * because if the mutex is not unlocked, g_mutex_clear() causes assert.
a8b23d
+    */
a8b23d
+#define BUS_DBUS_MUTEX_SAFE_CLEAR(mtex) {                               \
a8b23d
+    int count = 0;                                                      \
a8b23d
+    while (!g_mutex_trylock ((mtex))) {                                 \
a8b23d
+        g_usleep (1);                                                   \
a8b23d
+        if (count > 60) {                                               \
a8b23d
+            g_warning (#mtex " is dead lock");                          \
a8b23d
+            break;                                                      \
a8b23d
+        }                                                               \
a8b23d
+        ++count;                                                        \
a8b23d
+    }                                                                   \
a8b23d
+    g_mutex_unlock ((mtex));                                            \
a8b23d
+    g_mutex_clear ((mtex));                                             \
a8b23d
+}
a8b23d
+
a8b23d
+    BUS_DBUS_MUTEX_SAFE_CLEAR (&dbus->dispatch_lock);
a8b23d
+    BUS_DBUS_MUTEX_SAFE_CLEAR (&dbus->forward_lock);
a8b23d
+
a8b23d
+#undef BUS_DBUS_MUTEX_SAFE_CLEAR
a8b23d
 
a8b23d
     /* FIXME destruct _lock and _queue members. */
a8b23d
     IBUS_OBJECT_CLASS(bus_dbus_impl_parent_class)->destroy ((IBusObject *) dbus);
a8b23d
@@ -1483,13 +1515,20 @@ bus_dbus_impl_connection_filter_cb (GDBusConnection *dbus_connection,
a8b23d
                                     gboolean         incoming,
a8b23d
                                     gpointer         user_data)
a8b23d
 {
a8b23d
+    BusDBusImpl *dbus;
a8b23d
+    BusConnection *connection;
a8b23d
+
a8b23d
     g_assert (G_IS_DBUS_CONNECTION (dbus_connection));
a8b23d
     g_assert (G_IS_DBUS_MESSAGE (message));
a8b23d
     g_assert (BUS_IS_DBUS_IMPL (user_data));
a8b23d
 
a8b23d
-    BusDBusImpl *dbus = (BusDBusImpl *) user_data;
a8b23d
-    BusConnection *connection = bus_connection_lookup (dbus_connection);
a8b23d
+    if (g_dbus_connection_is_closed (dbus_connection))
a8b23d
+        return NULL;
a8b23d
+
a8b23d
+    dbus = (BusDBusImpl *) user_data;
a8b23d
+    connection = bus_connection_lookup (dbus_connection);
a8b23d
     g_assert (connection != NULL);
a8b23d
+    g_assert (BUS_IS_CONNECTION (connection));
a8b23d
 
a8b23d
     if (incoming) {
a8b23d
         /* is incoming message */
a8b23d
diff --git a/bus/engineproxy.c b/bus/engineproxy.c
a8b23d
index 2d98995c..bbbe5532 100644
a8b23d
--- a/bus/engineproxy.c
a8b23d
+++ b/bus/engineproxy.c
a8b23d
@@ -660,20 +660,33 @@ bus_engine_proxy_g_signal (GDBusProxy  *proxy,
a8b23d
     g_return_if_reached ();
a8b23d
 }
a8b23d
 
a8b23d
+#pragma GCC optimize ("O0")
a8b23d
 static BusEngineProxy *
a8b23d
 bus_engine_proxy_new_internal (const gchar     *path,
a8b23d
                                IBusEngineDesc  *desc,
a8b23d
-                               GDBusConnection *connection)
a8b23d
+                               GDBusConnection *connection,
a8b23d
+                               GError         **error)
a8b23d
 {
a8b23d
+    GDBusProxyFlags flags;
a8b23d
+    BusEngineProxy *engine;
a8b23d
+
a8b23d
     g_assert (path);
a8b23d
     g_assert (IBUS_IS_ENGINE_DESC (desc));
a8b23d
     g_assert (G_IS_DBUS_CONNECTION (connection));
a8b23d
+    g_assert (error && *error == NULL);
a8b23d
 
a8b23d
-    GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
a8b23d
-    BusEngineProxy *engine =
a8b23d
+    /* rhbz#1601577 engine == NULL if connection is closed. */
a8b23d
+    if (g_dbus_connection_is_closed (connection)) {
a8b23d
+        *error = g_error_new (G_DBUS_ERROR,
a8b23d
+                              G_DBUS_ERROR_FAILED,
a8b23d
+                              "Connection is closed.");
a8b23d
+        return NULL;
a8b23d
+    }
a8b23d
+    flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
a8b23d
+    engine =
a8b23d
         (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY,
a8b23d
                                            NULL,
a8b23d
-                                           NULL,
a8b23d
+                                           error,
a8b23d
                                            "desc",              desc,
a8b23d
                                            "g-connection",      connection,
a8b23d
                                            "g-interface-name",  IBUS_INTERFACE_ENGINE,
a8b23d
@@ -681,12 +694,19 @@ bus_engine_proxy_new_internal (const gchar     *path,
a8b23d
                                            "g-default-timeout", g_gdbus_timeout,
a8b23d
                                            "g-flags",           flags,
a8b23d
                                            NULL);
a8b23d
+    /* FIXME: rhbz#1601577 */
a8b23d
+    if (!engine) {
a8b23d
+        /* show abrt local variable */
a8b23d
+        gchar *message = g_strdup ((*error)->message);
a8b23d
+        g_error ("%s", message);
a8b23d
+    }
a8b23d
     const gchar *layout = ibus_engine_desc_get_layout (desc);
a8b23d
     if (layout != NULL && layout[0] != '\0') {
a8b23d
         engine->keymap = ibus_keymap_get (layout);
a8b23d
     }
a8b23d
     return engine;
a8b23d
 }
a8b23d
+#pragma GCC reset_options
a8b23d
 
a8b23d
 typedef struct {
a8b23d
     GTask           *task;
a8b23d
@@ -748,23 +768,30 @@ create_engine_ready_cb (BusFactoryProxy    *factory,
a8b23d
                         GAsyncResult       *res,
a8b23d
                         EngineProxyNewData *data)
a8b23d
 {
a8b23d
+    GError *error = NULL;
a8b23d
+    gchar *path;
a8b23d
+    BusEngineProxy *engine;
a8b23d
+
a8b23d
     g_return_if_fail (data->task != NULL);
a8b23d
 
a8b23d
-    GError *error = NULL;
a8b23d
-    gchar *path = bus_factory_proxy_create_engine_finish (factory,
a8b23d
-                                                          res,
a8b23d
-                                                          &error);
a8b23d
+    path = bus_factory_proxy_create_engine_finish (factory, res, &error);
a8b23d
     if (path == NULL) {
a8b23d
         g_task_return_error (data->task, error);
a8b23d
         engine_proxy_new_data_free (data);
a8b23d
         return;
a8b23d
     }
a8b23d
 
a8b23d
-    BusEngineProxy *engine =
a8b23d
-            bus_engine_proxy_new_internal (path,
a8b23d
-                                           data->desc,
a8b23d
-                                           g_dbus_proxy_get_connection ((GDBusProxy *)data->factory));
a8b23d
+    engine = bus_engine_proxy_new_internal (
a8b23d
+            path,
a8b23d
+            data->desc,
a8b23d
+            g_dbus_proxy_get_connection ((GDBusProxy *)data->factory),
a8b23d
+            &error);
a8b23d
     g_free (path);
a8b23d
+    if (!engine) {
a8b23d
+        g_task_return_error (data->task, error);
a8b23d
+        engine_proxy_new_data_free (data);
a8b23d
+        return;
a8b23d
+    }
a8b23d
 
a8b23d
     /* FIXME: set destroy callback ? */
a8b23d
     g_task_return_pointer (data->task, engine, NULL);
a8b23d
diff --git a/client/x11/main.c b/client/x11/main.c
a8b23d
index c9ee174d..768b91f0 100644
a8b23d
--- a/client/x11/main.c
a8b23d
+++ b/client/x11/main.c
a8b23d
@@ -40,6 +40,7 @@
a8b23d
 #include <iconv.h>
a8b23d
 #include <signal.h>
a8b23d
 #include <stdlib.h>
a8b23d
+#include <unistd.h>
a8b23d
 
a8b23d
 #include <getopt.h>
a8b23d
 
a8b23d
@@ -1104,7 +1105,12 @@ _atexit_cb ()
a8b23d
 static void
a8b23d
 _sighandler (int sig)
a8b23d
 {
a8b23d
-    exit(EXIT_FAILURE);
a8b23d
+    /* rhbz#1767691 _sighandler() is called with SIGTERM
a8b23d
+     * and exit() causes SEGV during calling atexit functions.
a8b23d
+     * _atexit_cb() might be broken. _exit() does not call
a8b23d
+     * atexit functions.
a8b23d
+     */
a8b23d
+    _exit(EXIT_FAILURE);
a8b23d
 }
a8b23d
 
a8b23d
 static void
a8b23d
diff --git a/src/ibusbus.c b/src/ibusbus.c
a8b23d
index b7ffbb47..668c8a26 100644
a8b23d
--- a/src/ibusbus.c
a8b23d
+++ b/src/ibusbus.c
a8b23d
@@ -689,6 +689,11 @@ ibus_bus_destroy (IBusObject *object)
a8b23d
     _bus = NULL;
a8b23d
 
a8b23d
     if (bus->priv->monitor) {
a8b23d
+        /* rhbz#1795499 _changed_cb() causes SEGV because of no bus->priv
a8b23d
+         * after ibus_bus_destroy() is called.
a8b23d
+         */
a8b23d
+        g_signal_handlers_disconnect_by_func (bus->priv->monitor,
a8b23d
+                                              (GCallback) _changed_cb, bus);
a8b23d
         g_object_unref (bus->priv->monitor);
a8b23d
         bus->priv->monitor = NULL;
a8b23d
     }
a8b23d
diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala
a8b23d
index a6f2e8e6..b7a04081 100644
a8b23d
--- a/ui/gtk3/extension.vala
a8b23d
+++ b/ui/gtk3/extension.vala
a8b23d
@@ -73,6 +73,10 @@ class ExtensionGtk : Gtk.Application {
a8b23d
                                       string         signal_name,
a8b23d
                                       Variant        parameters) {
a8b23d
         debug("signal_name = %s", signal_name);
a8b23d
+        /* rhbz#1797120 Fix assert(bus.is_connected()) in
a8b23d
+         * panel_binding_construct()
a8b23d
+         */
a8b23d
+        return_if_fail(m_bus.is_connected());
a8b23d
         m_panel = new PanelBinding(m_bus, this);
a8b23d
         m_panel.load_settings();
a8b23d
     }
a8b23d
diff --git a/ui/gtk3/switcher.vala b/ui/gtk3/switcher.vala
a8b23d
index a4529c88..29a70dd5 100644
a8b23d
--- a/ui/gtk3/switcher.vala
a8b23d
+++ b/ui/gtk3/switcher.vala
a8b23d
@@ -140,8 +140,8 @@ class Switcher : Gtk.Window {
a8b23d
                    IBus.EngineDesc[] engines,
a8b23d
                    int               index,
a8b23d
                    string            input_context_path) {
a8b23d
-        assert (m_loop == null);
a8b23d
-        assert (index < engines.length);
a8b23d
+        assert(m_loop == null);
a8b23d
+        assert(index < engines.length);
a8b23d
 
a8b23d
         m_is_running = true;
a8b23d
         m_keyval = keyval;
a8b23d
@@ -198,16 +198,18 @@ class Switcher : Gtk.Window {
a8b23d
                            null,
a8b23d
                            event,
a8b23d
                            null);
a8b23d
-        if (status != Gdk.GrabStatus.SUCCESS)
a8b23d
+        if (status != Gdk.GrabStatus.SUCCESS) {
a8b23d
             warning("Grab keyboard failed! status = %d", status);
a8b23d
-        status = seat.grab(get_window(),
a8b23d
-                           Gdk.SeatCapabilities.POINTER,
a8b23d
-                           true,
a8b23d
-                           null,
a8b23d
-                           event,
a8b23d
-                           null);
a8b23d
-        if (status != Gdk.GrabStatus.SUCCESS)
a8b23d
-            warning("Grab pointer failed! status = %d", status);
a8b23d
+        } else {
a8b23d
+            status = seat.grab(get_window(),
a8b23d
+                               Gdk.SeatCapabilities.POINTER,
a8b23d
+                               true,
a8b23d
+                               null,
a8b23d
+                               event,
a8b23d
+                               null);
a8b23d
+            if (status != Gdk.GrabStatus.SUCCESS)
a8b23d
+                warning("Grab pointer failed! status = %d", status);
a8b23d
+        }
a8b23d
 #else
a8b23d
         Gdk.Device device = event.get_device();
a8b23d
         if (device == null) {
a8b23d
@@ -243,30 +245,41 @@ class Switcher : Gtk.Window {
a8b23d
                                Gdk.EventMask.KEY_RELEASE_MASK,
a8b23d
                                null,
a8b23d
                                Gdk.CURRENT_TIME);
a8b23d
-        if (status != Gdk.GrabStatus.SUCCESS)
a8b23d
+        if (status != Gdk.GrabStatus.SUCCESS) {
a8b23d
             warning("Grab keyboard failed! status = %d", status);
a8b23d
-        // Grab all pointer events
a8b23d
-        status = pointer.grab(get_window(),
a8b23d
-                              Gdk.GrabOwnership.NONE,
a8b23d
-                              true,
a8b23d
-                              Gdk.EventMask.BUTTON_PRESS_MASK |
a8b23d
-                              Gdk.EventMask.BUTTON_RELEASE_MASK,
a8b23d
-                              null,
a8b23d
-                              Gdk.CURRENT_TIME);
a8b23d
-        if (status != Gdk.GrabStatus.SUCCESS)
a8b23d
-            warning("Grab pointer failed! status = %d", status);
a8b23d
+        } else {
a8b23d
+            // Grab all pointer events
a8b23d
+            status = pointer.grab(get_window(),
a8b23d
+                                  Gdk.GrabOwnership.NONE,
a8b23d
+                                  true,
a8b23d
+                                  Gdk.EventMask.BUTTON_PRESS_MASK |
a8b23d
+                                  Gdk.EventMask.BUTTON_RELEASE_MASK,
a8b23d
+                                  null,
a8b23d
+                                  Gdk.CURRENT_TIME);
a8b23d
+            if (status != Gdk.GrabStatus.SUCCESS)
a8b23d
+                warning("Grab pointer failed! status = %d", status);
a8b23d
+        }
a8b23d
 #endif
a8b23d
 
a8b23d
-        // Probably we can delete m_popup_delay_time in 1.6
a8b23d
-        pointer.get_position_double(null,
a8b23d
-                                    out m_mouse_init_x,
a8b23d
-                                    out m_mouse_init_y);
a8b23d
-        m_mouse_moved = false;
a8b23d
+        /* Fix RHBZ #1771238 assert(m_loop == null)
a8b23d
+         * Grabbing keyboard can be failed when the second Super-e is typed
a8b23d
+         * before Switcher dialog is focused. And m_loop could not be released
a8b23d
+         * if the failed Super-e would call m_loop.run() below and could not
a8b23d
+         * call key_release_event(). And m_loop == null would be false in the
a8b23d
+         * third Super-e.
a8b23d
+         */
a8b23d
+        if (status == Gdk.GrabStatus.SUCCESS) {
a8b23d
+            // Probably we can delete m_popup_delay_time in 1.6
a8b23d
+            pointer.get_position_double(null,
a8b23d
+                                        out m_mouse_init_x,
a8b23d
+                                        out m_mouse_init_y);
a8b23d
+            m_mouse_moved = false;
a8b23d
 
a8b23d
 
a8b23d
-        m_loop = new GLib.MainLoop();
a8b23d
-        m_loop.run();
a8b23d
-        m_loop = null;
a8b23d
+            m_loop = new GLib.MainLoop();
a8b23d
+            m_loop.run();
a8b23d
+            m_loop = null;
a8b23d
+        }
a8b23d
 
a8b23d
 #if VALA_0_34
a8b23d
         seat.ungrab();
a8b23d
-- 
a8b23d
2.24.1
a8b23d