diff options
author | Simon Ser <contact@emersion.fr> | 2022-06-07 18:18:11 +0200 |
---|---|---|
committer | Simon Ser <contact@emersion.fr> | 2022-06-07 18:18:11 +0200 |
commit | b89ed9015c3fbe8d339e9d65cf70fdca6e5645bc (patch) | |
tree | 68c680b39d6f18d19d20ae1ebf0fba0e90d0bacb /util | |
parent | 09498499f6e830e70883ef158de16523d4b08c6f (diff) |
util/global: fix memory leak on display destroy in wlr_global_destroy_safe
If the display is destroyed before wlr_global_destroy_safe's timer
fires, the struct destroy_global_data is leaked. This shouldn't cause
issues in practice because the timer will never fire, but makes it
harder to spot compositor memory leaks.
Diffstat (limited to 'util')
-rw-r--r-- | util/global.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/util/global.c b/util/global.c index fa99a994..93636a89 100644 --- a/util/global.c +++ b/util/global.c @@ -4,16 +4,27 @@ struct destroy_global_data { struct wl_global *global; struct wl_event_source *event_source; + struct wl_listener display_destroy; }; -static int destroy_global(void *_data) { - struct destroy_global_data *data = _data; +static void destroy_global(struct destroy_global_data *data) { + wl_list_remove(&data->display_destroy.link); wl_global_destroy(data->global); wl_event_source_remove(data->event_source); free(data); +} + +static int handle_timer_event(void *data) { + destroy_global(data); return 0; } +static void handle_display_destroy(struct wl_listener *listener, void *_data) { + struct destroy_global_data *data = + wl_container_of(listener, data, display_destroy); + destroy_global(data); +} + void wlr_global_destroy_safe(struct wl_global *global) { // Don't destroy the global immediately. If the global has been created // recently, clients might try to bind to it after we've destroyed it. @@ -33,11 +44,14 @@ void wlr_global_destroy_safe(struct wl_global *global) { } data->global = global; data->event_source = - wl_event_loop_add_timer(event_loop, destroy_global, data); + wl_event_loop_add_timer(event_loop, handle_timer_event, data); if (data->event_source == NULL) { free(data); wl_global_destroy(global); return; } wl_event_source_timer_update(data->event_source, 5000); + + data->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &data->display_destroy); } |