xwayland: clean up glamor EGL state on fatal exits

Xwayland initializes glamor on top of an EGL display, but some fatal
exit paths bypass the normal screen close sequence. In particular, this
can happen through xwl_give_up() after the Wayland compositor goes away,
or through ddxGiveUp() after early startup failures such as keymap
compilation failure.

A relevant excerpt from the ASan report:
  Direct leak of 368 byte(s) in 1 object(s) allocated from:
    #0 in calloc
    #1 in dri2_display_create ../src/egl/drivers/dri2/egl_dri2.c:1014
    #2 in dri2_initialize ../src/egl/drivers/dri2/egl_dri2.c:874
    #3 in eglInitialize ../src/egl/main/eglapi.c:697
    #4 in xwl_glamor_gbm_init_egl ../hw/xwayland/xwayland-glamor-gbm.c:1739
    #5 in xwl_glamor_init ../hw/xwayland/xwayland-glamor.c:242
    #6 in xwl_screen_init ../hw/xwayland/xwayland-screen.c:1121
    #7 in AddScreen ../dix/dispatch.c:3999
    #8 in InitOutput ../hw/xwayland/xwayland.c:437
    #9 in dix_main ../dix/main.c:190
    ...
  Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 in calloc
    #1 in _eglCreateArray ../src/egl/main/eglarray.c:69
    #2 in _eglLinkConfig ../src/egl/main/eglconfig.c:85
    #3 in dri2_add_config ../src/egl/drivers/dri2/egl_dri2.c:457
    #4 in drm_add_configs_for_visuals ../src/egl/drivers/dri2/platform_drm.c:563
    #5 in dri2_initialize_drm ../src/egl/drivers/dri2/platform_drm.c:706
    #6 in dri2_initialize ../src/egl/drivers/dri2/egl_dri2.c:892
    #7 in eglInitialize ../src/egl/main/eglapi.c:697
    ...
This commit is contained in:
Pavel Ondračka 2026-04-02 10:15:28 +02:00
parent 3d85c04df0
commit 83dc5453c6
6 changed files with 58 additions and 4 deletions

View file

@ -1707,6 +1707,21 @@ xwl_glamor_gbm_init_main_dev(struct xwl_screen *xwl_screen)
return TRUE;
}
void
xwl_glamor_gbm_cleanup_egl(struct xwl_screen *xwl_screen)
{
if (!xwl_screen->glamor)
return;
if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
xwl_glamor_maybe_destroy_context(xwl_screen);
eglTerminate(xwl_screen->egl_display);
xwl_screen->egl_display = EGL_NO_DISPLAY;
}
xwl_glamor_gbm_cleanup(xwl_screen);
}
Bool
xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
{
@ -1845,7 +1860,7 @@ skip_drm_auth:
return TRUE;
error:
xwl_glamor_gbm_cleanup(xwl_screen);
xwl_glamor_gbm_cleanup_egl(xwl_screen);
return FALSE;
}

View file

@ -40,6 +40,7 @@ Bool xwl_glamor_init_gbm(struct xwl_screen *xwl_screen);
Bool xwl_glamor_has_wl_drm(struct xwl_screen *xwl_screen);
Bool xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen);
Bool xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen);
void xwl_glamor_gbm_cleanup_egl(struct xwl_screen *xwl_screen);
drmDevice *xwl_gbm_get_main_device(struct xwl_screen *xwl_screen);
/* Explicit buffer synchronization points */

View file

@ -50,6 +50,8 @@
#include <sys/mman.h>
#include <scrnintstr.h>
static void
glamor_egl_make_current(struct glamor_context *glamor_ctx)
{
@ -268,3 +270,23 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
return TRUE;
}
void
xwl_glamor_cleanup_all_screens(void)
{
int i;
for (i = 0; i < screenInfo.numScreens; i++) {
ScreenPtr screen = screenInfo.screens[i];
struct xwl_screen *xwl_screen;
if (!screen)
continue;
xwl_screen = xwl_screen_get(screen);
if (!xwl_screen)
continue;
xwl_glamor_gbm_cleanup_egl(xwl_screen);
}
}

View file

@ -47,6 +47,7 @@ typedef enum _xwl_glamor_mode_flags{
#ifdef XWL_HAS_GLAMOR
Bool xwl_glamor_init(struct xwl_screen *xwl_screen);
void xwl_glamor_cleanup_all_screens(void);
Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version);

View file

@ -91,6 +91,10 @@ xwl_give_up(const char *f, ...)
VErrorFSigSafe(f, args);
va_end(args);
#ifdef XWL_HAS_GLAMOR
xwl_glamor_cleanup_all_screens();
#endif
CloseWellKnownConnections();
OsCleanup(TRUE);
fflush(stderr);
@ -237,9 +241,11 @@ Bool
xwl_close_screen(ScreenPtr screen)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
CloseScreenProcPtr close_screen = xwl_screen->CloseScreen;
struct xwl_output *xwl_output, *next_xwl_output;
struct xwl_seat *xwl_seat, *next_xwl_seat;
struct xwl_wl_surface *xwl_wl_surface, *xwl_wl_surface_next;
Bool ret;
#ifdef XWL_HAS_GLAMOR
xwl_dmabuf_feedback_destroy(&xwl_screen->default_feedback);
#endif
@ -281,13 +287,18 @@ xwl_close_screen(ScreenPtr screen)
RemoveNotifyFd(xwl_screen->wayland_fd);
wl_display_disconnect(xwl_screen->display);
screen->CloseScreen = close_screen;
ret = close_screen(screen);
screen->CloseScreen = xwl_screen->CloseScreen;
#ifdef XWL_HAS_GLAMOR
xwl_glamor_gbm_cleanup_egl(xwl_screen);
#endif
wl_display_disconnect(xwl_screen->display);
free(xwl_screen);
return screen->CloseScreen(screen);
return ret;
}
static struct xwl_seat *
@ -1180,6 +1191,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
#ifdef XWL_HAS_GLAMOR
if (xwl_screen->glamor && !xwl_glamor_init(xwl_screen)) {
ErrorF("Failed to initialize glamor, falling back to sw\n");
xwl_glamor_gbm_cleanup_egl(xwl_screen);
xwl_screen->glamor = XWL_GLAMOR_NONE;
}
#endif

View file

@ -61,6 +61,9 @@ extern _X_EXPORT Bool noXFree86VidModeExtension;
void
ddxGiveUp(enum ExitCode error)
{
#ifdef XWL_HAS_GLAMOR
xwl_glamor_cleanup_all_screens();
#endif
}
void