summary refs log tree commit diff stats
path: root/src/common/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/plugin.c')
-rw-r--r--src/common/plugin.c78
1 files changed, 57 insertions, 21 deletions
diff --git a/src/common/plugin.c b/src/common/plugin.c
index 40e55bbf..f4691d73 100644
--- a/src/common/plugin.c
+++ b/src/common/plugin.c
@@ -491,7 +491,6 @@ plugin_auto_load (session *sess)
 	for_files (lib_dir, "hcfishlim.dll", plugin_auto_load_cb);
 	for_files(lib_dir, "hclua.dll", plugin_auto_load_cb);
 	for_files (lib_dir, "hcperl.dll", plugin_auto_load_cb);
-	for_files (lib_dir, "hcpython2.dll", plugin_auto_load_cb);
 	for_files (lib_dir, "hcpython3.dll", plugin_auto_load_cb);
 	for_files (lib_dir, "hcupd.dll", plugin_auto_load_cb);
 	for_files (lib_dir, "hcwinamp.dll", plugin_auto_load_cb);
@@ -572,12 +571,15 @@ plugin_hook_find (GSList *list, int type, char *name)
 
 static int
 plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
-				 hexchat_event_attrs *attrs, int type)
+				 hexchat_event_attrs *attrs, int type, int mask)
 {
+	/* fix segfault https://github.com/hexchat/hexchat/issues/2265 */
+	static int depth = 0;
 	GSList *list, *next;
 	hexchat_hook *hook;
 	int ret, eat = 0;
 
+	depth++;
 	list = hook_list;
 	while (1)
 	{
@@ -609,6 +611,11 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
 			break;
 		}
 
+		if ((ret & mask) != ret) {
+			g_critical("plugin tried to eat cleanup hooks");
+		}
+		ret &= mask;
+
 		if ((ret & HEXCHAT_EAT_HEXCHAT) && (ret & HEXCHAT_EAT_PLUGIN))
 		{
 			eat = 1;
@@ -623,18 +630,22 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
 	}
 
 xit:
-	/* really remove deleted hooks now */
-	list = hook_list;
-	while (list)
+	depth--;
+	if (!depth)
 	{
-		hook = list->data;
-		next = list->next;
-		if (!hook || hook->type == HOOK_DELETED)
+		/* really remove deleted hooks now */
+		list = hook_list;
+		while (list)
 		{
-			hook_list = g_slist_remove (hook_list, hook);
-			g_free (hook);
+			hook = list->data;
+			next = list->next;
+			if (!hook || hook->type == HOOK_DELETED)
+			{
+				hook_list = g_slist_remove (hook_list, hook);
+				g_free (hook);
+			}
+			list = next;
 		}
-		list = next;
 	}
 
 	return eat;
@@ -645,7 +656,7 @@ xit:
 int
 plugin_emit_command (session *sess, char *name, char *word[], char *word_eol[])
 {
-	return plugin_hook_run (sess, name, word, word_eol, NULL, HOOK_COMMAND);
+	return plugin_hook_run (sess, name, word, word_eol, NULL, HOOK_COMMAND, -1);
 }
 
 hexchat_event_attrs *
@@ -671,7 +682,7 @@ plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[],
 	attrs.server_time_utc = server_time;
 
 	return plugin_hook_run (sess, name, word, word_eol, &attrs, 
-							HOOK_SERVER | HOOK_SERVER_ATTRS);
+							HOOK_SERVER | HOOK_SERVER_ATTRS, -1);
 }
 
 /* see if any plugins are interested in this print event */
@@ -684,11 +695,23 @@ plugin_emit_print (session *sess, char *word[], time_t server_time)
 	attrs.server_time_utc = server_time;
 
 	return plugin_hook_run (sess, word[0], word, NULL, &attrs,
-							HOOK_PRINT | HOOK_PRINT_ATTRS);
+							HOOK_PRINT | HOOK_PRINT_ATTRS, -1);
+}
+
+/* used by plugin_emit_dummy_print to fix some UB */
+static void
+check_and_invalidate(void *plug_, void *killsess_)
+{
+	hexchat_plugin *plug = plug_;
+	session *killsess = killsess_;
+	if (plug->context == killsess)
+	{
+		plug->context = NULL;
+	}
 }
 
 int
-plugin_emit_dummy_print (session *sess, char *name)
+plugin_emit_dummy_print (session *sess, char *name, int mask)
 {
 	char *word[PDIWORDS];
 	int i;
@@ -697,7 +720,16 @@ plugin_emit_dummy_print (session *sess, char *name)
 	for (i = 1; i < PDIWORDS; i++)
 		word[i] = "\000";
 
-	return plugin_hook_run (sess, name, word, NULL, NULL, HOOK_PRINT);
+	i = plugin_hook_run (sess, name, word, NULL, NULL, HOOK_PRINT, mask);
+
+	/* shoehorned fix for Undefined Behaviour */
+	/* see https://stackoverflow.com/q/52628773/3691554 */
+	/* this needs to be done on the hexchat side */
+	if (strcmp(name, "Close Context") == 0) {
+		g_slist_foreach(plugin_list, &check_and_invalidate, sess);
+	}
+
+	return i;
 }
 
 int
@@ -730,7 +762,7 @@ plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, gu
 	for (i = 5; i < PDIWORDS; i++)
 		word[i] = "\000";
 
-	return plugin_hook_run (sess, word[0], word, NULL, NULL, HOOK_PRINT);
+	return plugin_hook_run (sess, word[0], word, NULL, NULL, HOOK_PRINT, -1);
 }
 
 static int
@@ -1121,12 +1153,16 @@ hexchat_get_context (hexchat_plugin *ph)
 int
 hexchat_set_context (hexchat_plugin *ph, hexchat_context *context)
 {
-	if (is_session (context))
+	if (context == NULL) {
+		return 0;
+	}
+	if (!is_session (context))
 	{
-		ph->context = context;
-		return 1;
+		g_critical("plugin tried to set an invalid context");
+		return 0;
 	}
-	return 0;
+	ph->context = context;
+	return 1;
 }
 
 hexchat_context *