summary refs log tree commit diff stats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/hexchat.c6
-rw-r--r--src/common/plugin.c77
-rw-r--r--src/common/plugin.h2
3 files changed, 61 insertions, 24 deletions
diff --git a/src/common/hexchat.c b/src/common/hexchat.c
index 3ba7ed6d..f74fe489 100644
--- a/src/common/hexchat.c
+++ b/src/common/hexchat.c
@@ -183,7 +183,7 @@ lastact_getfirst(int (*filter) (session *sess))
 int
 is_session (session * sess)
 {
-	return g_slist_find (sess_list, sess) ? 1 : 0;
+	return sess != NULL && (g_slist_find (sess_list, sess) ? 1 : 0);
 }
 
 session *
@@ -552,7 +552,7 @@ new_ircwindow (server *serv, char *name, int type, int focus)
 		if (user && user->hostname)
 			set_topic (sess, user->hostname, user->hostname);
 	}
-	plugin_emit_dummy_print (sess, "Open Context");
+	plugin_emit_dummy_print (sess, "Open Context", -1);
 
 	return sess;
 }
@@ -629,7 +629,7 @@ session_free (session *killsess)
 	GSList *list;
 	int oldidx;
 
-	plugin_emit_dummy_print (killsess, "Close Context");
+	plugin_emit_dummy_print (killsess, "Close Context", 0);
 
 	if (current_tab == killsess)
 		current_tab = NULL;
diff --git a/src/common/plugin.c b/src/common/plugin.c
index 536f376d..f4691d73 100644
--- a/src/common/plugin.c
+++ b/src/common/plugin.c
@@ -571,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)
 	{
@@ -608,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;
@@ -622,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;
@@ -644,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 *
@@ -670,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 */
@@ -683,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;
@@ -696,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
@@ -729,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
@@ -1120,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 *
diff --git a/src/common/plugin.h b/src/common/plugin.h
index fb7da831..051d1f5a 100644
--- a/src/common/plugin.h
+++ b/src/common/plugin.h
@@ -174,7 +174,7 @@ int plugin_emit_command (session *sess, char *name, char *word[], char *word_eol
 int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[],
 						time_t server_time);
 int plugin_emit_print (session *sess, char *word[], time_t server_time);
-int plugin_emit_dummy_print (session *sess, char *name);
+int plugin_emit_dummy_print (session *sess, char *name, int mask);
 int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, gunichar key);
 GList* plugin_command_list(GList *tmp_list);
 int plugin_show_help (session *sess, char *cmd);