[libpeas] Load C plugins with local linkage



commit 3ee92ca98b095bbd840f4c7b10df8939fe246484
Author: Thomas Martitz <kugel rockbox org>
Date:   Thu Dec 18 05:03:30 2014 -0800

    Load C plugins with local linkage
    
    C extensions can bring arbitrary symbols into the global symbol table
    which is then shared with all other extensions and the main binary.
    This is a recipe for symbol clashes which are hard to debug. Using
    G_MODULE_BIND_LOCAL provides proper isolation and makes
    applications more robust.
    
    Based on a patch by Thomas Martitz
    
    https://bugzilla.gnome.org/show_bug.cgi?id=740823

 docs/reference/libpeas-sections.txt |    1 +
 libpeas/peas-engine.c               |    6 +++-
 libpeas/peas-object-module.c        |   62 ++++++++++++++++++++++++++++++++--
 libpeas/peas-object-module.h        |    4 ++
 libpeas/peas-plugin-loader-c.c      |    8 +++--
 5 files changed, 73 insertions(+), 8 deletions(-)
---
diff --git a/docs/reference/libpeas-sections.txt b/docs/reference/libpeas-sections.txt
index 173777d..ff80d31 100644
--- a/docs/reference/libpeas-sections.txt
+++ b/docs/reference/libpeas-sections.txt
@@ -151,6 +151,7 @@ PEAS_OBJECT_MODULE_GET_CLASS
 <SUBSECTION Private>
 PeasObjectModulePrivate
 peas_object_module_new
