xserver: Branch 'server-1.19-branch' - 2 commits

Adam Jackson ajax at kemper.freedesktop.org
Wed Mar 15 17:24:53 UTC 2017


 hw/xwayland/xwayland-cursor.c |   14 ++++++++-
 hw/xwayland/xwayland-glamor.c |   60 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 64 insertions(+), 10 deletions(-)

New commits:
commit 18fcb66688057f5676952e2535d4bb9942371199
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Mar 2 10:19:26 2017 +0100

    xwayland: Monitor client states to destroy callbacks
    
    In XWayland, dri3_send_open_reply() is called from a sync callback, so
    there is a possibility that the client might be gone when we get to the
    callback eventually, which leads to a crash in _XSERVTransSendFd() from
    WriteFdToClient() .
    
    Client resources can survive the client itself, in which case we
    may end up in our sync callback trying to access client's data after
    it's been freed/reclaimed.
    
    Add a ClientStateCallback handler to monitor the client state changes
    and clear the sync callback set up by the glamor drm code if any.
    
    Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1416553
    Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=100040
    Tested-by: Mark B <mark.blakeney at bullet-systems.net>
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <michel.daenzer at amd.com>
    (cherry picked from commit 937527f9798d573ec82c2c508821899c229c018f)

diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index b3d0aab..63f2303 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -38,6 +38,8 @@
 #include <dri3.h>
 #include "drm-client-protocol.h"
 
+static DevPrivateKeyRec xwl_auth_state_private_key;
+
 struct xwl_pixmap {
     struct wl_buffer *buffer;
     struct gbm_bo *bo;
@@ -429,17 +431,49 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
 struct xwl_auth_state {
     int fd;
     ClientPtr client;
+    struct wl_callback *callback;
 };
 
 static void
+free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state)
+{
+    dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL);
+    if (state) {
+        wl_callback_destroy(state->callback);
+        free(state);
+    }
+}
+
+static void
+xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data)
+{
+    NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
+    ClientPtr pClient = clientinfo->client;
+    struct xwl_auth_state *state;
+
+    switch (pClient->clientState) {
+    case ClientStateGone:
+    case ClientStateRetained:
+        state = dixLookupPrivate(&pClient->devPrivates, &xwl_auth_state_private_key);
+        free_xwl_auth_state(pClient, state);
+        break;
+    default:
+        break;
+    }
+}
+
+static void
 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
 {
     struct xwl_auth_state *state = data;
-
-    dri3_send_open_reply(state->client, state->fd);
-    AttendClient(state->client);
-    free(state);
-    wl_callback_destroy(callback);
+    ClientPtr client = state->client;
+
+    /* if the client is gone, the callback is cancelled so it's safe to
+     * assume the client is still in ClientStateRunning at this point...
+     */
+    dri3_send_open_reply(client, state->fd);
+    AttendClient(client);
+    free_xwl_auth_state(client, state);
 }
 
 static const struct wl_callback_listener sync_listener = {
@@ -454,7 +488,6 @@ xwl_dri3_open_client(ClientPtr client,
 {
     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
     struct xwl_auth_state *state;
-    struct wl_callback *callback;
     drm_magic_t magic;
     int fd;
 
@@ -482,8 +515,9 @@ xwl_dri3_open_client(ClientPtr client,
     }
 
     wl_drm_authenticate(xwl_screen->drm, magic);
-    callback = wl_display_sync(xwl_screen->display);
-    wl_callback_add_listener(callback, &sync_listener, state);
+    state->callback = wl_display_sync(xwl_screen->display);
+    wl_callback_add_listener(state->callback, &sync_listener, state);
+    dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state);
 
     IgnoreClient(client);
 
@@ -565,6 +599,16 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
         return FALSE;
     }
 
+    if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT, 0)) {
+        ErrorF("Failed to register private key\n");
+        return FALSE;
+    }
+
+    if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback, NULL)) {
+        ErrorF("Failed to add client state callback\n");
+        return FALSE;
+    }
+
     xwl_screen->CreateScreenResources = screen->CreateScreenResources;
     screen->CreateScreenResources = xwl_glamor_create_screen_resources;
     screen->CreatePixmap = xwl_glamor_create_pixmap;
commit d402b86b4561eb2580421de91d977a35abe88190
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Mar 7 10:28:35 2017 +0100

    xwayland: clear cursor frame callback
    
    After an X cursor is unrealized, the seat's corresponding x_cursor is
    cleared, but if a frame callback was pending at the time, it will
    remain and thus prevent any further cursor update, leaving the window
    with no cursor.
    
    Make sure to destroy the frame callback, if any, when that occurs, so
    that next time a cursor needs to be set, it won't be ignored for a frame
    callback that will never be triggered.
    
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1389327
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
    Reviewed-by: Rui Matos <tiagomatos at gmail.com>
    (cherry picked from commit d4b7e0eaa4b2e97ce1dec653a2ae7d9621fe1431)

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index 0c1cd34..f334f1c 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -96,14 +96,22 @@ xwl_unrealize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor)
 }
 
 static void
+clear_cursor_frame_callback(struct xwl_seat *xwl_seat)
+{
+   if (xwl_seat->cursor_frame_cb) {
+       wl_callback_destroy (xwl_seat->cursor_frame_cb);
+       xwl_seat->cursor_frame_cb = NULL;
+   }
+}
+
+static void
 frame_callback(void *data,
                struct wl_callback *callback,
                uint32_t time)
 {
     struct xwl_seat *xwl_seat = data;
 
-    wl_callback_destroy (xwl_seat->cursor_frame_cb);
-    xwl_seat->cursor_frame_cb = NULL;
+    clear_cursor_frame_callback(xwl_seat);
     if (xwl_seat->cursor_needs_update) {
         xwl_seat->cursor_needs_update = FALSE;
         xwl_seat_set_cursor(xwl_seat);
@@ -127,6 +135,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
     if (!xwl_seat->x_cursor) {
         wl_pointer_set_cursor(xwl_seat->wl_pointer,
                               xwl_seat->pointer_enter_serial, NULL, 0, 0);
+        clear_cursor_frame_callback(xwl_seat);
+        xwl_seat->cursor_needs_update = FALSE;
         return;
     }
 


More information about the xorg-commit mailing list