From: Alexandros Frantzis alexandros.frantzis@collabora.com
In our setup with a dedicated event dispatch thread, libwayland ensures that object proxies associated with an event handler remain valid (or NULL) while the handler is executing. However, no such guarantees are given for the proxy user data. It is thus possible for the user data to become invalid (e.g., its memory freed from a different thread) right after the event handler is entered.
This is an issue for wayland_surface associated proxies since they may receive unsolicited events from the compositor at any time (e.g., xdg_surface.configure), even while we are destroying the wayland_surface.
To avoid the problem, we introduce a lock that protects access to xdg_surface user data and ensures that the associated wayland_surface remains valid for the duration of the handler.
Co-authored-by: RĂ©mi Bernon rbernon@codeweavers.com --- dlls/winewayland.drv/wayland_surface.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index addb2f7ed45..250efd1c6a8 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -32,18 +32,35 @@
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
+/* Protects access to the user data of xdg_surface */ +static pthread_mutex_t xdg_data_mutex = PTHREAD_MUTEX_INITIALIZER; + +static struct wayland_surface *wayland_surface_lock_xdg(struct xdg_surface *xdg_surface) +{ + struct wayland_surface *surface; + + pthread_mutex_lock(&xdg_data_mutex); + surface = xdg_surface_get_user_data(xdg_surface); + if (surface) pthread_mutex_lock(&surface->mutex); + pthread_mutex_unlock(&xdg_data_mutex); + + return surface; +} + static void xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { - struct wayland_surface *surface = data; + struct wayland_surface *surface;
TRACE("serial=%u\n", serial);
- pthread_mutex_lock(&surface->mutex); + if (!(surface = wayland_surface_lock_xdg(xdg_surface))) return; + /* Handle this event only if wayland_surface is still associated with * the target xdg_surface. */ if (surface->xdg_surface == xdg_surface) xdg_surface_ack_configure(xdg_surface, serial); + pthread_mutex_unlock(&surface->mutex); }
@@ -93,6 +110,7 @@ err: */ void wayland_surface_destroy(struct wayland_surface *surface) { + pthread_mutex_lock(&xdg_data_mutex); pthread_mutex_lock(&surface->mutex);
if (surface->xdg_toplevel) @@ -103,6 +121,7 @@ void wayland_surface_destroy(struct wayland_surface *surface)
if (surface->xdg_surface) { + xdg_surface_set_user_data(surface->xdg_surface, NULL); xdg_surface_destroy(surface->xdg_surface); surface->xdg_surface = NULL; } @@ -114,6 +133,7 @@ void wayland_surface_destroy(struct wayland_surface *surface) }
pthread_mutex_unlock(&surface->mutex); + pthread_mutex_unlock(&xdg_data_mutex);
wl_display_flush(process_wayland.wl_display);