xserver: Branch 'server-1.20-branch' - 11 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jan 10 08:16:57 UTC 2019


 hw/xwayland/xwayland-glamor-gbm.c |    6 +
 hw/xwayland/xwayland-present.c    |  163 ++++++++++++++++++++------------------
 hw/xwayland/xwayland.c            |   22 +++--
 hw/xwayland/xwayland.h            |    6 +
 present/present_wnmd.c            |    2 
 5 files changed, 117 insertions(+), 82 deletions(-)

New commits:
commit a352f979545723054b0a74862a56dc53b1be93fb
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Jan 8 12:48:53 2019 +0100

    xwayland: handle case without any crtc
    
    Xwayland creates and destroys the CRTC along with the Wayland outputs,
    so there is possibly a case where the number of CRTC drops to 0.
    
    However, `xwl_present_get_crtc()` always return `crtcs[0]` which is
    invalid when `numCrtcs` is 0.
    
    That leads to crash if a client queries the Present capabilities when
    there is no CRTC, the backtrace looks like:
    
      #0  raise() from libc.so
      #1  abort() from libc.so
      #2  OsAbort() at utils.c:1350
      #3  AbortServer() at log.c:879
      #4  FatalError() at log.c:1017
      #5  OsSigHandler() at osinit.c:156
      #6  OsSigHandler() at osinit.c:110
      #7  <signal handler called>
      #8  main_arena() from libc.so
      #9  proc_present_query_capabilities() at present_request.c:236
      #10 Dispatch() at dispatch.c:478
      #11 dix_main() at main.c:276
    
    To avoid returning an invalid pointer (`crtcs[0]`) in that case, simply
    check for `numCrtcs` being 0 and return `NULL` in that case.
    
    Thanks to Michel Dänzer <michel.daenzer at amd.com> for pointing this as a
    possible cause of the crash.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <michel.daenzer at amd.com>
    Bugzilla: https://bugzilla.redhat.com/1609181
    (cherry picked from commit e8295c50209f2963fa2823e8de7e8363a38cd2d1)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 980034db4..74fe84672 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -323,6 +323,10 @@ xwl_present_get_crtc(WindowPtr present_window)
         return NULL;
 
     rr_private = rrGetScrPriv(present_window->drawable.pScreen);
+
+    if (rr_private->numCrtcs == 0)
+        return NULL;
+
     return rr_private->crtcs[0];
 }
 
commit 210cd529064348de7d4f9a9050b0cf68f8fd326c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Nov 15 17:16:59 2018 +0100

    xwayland: Don't take buffer release queue into account for frame timer
    
    The buffer release queue has two kinds of entries:
    
    * Pending async flips.
    * Completed flips waiting for their buffer to be released by the Wayland
      compositor.
    
    xwl_present_timer_callback neither completes async flips nor releases
    buffers, so the timer isn't needed for the buffer release queue.
    
    (cherry picked from commit e6cd1c9bdefe83e7d99b703a68d26eebb451f889)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 4ce8087d0..980034db4 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -86,8 +86,7 @@ static inline Bool
 xwl_present_has_events(struct xwl_present_window *xwl_present_window)
 {
     return !!xwl_present_window->sync_flip ||
-           !xorg_list_is_empty(&xwl_present_window->event_list) ||
-           !xorg_list_is_empty(&xwl_present_window->release_queue);
+           !xorg_list_is_empty(&xwl_present_window->event_list);
 }
 
 static void
