[geany/geany] 8f7133: Merge branch '1.25/safer-plugin_signal_connect'

Colomban Wendling git-noreply at xxxxx
Sun Apr 13 18:07:26 UTC 2014


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Sun, 13 Apr 2014 18:07:26 UTC
Commit:      8f713377c403e6b0368ff1aae918876f756c1564
             https://github.com/geany/geany/commit/8f713377c403e6b0368ff1aae918876f756c1564

Log Message:
-----------
Merge branch '1.25/safer-plugin_signal_connect'


Modified Paths:
--------------
    src/plugindata.h
    src/pluginprivate.h
    src/plugins.c
    src/pluginutils.c

Modified: src/plugindata.h
2 files changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -55,7 +55,7 @@ G_BEGIN_DECLS
  * @warning You should not test for values below 200 as previously
  * @c GEANY_API_VERSION was defined as an enum value, not a macro.
  */
-#define GEANY_API_VERSION 217
+#define GEANY_API_VERSION 218
 
 /* hack to have a different ABI when built with GTK3 because loading GTK2-linked plugins
  * with GTK3-linked Geany leads to crash */


Modified: src/pluginprivate.h
3 files changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -61,4 +61,7 @@ GeanyPluginPrivate;
 typedef GeanyPluginPrivate Plugin;	/* shorter alias */
 
 
+void plugin_watch_object(Plugin *plugin, gpointer object);
+
+
 #endif /* GEANY_PLUGINPRIVATE_H */


Modified: src/plugins.c
34 files changed, 34 insertions(+), 0 deletions(-)
===================================================================
@@ -769,6 +769,37 @@ plugin_new(const gchar *fname, gboolean init_plugin, gboolean add_to_list)
 }
 
 
+static void on_object_weak_notify(gpointer data, GObject *old_ptr)
+{
+	Plugin *plugin = data;
+	guint i = 0;
+
+	g_return_if_fail(plugin && plugin->signal_ids);
+
+	for (i = 0; i < plugin->signal_ids->len; i++)
+	{
+		SignalConnection *sc = &g_array_index(plugin->signal_ids, SignalConnection, i);
+
+		if (sc->object == old_ptr)
+		{
+			g_array_remove_index_fast(plugin->signal_ids, i);
+			/* we can break the loop right after finding the first match,
+			 * because we will get one notification per connected signal */
+			break;
+		}
+	}
+}
+
+
+/* add an object to watch for destruction, and release pointers to it when destroyed.
+ * this should only be used by plugin_signal_connect() to add a watch on
+ * the object lifetime and nuke out references to it in plugin->signal_ids */
+void plugin_watch_object(Plugin *plugin, gpointer object)
+{
+	g_object_weak_ref(object, on_object_weak_notify, plugin);
+}
+
+
 static void remove_callbacks(Plugin *plugin)
 {
 	GArray *signal_ids = plugin->signal_ids;
@@ -778,7 +809,10 @@ static void remove_callbacks(Plugin *plugin)
 		return;
 
 	foreach_array(SignalConnection, sc, signal_ids)
+	{
 		g_signal_handler_disconnect(sc->object, sc->handler_id);
+		g_object_weak_unref(sc->object, on_object_weak_notify, plugin);
+	}
 
 	g_array_free(signal_ids, TRUE);
 }


Modified: src/pluginutils.c
14 files changed, 12 insertions(+), 2 deletions(-)
===================================================================
@@ -105,7 +105,8 @@ void plugin_module_make_resident(GeanyPlugin *plugin)
  * @param user_data The user data passed to the signal handler.
  * @see plugin_callbacks.
  *
- * @warning This should only be used on objects that outlive the plugin, never on
+ * @warning Before version 1.25 (API < 218),
+ *          this should only be used on objects that outlive the plugin, never on
  *          objects that will get destroyed before the plugin is unloaded.  For objects
  *          created and destroyed by the plugin, you can simply use @c g_signal_connect(),
  *          since all handlers are disconnected when the object is destroyed anyway.
@@ -116,7 +117,10 @@ void plugin_module_make_resident(GeanyPlugin *plugin)
  *          disconnect the signal on @c plugin_cleanup()), and when the object is destroyed
  *          during the plugin's lifetime (in which case you cannot and should not disconnect
  *          manually in @c plugin_cleanup() since it already has been disconnected and the
- *          object has been destroyed), and disconnect yourself or not as appropriate. */
+ *          object has been destroyed), and disconnect yourself or not as appropriate.
+ * @note Since version 1.25 (API >= 218), the object lifetime is watched and so the above
+ *       restriction does not apply.  However, for objects destroyed by the plugin,
+ *       @c g_signal_connect() is safe and has lower overhead. */
 void plugin_signal_connect(GeanyPlugin *plugin,
 		GObject *object, const gchar *signal_name, gboolean after,
 		GCallback callback, gpointer user_data)
@@ -124,6 +128,9 @@ void plugin_signal_connect(GeanyPlugin *plugin,
 	gulong id;
 	SignalConnection sc;
 
+	g_return_if_fail(plugin != NULL);
+	g_return_if_fail(object == NULL || G_IS_OBJECT(object));
+
 	if (!object)
 		object = geany_object;
 
@@ -137,6 +144,9 @@ void plugin_signal_connect(GeanyPlugin *plugin,
 	sc.object = object;
 	sc.handler_id = id;
 	g_array_append_val(plugin->priv->signal_ids, sc);
+
+	/* watch the object lifetime to nuke our pointers to it */
+	plugin_watch_object(plugin->priv, object);
 }
 
 



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list