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 <contact@emersion.fr>
This commit is contained in:
Simon Ser 2024-08-28 14:50:49 +02:00
parent 6c4a695045
commit e37b321a82
2 changed files with 31 additions and 1 deletions

View file

@ -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);

View file

@ -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);
}