commit 7c28b0e34ecbe9842193733dfd86097c06921406
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Nov 9 17:18:53 2018 +0100

    xwayland: Don't need xwl_window anymore in xwl_present_queue_vblank
    
    Fixes issue #12. Presumably the problem was that Present operations on
    unmapped windows were executed immediately instead of only when reaching
    the target MSC.
    
    (cherry picked from commit f541615342ce6bfb0e6d4e68deb3a924a87e8ba9)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 51ba5888b..4ce8087d0 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -350,13 +350,9 @@ xwl_present_queue_vblank(WindowPtr present_window,
                          uint64_t event_id,
                          uint64_t msc)
 {
-    struct xwl_window *xwl_window = xwl_window_from_window(present_window);
     struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
     struct xwl_present_event *event;
 
-    if (!xwl_window)
-        return BadMatch;
-
     event = malloc(sizeof *event);
     if (!event)
         return BadAlloc;
commit 46135957095ec954e21107d1001452e9533ef2ee
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Nov 1 18:24:28 2018 +0100

    xwayland: Add xwl_present_unrealize_window
    
    When a window is unrealized, a pending frame callback may never be
    called, which could result in repeatedly freezing until the frame timer
    fires after a second.
    
    Fixes these symptoms when switching from fullscreen to windowed mode in
    sauerbraten.
    
    (cherry picked from commit 8c9538573cb9a342897eb3fb4b0c1e4ed917bd0e)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 8a87e5df6..51ba5888b 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -524,6 +524,22 @@ xwl_present_flips_stop(WindowPtr window)
     xwl_present_reset_timer(xwl_present_window);
 }
 
+void
+xwl_present_unrealize_window(WindowPtr window)
+{
+    struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
+
+    if (!xwl_present_window || !xwl_present_window->frame_callback)
+        return;
+
+    /* The pending frame callback may never be called, so drop it and shorten
+     * the frame timer interval.
+     */
+    wl_callback_destroy(xwl_present_window->frame_callback);
+    xwl_present_window->frame_callback = NULL;
+    xwl_present_reset_timer(xwl_present_window);
+}
+
 static present_wnmd_info_rec xwl_present_info = {
     .version = PRESENT_SCREEN_INFO_VERSION,
     .get_crtc = xwl_present_get_crtc,
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 988b8e17d..7e6e0ab25 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -609,6 +609,11 @@ xwl_unrealize_window(WindowPtr window)
     xwl_screen->UnrealizeWindow = screen->UnrealizeWindow;
     screen->UnrealizeWindow = xwl_unrealize_window;
 
+#ifdef GLAMOR_HAS_GBM
+    if (xwl_screen->present)
+        xwl_present_unrealize_window(window);
+#endif
+
     xwl_window = xwl_window_get(window);
     if (!xwl_window)
         return ret;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index a79f836ad..463622669 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -454,6 +454,7 @@ void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen);
 #ifdef GLAMOR_HAS_GBM
 Bool xwl_present_init(ScreenPtr screen);
 void xwl_present_cleanup(WindowPtr window);
+void xwl_present_unrealize_window(WindowPtr window);
 #endif /* GLAMOR_HAS_GBM */
 
 #ifdef XV
commit 98f41563e6599eb762e6a3ec12f99ba6b5388039
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Nov 1 18:44:24 2018 +0100

    xwayland: Replace xwl_window::present_window with ::present_flipped
    
    There's no need to keep track of the window which last performed a
    Present flip. This fixes crashes due to the assertion in
    xwl_present_flips_stop failing. Fixes issue #10.
    
    The damage generated by a flip only needs to be ignored once, then
    xwl_window::present_flipped can be cleared. This may fix freezing in
    the (hypothetical) scenario where Present flips are performed on a
    window, followed by other drawing requests using the window as the
    destination, but nothing triggering xwl_present_flips_stop. The damage
    from the latter drawing requests would continue being ignored.
    
    (cherry picked from commit 6b016d58d23d16eaae9908a92ed90547d1926317)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 047f985b6..8a87e5df6 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -90,24 +90,19 @@ xwl_present_has_events(struct xwl_present_window *xwl_present_window)
            !xorg_list_is_empty(&xwl_present_window->release_queue);
 }
 