+peas_object_module_new_full
 peas_object_module_create_object
 peas_object_module_get_library
 peas_object_module_get_module_name
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c
index 11a3774..7934adc 100644
--- a/libpeas/peas-engine.c
+++ b/libpeas/peas-engine.c
@@ -642,7 +642,11 @@ load_module (const gchar *module_name,
 {
   PeasObjectModule *module;
 
-  module = peas_object_module_new (module_name, module_dir, TRUE);
+  /* Bind loaders globally, binding
+   * locally can break the plugin loaders
+   */
+  module = peas_object_module_new_full (module_name, module_dir,
+                                        TRUE, FALSE);
 
   if (!g_type_module_use (G_TYPE_MODULE (module)))
     g_clear_object (&module);
diff --git a/libpeas/peas-object-module.c b/libpeas/peas-object-module.c
index c74152e..b556575 100644
--- a/libpeas/peas-object-module.c
+++ b/libpeas/peas-object-module.c
@@ -51,6 +51,7 @@ enum {
   PROP_MODULE_NAME,
   PROP_PATH,
   PROP_RESIDENT,
+  PROP_LOCAL_LINKAGE,
   N_PROPERTIES
 };
 
@@ -73,14 +74,19 @@ struct _PeasObjectModulePrivate {
   gchar *module_name;
 
   guint resident : 1;
+  guint local_linkage : 1;
 };
 
 static gboolean
 peas_object_module_load (GTypeModule *gmodule)
 {
   PeasObjectModule *module = PEAS_OBJECT_MODULE (gmodule);
+  GModuleFlags flags = 0;
   gchar *path;
 
+  if (module->priv->local_linkage)
+    flags = G_MODULE_BIND_LOCAL;
+
   path = g_module_build_path (module->priv->path, module->priv->module_name);
   g_return_val_if_fail (path != NULL, FALSE);
 
@@ -92,10 +98,8 @@ peas_object_module_load (GTypeModule *gmodule)
   if (G_MODULE_SUFFIX[0] != '\0' && g_str_has_suffix (path, "." G_MODULE_SUFFIX))
     path[strlen (path) - strlen (G_MODULE_SUFFIX) - 1] = '\0';
 
-  /* Bind symbols globally and immediately,
-   * binding locally broke the Python plugin loader.
-   */
-  module->priv->library = g_module_open (path, 0);
+  /* Bind symbols immediately to avoid errors long after loading */
+  module->priv->library = g_module_open (path, flags);
   g_free (path);
 
   if (module->priv->library == NULL)
@@ -195,6 +199,9 @@ peas_object_module_get_property (GObject    *object,
     case PROP_RESIDENT:
       g_value_set_boolean (value, module->priv->resident);
       break;
+    case PROP_LOCAL_LINKAGE:
+      g_value_set_boolean (value, module->priv->local_linkage);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -222,6 +229,9 @@ peas_object_module_set_property (GObject      *object,
     case PROP_RESIDENT:
       module->priv->resident = g_value_get_boolean (value);
       break;
+    case PROP_LOCAL_LINKAGE:
+      module->priv->local_linkage = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -268,6 +278,23 @@ peas_object_module_class_init (PeasObjectModuleClass *klass)
                           G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS);
 
+  /**
+   * PeasObjectModule:local-linkage
+   *
+   * This property indicates whether the module is loaded with
+   * local linkage, i.e. #G_MODULE_BIND_LOCAL.
+   *
+   * Since 1.14
+   */
+  properties[PROP_LOCAL_LINKAGE] =
+    g_param_spec_boolean ("local-linkage",
+                          "Local linkage",
+                          "Whether the module loaded with local linkage",
+                          FALSE,
+                          G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
   g_type_class_add_private (klass, sizeof (PeasObjectModulePrivate));
 }
@@ -295,6 +322,33 @@ peas_object_module_new (const gchar *module_name,
 }
 
 /**
+ * peas_object_module_new_full: (skip)
+ * @module_name: The module name.
+ * @path: The path.
+ * @resident: If the module should be resident.
+ * @local_linkage: Whether to load the module with local linkage.
+ *
+ * Creates a new #PeasObjectModule with local linkage.
+ *
+ * Return value: a new #PeasObjectModule.
+ *
+ * Since 1.14
+ */
+PeasObjectModule *
+peas_object_module_new_full (const gchar *module_name,
+                             const gchar *path,
+                             gboolean     resident,
+                             gboolean     local_linkage)
+{
+  return PEAS_OBJECT_MODULE (g_object_new (PEAS_TYPE_OBJECT_MODULE,
+                                           "module-name", module_name,
+                                           "path", path,
+                                           "resident", resident,
+                                           "local-linkage", local_linkage,
+                                           NULL));
+}
+
+/**
  * peas_object_module_create_object: (skip)
  * @module: A #PeasObjectModule.
  * @interface: The #GType of the extension interface.
diff --git a/libpeas/peas-object-module.h b/libpeas/peas-object-module.h
index 9cd599e..7ddf4f6 100644
--- a/libpeas/peas-object-module.h
+++ b/libpeas/peas-object-module.h
@@ -87,6 +87,10 @@ GType               peas_object_module_get_type               (void) G_GNUC_CONS
 PeasObjectModule   *peas_object_module_new                    (const gchar      *module_name,
                                                                const gchar      *path,
                                                                gboolean          resident);
+PeasObjectModule   *peas_object_module_new_full               (const gchar      *module_name,
+                                                               const gchar      *path,
+                                                               gboolean          resident,
+                                                               gboolean          local_linkage);
 
 GObject            *peas_object_module_create_object          (PeasObjectModule *module,
                                                                GType             interface,
diff --git a/libpeas/peas-plugin-loader-c.c b/libpeas/peas-plugin-loader-c.c
index 1ac9266..b0e8417 100644
--- a/libpeas/peas-plugin-loader-c.c
+++ b/libpeas/peas-plugin-loader-c.c
@@ -60,10 +60,12 @@ peas_plugin_loader_c_load (PeasPluginLoader *loader,
       module_dir = peas_plugin_info_get_module_dir (info);
 
       /* Force all C modules to be resident in case they
-       * use libraries that do not deal well with reloading
+       * use libraries that do not deal well with reloading.
+       * Furthermore, we use local linkage to improve module isolation.
        */
-      info->loader_data = peas_object_module_new (module_name,
-                                                  module_dir, TRUE);
+      info->loader_data = peas_object_module_new_full (module_name,
+                                                       module_dir,
+                                                       TRUE, TRUE);
 
       if (!g_type_module_use (G_TYPE_MODULE (info->loader_data)))
         g_clear_object (&info->loader_data);


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