From e37b321a8262f43c78c07acf3a19d1c9585bbff3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 28 Aug 2024 14:50:49 +0200 Subject: [PATCH] server: fix abort when terminating display on wl_event_loop destroy The destruction of wl_event_loop may trigger a call to wl_display_terminate() in user code. This would fail with EBADF because we close terminate_efd earlier in wl_display_destroy(). Close the FD after wl_event_loop_destroy() to avoid this issue. Add a test for this behavior. Signed-off-by: Simon Ser --- src/wayland-server.c | 3 ++- tests/display-test.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/wayland-server.c b/src/wayland-server.c index 1d6be3ec..e77b0e8f 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -1267,11 +1267,12 @@ wl_display_destroy(struct wl_display *display) wl_socket_destroy(s); } - close(display->terminate_efd); wl_event_source_remove(display->term_source); wl_event_loop_destroy(display->loop); + close(display->terminate_efd); + wl_list_for_each_safe(global, gnext, &display->global_list, link) free(global); diff --git a/tests/display-test.c b/tests/display-test.c index c2def444..f43340fc 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1715,3 +1715,32 @@ TEST(no_source_terminate) display_run(d); display_destroy(d); } + +struct terminate_on_event_loop_destroy_data { + struct wl_display *display; + struct wl_listener loop_destroy_listener; +}; + +static void +handle_event_loop_destroy(struct wl_listener *listener, void *user_data) +{ + struct terminate_on_event_loop_destroy_data *data = + wl_container_of(listener, data, loop_destroy_listener); + wl_display_terminate(data->display); +} + +TEST(terminate_on_event_loop_destroy) +{ + struct display *d; + struct wl_event_loop *loop; + struct terminate_on_event_loop_destroy_data data; + + d = display_create(); + loop = wl_display_get_event_loop(d->wl_display); + + data.display = d->wl_display; + data.loop_destroy_listener.notify = handle_event_loop_destroy; + wl_event_loop_add_destroy_listener(loop, &data.loop_destroy_listener); + + display_destroy(d); +}