From 6116702dd2331b8604c1b2360a64358e307ad4cf Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Nov 2023 13:19:28 +0100 Subject: [PATCH] Only handle MAM response if window still exists Before this patch the following scenario lead to a segfault: 1. open a window that sends a MAM request 2. fast enough close that window again before the MAM response was processed Once the MAM response is received we'd call `_mam_rsm_id_handler()` from the `_iq_handler()` and `window` would point to a non-existant window which leads to a segfault. Signed-off-by: Steffen Jaeckel --- src/ui/core.c | 2 ++ src/xmpp/iq.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ src/xmpp/xmpp.h | 1 + 3 files changed, 55 insertions(+) diff --git a/src/ui/core.c b/src/ui/core.c index 24e15eba0..39535eaad 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -712,6 +712,8 @@ ui_close_win(int index) } } + // remove the IQ handlers + iq_handlers_remove_win(window); wins_close_by_num(index); title_bar_console(); status_bar_current(1); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 793dbc597..924c98be7 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -267,6 +267,54 @@ iq_handlers_init(void) rooms_cache = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)xmpp_stanza_release); } +struct iq_win_finder +{ + gsize max, cur; + char** to_be_removed; +}; + +static void +_win_find(char* key, + ProfIqHandler* handler, + struct iq_win_finder* finder) +{ + if (handler->func == _mam_rsm_id_handler) { + if (finder->cur >= finder->max) { + finder->max *= 2; + finder->to_be_removed = g_realloc_n(finder->to_be_removed, finder->max, sizeof(char*)); + } + finder->to_be_removed[finder->cur++] = g_strdup(key); + } +} + +void +iq_handlers_remove_win(ProfWin* window) +{ + log_debug("Remove window %p of type %d", window, window ? window->type : -1); + if (!window) + return; + GSList *cur = late_delivery_windows, *next; + while (cur) { + LateDeliveryUserdata* del_data = cur->data; + next = g_slist_next(cur); + if (del_data->win == (void*)window) + late_delivery_windows = g_slist_delete_link(late_delivery_windows, + cur); + cur = next; + } + struct iq_win_finder st = { 0 }; + st.max = g_hash_table_size(id_handlers); + if (st.max == 0) + return; + st.to_be_removed = g_new(char*, st.max); + g_hash_table_foreach(id_handlers, (GHFunc)_win_find, &st); + for (gsize n = 0; n < st.cur; ++n) { + g_hash_table_remove(id_handlers, st.to_be_removed[n]); + g_free(st.to_be_removed[n]); + } + g_free(st.to_be_removed); +} + void iq_handlers_clear() { @@ -2696,6 +2744,10 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) gboolean is_complete = g_strcmp0(xmpp_stanza_get_attribute(fin, "complete"), "true") == 0; MamRsmUserdata* data = (MamRsmUserdata*)userdata; ProfWin* window = (ProfWin*)data->win; + if (wins_get_num(window) == -1) { + log_error("Window %p should not get any events anymore", window); + return 0; + } buffer_remove_entry(window->layout->buffer, 0); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index baff12958..23b207299 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -240,6 +240,7 @@ void iq_enable_carbons(void); void iq_disable_carbons(void); void iq_send_software_version(const char* const fulljid); void iq_rooms_cache_clear(void); +void iq_handlers_remove_win(ProfWin* window); void iq_handlers_clear(); void iq_room_list_request(gchar* conferencejid, gchar* filter); void iq_disco_info_request(gchar* jid);