-static inline Bool
-xwl_present_is_flipping(WindowPtr window, struct xwl_window *xwl_window)
-{
-    return xwl_window && xwl_window->present_window == window;
-}
-
 static void
 xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
 {
     if (xwl_present_has_events(xwl_present_window)) {
-        WindowPtr present_window = xwl_present_window->window;
-        Bool is_flipping = xwl_present_is_flipping(present_window,
-                                                   xwl_window_from_window(present_window));
+        CARD32 timeout;
+
+        if (xwl_present_window->frame_callback)
+            timeout = TIMER_LEN_FLIP;
+        else
+            timeout = TIMER_LEN_COPY;
 
         xwl_present_window->frame_timer = TimerSet(xwl_present_window->frame_timer,
-                                                   0,
-                                                   is_flipping ? TIMER_LEN_FLIP :
-                                                                 TIMER_LEN_COPY,
+                                                   0, timeout,
                                                    &xwl_present_timer_callback,
                                                    xwl_present_window);
     } else {
@@ -118,16 +113,12 @@ xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
 void
 xwl_present_cleanup(WindowPtr window)
 {
-    struct xwl_window *xwl_window = xwl_window_from_window(window);
     struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
     struct xwl_present_event *event, *tmp;
 
     if (!xwl_present_window)
         return;
 
-    if (xwl_window && xwl_window->present_window == window)
-        xwl_window->present_window = NULL;
-
     if (xwl_present_window->frame_callback) {
         wl_callback_destroy(xwl_present_window->frame_callback);
         xwl_present_window->frame_callback = NULL;
@@ -366,10 +357,6 @@ xwl_present_queue_vblank(WindowPtr present_window,
     if (!xwl_window)
         return BadMatch;
 
-    if (xwl_window->present_window &&
-            xwl_window->present_window != present_window)
-        return BadMatch;
-
     event = malloc(sizeof *event);
     if (!event)
         return BadAlloc;
@@ -439,13 +426,6 @@ xwl_present_check_flip2(RRCrtcPtr crtc,
         return FALSE;
 
     /*
-     * Do not flip if there is already another child window doing flips.
-     */
-    if (xwl_window->present_window &&
-            xwl_window->present_window != present_window)
-        return FALSE;
-
-    /*
      * We currently only allow flips of windows, that have the same
      * dimensions as their xwl_window parent window. For the case of
      * different sizes subsurfaces are presumably the way forward.
@@ -481,8 +461,6 @@ xwl_present_flip(WindowPtr present_window,
     if (!event)
         return FALSE;
 
-    xwl_window->present_window = present_window;
-
     buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, &buffer_created);
 
     event->event_id = event_id;
@@ -507,13 +485,6 @@ xwl_present_flip(WindowPtr present_window,
     /* We can flip directly to the main surface (full screen window without clips) */
     wl_surface_attach(xwl_window->surface, buffer, 0, 0);
 
-    if (!xwl_present_window->frame_timer ||
-            xwl_present_window->frame_timer_firing) {
-        /* Realign timer */
-        xwl_present_window->frame_timer_firing = FALSE;
-        xwl_present_reset_timer(xwl_present_window);
-    }
-
     if (!xwl_present_window->frame_callback) {
         xwl_present_window->frame_callback = wl_surface_frame(xwl_window->surface);
         wl_callback_add_listener(xwl_present_window->frame_callback,
@@ -521,6 +492,10 @@ xwl_present_flip(WindowPtr present_window,
                                  xwl_present_window);
     }
 
+    /* Realign timer */
+    xwl_present_window->frame_timer_firing = FALSE;
+    xwl_present_reset_timer(xwl_present_window);
+
     wl_surface_damage(xwl_window->surface, 0, 0,
                       damage_box->x2 - damage_box->x1,
                       damage_box->y2 - damage_box->y1);
@@ -536,22 +511,15 @@ xwl_present_flip(WindowPtr present_window,
     }
 
     wl_display_flush(xwl_window->xwl_screen->display);
+    xwl_window->present_flipped = TRUE;
     return TRUE;
 }
 
 static void
 xwl_present_flips_stop(WindowPtr window)
 {
-    struct xwl_window *xwl_window = xwl_window_from_window(window);
     struct xwl_present_window   *xwl_present_window = xwl_present_window_priv(window);
 
-    if (!xwl_window)
-        return;
-
-    assert(xwl_window->present_window == window);
-
-    xwl_window->present_window = NULL;
-
     /* Change back to the fast refresh rate */
     xwl_present_reset_timer(xwl_present_window);
 }
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 96b4db18c..988b8e17d 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -370,6 +370,18 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
     struct xwl_window *xwl_window = data;
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
 
+#ifdef GLAMOR_HAS_GBM
+    if (xwl_window->present_flipped) {
+        /* This damage is from a Present flip, which already committed a new
+         * buffer for the surface, so we don't need to do anything in response
+         */
+        RegionEmpty(DamageRegion(pDamage));
+        xorg_list_del(&xwl_window->link_damage);
+        xwl_window->present_flipped = FALSE;
+        return;
+    }
+#endif
+
     xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list);
 }
 
@@ -721,11 +733,6 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen)
 
     xorg_list_for_each_entry_safe(xwl_window, next_xwl_window,
                                   &xwl_screen->damage_window_list, link_damage) {
-#ifdef GLAMOR_HAS_GBM
-        /* Present on the main surface. So don't commit here as well. */
-        if (xwl_window->present_window)
-            continue;
-#endif
         /* If we're waiting on a frame callback from the server,
          * don't attach a new buffer. */
         if (xwl_window->frame_callback)
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 3f4a601fe..a79f836ad 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -182,7 +182,9 @@ struct xwl_window {
     struct xorg_list link_damage;
     struct wl_callback *frame_callback;
     Bool allow_commits;
-    WindowPtr present_window;
+#ifdef GLAMOR_HAS_GBM
+    Bool present_flipped;
+#endif
 };
 
 #ifdef GLAMOR_HAS_GBM
commit f393801dbbe89bce716a8ceeb2b5c8440b9021ce
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Oct 18 17:42:01 2018 +0200

    xwayland: Complete "synchronous" Present flips from xwl_present_msc_bump
    
    Completing them from xwl_present_sync_callback had at least two issues:
    
    * It was before the MSC was incremented in xwl_present_frame_callback,
      so the MSC value in the completion event could be lower than the
      target specified by the client. This could cause hangs with the Mesa
      Vulkan drivers.
    * It allowed clients to run at a frame-rate higher than the Wayland
      compositor's frame-rate, wasting energy on generating frames which
      were never displayed. This isn't expected to happen unless the client
      specified PresentOptionAsync (in which case flips are still completed
      from xwl_present_sync_callback, allowing higher frame-rates).
    
    v2:
    * Make xwl_present_has_events return true when there's a pending
      "synchronous" flip, so those complete after at most ~1 second even if
      the Wayland server doesn't send a frame event.
    
    Bugzilla: https://bugs.freedesktop.org/106713
    (cherry picked from commit ace551d8a2603e37b18237a52f62d627c75d9e2a)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 628dae06c..047f985b6 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -85,7 +85,8 @@ xwl_present_timer_callback(OsTimerPtr timer,
 static inline Bool
 xwl_present_has_events(struct xwl_present_window *xwl_present_window)
 {
-    return !xorg_list_is_empty(&xwl_present_window->event_list) ||
+    return !!xwl_present_window->sync_flip ||
+           !xorg_list_is_empty(&xwl_present_window->event_list) ||
            !xorg_list_is_empty(&xwl_present_window->release_queue);
 }
 
@@ -139,6 +140,16 @@ xwl_present_cleanup(WindowPtr window)
     }
 
     /* Clear remaining buffer releases and inform Present about free ressources */
+    event = xwl_present_window->sync_flip;
+    xwl_present_window->sync_flip = NULL;
+    if (event) {
+        if (event->buffer_released) {
+            free(event);
+        } else {
+            event->pending = FALSE;
+            event->abort = TRUE;
+        }
+    }
     xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->release_queue, list) {
         xorg_list_del(&event->list);
         event->abort = TRUE;
@@ -199,6 +210,24 @@ xwl_present_msc_bump(struct xwl_present_window *xwl_present_window)
 
     xwl_present_window->ust = GetTimeInMicros();
 
+    event = xwl_present_window->sync_flip;
+    xwl_present_window->sync_flip = NULL;
+    if (event) {
+        event->pending = FALSE;
+
+        present_wnmd_event_notify(xwl_present_window->window, event->event_id,
+                                  xwl_present_window->ust, msc);
+
+        if (event->buffer_released) {
+            /* If the buffer was already released, clean up now */
+            present_wnmd_event_notify(xwl_present_window->window, event->event_id,
+                                      xwl_present_window->ust, msc);
+            free(event);
+        } else {
+            xorg_list_add(&event->list, &xwl_present_window->release_queue);
+        }
+    }
+
     xorg_list_for_each_entry_safe(event, tmp,
                                   &xwl_present_window->event_list,
                                   list) {
@@ -459,12 +488,17 @@ xwl_present_flip(WindowPtr present_window,
     event->event_id = event_id;
     event->xwl_present_window = xwl_present_window;
     event->buffer = buffer;
-    event->target_msc = xwl_present_window->msc;
+    event->target_msc = target_msc;
     event->pending = TRUE;
     event->abort = FALSE;
     event->buffer_released = FALSE;
 
-    xorg_list_add(&event->list, &xwl_present_window->release_queue);
+    if (sync_flip) {
+        xorg_list_init(&event->list);
+        xwl_present_window->sync_flip = event;
+    } else {
+        xorg_list_add(&event->list, &xwl_present_window->release_queue);
+    }
 
     if (buffer_created)
         wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL);
@@ -493,10 +527,13 @@ xwl_present_flip(WindowPtr present_window,
 
     wl_surface_commit(xwl_window->surface);
 
-    xwl_present_window->sync_callback = wl_display_sync(xwl_window->xwl_screen->display);
-    wl_callback_add_listener(xwl_present_window->sync_callback,
-                             &xwl_present_sync_listener,
-                             event);
+    if (!sync_flip) {
+        xwl_present_window->sync_callback =
+            wl_display_sync(xwl_window->xwl_screen->display);
+        wl_callback_add_listener(xwl_present_window->sync_callback,
+                                 &xwl_present_sync_listener,
+                                 event);
+    }
 
     wl_display_flush(xwl_window->xwl_screen->display);
     return TRUE;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 67819e178..3f4a601fe 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -188,6 +188,7 @@ struct xwl_window {
 #ifdef GLAMOR_HAS_GBM
 struct xwl_present_window {
     struct xwl_screen *xwl_screen;
+    struct xwl_present_event *sync_flip;
     WindowPtr window;
     struct xorg_list link;
 
commit e646e3054a3e1dbe8ff3906a546897246bcc78f0
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Oct 18 17:36:24 2018 +0200

    xwayland: Rename xwl_present_events_notify to xwl_present_msc_bump
    
    And consolidate more code from xwl_present_timer_callback and
    xwl_present_frame_callback in it.
    
    (cherry picked from commit 2bfc46d4147dc0bec4cdbb80431a0f4cc1d3b030)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index c758350b1..628dae06c 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -192,11 +192,13 @@ static const struct wl_buffer_listener xwl_present_release_listener = {
 };
 
 static void
-xwl_present_events_notify(struct xwl_present_window *xwl_present_window)
+xwl_present_msc_bump(struct xwl_present_window *xwl_present_window)
 {
-    uint64_t                    msc = xwl_present_window->msc;
+    uint64_t msc = ++xwl_present_window->msc;
     struct xwl_present_event    *event, *tmp;
 
+    xwl_present_window->ust = GetTimeInMicros();
+
     xorg_list_for_each_entry_safe(event, tmp,
                                   &xwl_present_window->event_list,
                                   list) {
@@ -218,10 +220,8 @@ xwl_present_timer_callback(OsTimerPtr timer,
     struct xwl_present_window *xwl_present_window = arg;
 
     xwl_present_window->frame_timer_firing = TRUE;
-    xwl_present_window->msc++;
-    xwl_present_window->ust = GetTimeInMicros();
 
-    xwl_present_events_notify(xwl_present_window);
+    xwl_present_msc_bump(xwl_present_window);
     xwl_present_reset_timer(xwl_present_window);
 
     return 0;
@@ -242,10 +242,7 @@ xwl_present_frame_callback(void *data,
         return;
     }
 
-    xwl_present_window->msc++;
-    xwl_present_window->ust = GetTimeInMicros();
-
-    xwl_present_events_notify(xwl_present_window);
+    xwl_present_msc_bump(xwl_present_window);
 
     /* we do not need the timer anymore for this frame,
      * reset it for potentially the next one
commit 47aed554b7c12c0c7f496c86a435dddaa51ae9bf
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Oct 24 11:23:05 2018 +0200

    xwayland: Use xwl_present_reset_timer in xwl_present_timer_callback
    
    Apart from simplifying the code, this should also prevent a condition
    (which might only be possible with the following fix) reported in
    https://gitlab.freedesktop.org/wayland/weston/issues/115#note_52467:
    
    1. xwl_present_timer_callback indirectly calls xwl_present_reset_timer
       -> xwl_present_free_timer
    2. xwl_present_timer_callback then returns a non-0 value, so DoTimer
       calls TimerSet with the old xwl_present_window->frame_timer pointer
       which was freed in step 1 => use after free
    
    Calling xwl_present_reset_timer explicitly passes NULL to TimerSet if
    step 1 freed xwl_present_window->frame_timer, and it will allocate a new
    one.
    
    (cherry picked from commit 5e8b9a3a563047e3998d45e761f7a50e4b0f6cb3)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index fb5c6499e..c758350b1 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -216,24 +216,15 @@ xwl_present_timer_callback(OsTimerPtr timer,
                            void *arg)
 {
     struct xwl_present_window *xwl_present_window = arg;
-    WindowPtr present_window = xwl_present_window->window;
-    struct xwl_window *xwl_window = xwl_window_from_window(present_window);
 
     xwl_present_window->frame_timer_firing = TRUE;
     xwl_present_window->msc++;
     xwl_present_window->ust = GetTimeInMicros();
 
     xwl_present_events_notify(xwl_present_window);
+    xwl_present_reset_timer(xwl_present_window);
 
-    if (xwl_present_has_events(xwl_present_window)) {
-        /* Still events, restart timer */
-        return xwl_present_is_flipping(present_window, xwl_window) ? TIMER_LEN_FLIP :
-                                                                     TIMER_LEN_COPY;
-    } else {
-        /* No more events, do not restart timer and delete it instead */
-        xwl_present_free_timer(xwl_present_window);
-        return 0;
-    }
+    return 0;
 }
 
 static void
commit cf8e064ec0bed45b8cda9ae390c7af78d8ede50f
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Oct 19 16:04:32 2018 +0200

    xwayland: do not crash if `gbm_bo_create()` fails
    
    The function `xwl_glamor_gbm_create_pixmap()` first creates a buffer
    objects and then creates the xwl_pixmap from it.
    
    However, `xwl_glamor_gbm_create_pixmap_for_bo()` is not called if the
    buffer object creation fails, and `xwl_glamor_gbm_create_pixmap()`
    simply returns `glamor_create_pixmap()`.
    
    The problem with this is that if `xwl_glamor_gbm_create_pixmap_for_bo()`
    is not called then neither is `xwl_pixmap_set_private()` and further
    calls to `xwl_pixmap_get()` will return NULL and cause a NULL pointer
    dereference if the return value is not checked:
    
      #0  xwl_glamor_gbm_get_wl_buffer_for_pixmap ()
          at hw/xwayland/xwayland-glamor-gbm.c:248
      #1  xwl_window_post_damage () at hw/xwayland/xwayland.c:697
      #2  xwl_display_post_damage () at hw/xwayland/xwayland.c:759
      #3  block_handler () at hw/xwayland/xwayland.c:890
      #4  BlockHandler () at dix/dixutils.c:388
      #5  WaitForSomething () at os/WaitFor.c:201
      #6  Dispatch () at dix/dispatch.c:421
      #7  dix_main () at dix/main.c:276
      #8  __libc_start_main () at ../csu/libc-start.c:308
      #9  _start ()
    
      (gdb) print xwl_pixmap
      $1 = (struct xwl_pixmap *) 0x0
    
    Make sure we check for `xwl_pixmap_get()` returned value where relevant
    and fail gracefully if this is the case.
    
    See also: https://gitlab.gnome.org/GNOME/mutter/issues/340
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Marco Trevisan <mail at 3v1n0.net>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 036794bebce72a3fa2f95996d2e537ff568e0ff1)

diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index 6aa1e4641..5f8a68fd8 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -244,6 +244,9 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
     uint64_t modifier;
     int i;
 
+    if (xwl_pixmap == NULL)
+       return NULL;
+
     if (xwl_pixmap->buffer) {
         /* Buffer already exists. Return it and inform caller if interested. */
         if (created)
@@ -494,6 +497,9 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
 
     xwl_pixmap = xwl_pixmap_get(pixmap);
 
+    if (xwl_pixmap == NULL)
+       return 0;
+
     if (!xwl_pixmap->bo)
        return 0;
 
commit f89518e17f7d507734af212785e0b3e47954f603
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Oct 22 11:48:25 2018 +0200

    present/wnmd: Fix use after free on CRTC removal
    
    Xwayland will add and remove CRTCs as Wayland outputs are added or
    removed.
    
    If there is a pending flip when this occurs, the
    `xwl_present_sync_callback()` will be triggered after the Xwayland
    output's RRCtrcPtr has been destroyed, hence causing a crash in Xwayland
    while trying to use freed memory:
    
      #1  abort ()
      #2  OsAbort () at utils.c:1350
      #3  AbortServer () at log.c:877
      #4  FatalError () at log.c:1015
      #5  OsSigHandler () at osinit.c:156
      #6  <signal handler called>
      #7  dixGetPrivate () at ../include/privates.h:122
      #8  dixLookupPrivate () at ../include/privates.h:166
      #9  present_screen_priv () at present_priv.h:198
      #10 present_wnmd_flip () at present_wnmd.c:358
      #11 present_wnmd_execute () at present_wnmd.c:466
      #12 present_wnmd_re_execute () at present_wnmd.c:80
      #13 xwl_present_sync_callback () at xwayland-present.c:287
      #14 ffi_call_unix64 () from /lib64/libffi.so.6
      #15 ffi_call () from /lib64/libffi.so.6
      #16 wl_closure_invoke () at src/connection.c:1006
      #17 dispatch_event () at src/wayland-client.c:1427
      #18 dispatch_queue () at src/wayland-client.c:1573
      #19 wl_display_dispatch_queue_pending () at src/wayland-client.c:1815
      #20 wl_display_dispatch_pending () at src/wayland-client.c:1878
      #21 xwl_read_events () at xwayland.c:814
      #22 ospoll_wait () at ospoll.c:651
      #23 WaitForSomething () at WaitFor.c:208
      #24 Dispatch () at ../include/list.h:220
      #25 dix_main () at main.c:276
    
    To avoid the issue, get the `ScreenPtr` from the window instead of the
    CRTC that might have been just freed, `xwl_present_flip()` has no use
    for the CRTC anyway.
    
    Bugzilla: https://bugs.freedesktop.org/108249
    Suggested-by: Michel Daenzer <michel.daenzer at amd.com>
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Daenzer <michel.daenzer at amd.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit b768b7d6cec41b8b320c468ec41aab5a8b49b27b)

diff --git a/present/present_wnmd.c b/present/present_wnmd.c
index 8f3836440..2c6412a72 100644
--- a/present/present_wnmd.c
+++ b/present/present_wnmd.c
@@ -354,7 +354,7 @@ present_wnmd_flip(WindowPtr window,
                   Bool sync_flip,
                   RegionPtr damage)
 {
-    ScreenPtr                   screen = crtc->pScreen;
+    ScreenPtr                   screen = window->drawable.pScreen;
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
 
     return (*screen_priv->wnmd_info->flip) (window,
commit 64f5e6ec2d297f90e9b9785a1cb7285d609a1877
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Oct 19 18:27:37 2018 +0200

    xwayland: Plug leaks in xwl_present_sync_callback
    
    xwl_present_window->sync_callback was leaked.
    
    The event memory was leaked if the corresponding buffer had already been
    released.
    
    (cherry picked from commit cb0de153bf0c486da7e968ab0f258c9c0c9ed34a)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 316e04443..fb5c6499e 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -274,6 +274,9 @@ xwl_present_sync_callback(void *data,
     struct xwl_present_event *event = data;
     struct xwl_present_window *xwl_present_window = event->xwl_present_window;
 
+    wl_callback_destroy(xwl_present_window->sync_callback);
+    xwl_present_window->sync_callback = NULL;
+
     event->pending = FALSE;
 
     if (event->abort) {
@@ -289,12 +292,14 @@ xwl_present_sync_callback(void *data,
                               xwl_present_window->ust,
                               xwl_present_window->msc);
 
-    if (event->buffer_released)
+    if (event->buffer_released) {
         /* If the buffer was already released, send the event now again */
         present_wnmd_event_notify(xwl_present_window->window,
                                   event->event_id,
                                   xwl_present_window->ust,
                                   xwl_present_window->msc);
+        xwl_present_free_event(event);
+    }
 }
 
 static const struct wl_callback_listener xwl_present_sync_listener = {


More information about the xorg-commit mailing list