Skip to content
Snippets Groups Projects
Commit e34bd553 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Fix a potential race between drawing and discarding last buffer.

If the last is freed while the screen is being updated, and the use
after free bug is not detected, corruption could occur resulting in
bad areas of the screen that persists until the window gets an
expose event again, or the impacted pixels are updated again.

Possibly fixes an issue reported by nelgin via IRC.
parent 228e8761
No related branches found
No related tags found
No related merge requests found
Pipeline #6750 passed
...@@ -165,6 +165,7 @@ static int r_shift; ...@@ -165,6 +165,7 @@ static int r_shift;
static int g_shift; static int g_shift;
static int b_shift; static int b_shift;
static struct graphics_buffer *last = NULL; static struct graphics_buffer *last = NULL;
pthread_mutex_t last_mutex;
#ifdef WITH_XRENDER #ifdef WITH_XRENDER
static XRenderPictFormat *xrender_pf = NULL; static XRenderPictFormat *xrender_pf = NULL;
static Pixmap xrender_pm = None; static Pixmap xrender_pm = None;
...@@ -724,6 +725,17 @@ resize_pictures(void) ...@@ -724,6 +725,17 @@ resize_pictures(void)
#endif #endif
} }
static void
free_last(void)
{
pthread_mutex_lock(&last_mutex);
if (last) {
release_buffer(last);
last = NULL;
}
pthread_mutex_unlock(&last_mutex);
}
static void resize_xim(void) static void resize_xim(void)
{ {
int width, height; int width, height;
...@@ -742,10 +754,7 @@ static void resize_xim(void) ...@@ -742,10 +754,7 @@ static void resize_xim(void)
if (xim) { if (xim) {
if (width == xim->width if (width == xim->width
&& height == xim->height) { && height == xim->height) {
if (last) { free_last();
release_buffer(last);
last = NULL;
}
return; return;
} }
#ifdef XDestroyImage #ifdef XDestroyImage
...@@ -754,10 +763,7 @@ static void resize_xim(void) ...@@ -754,10 +763,7 @@ static void resize_xim(void)
x11.XDestroyImage(xim); x11.XDestroyImage(xim);
#endif #endif
} }
if (last) { free_last();
release_buffer(last);
last = NULL;
}
xim = x11.XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL, width, height, 32, 0); xim = x11.XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL, width, height, 32, 0);
xim->data=(char *)calloc(1, xim->bytes_per_line*xim->height); xim->data=(char *)calloc(1, xim->bytes_per_line*xim->height);
} }
...@@ -1227,11 +1233,8 @@ static void init_mode_internal(int mode) ...@@ -1227,11 +1233,8 @@ static void init_mode_internal(int mode)
int ow, oh; int ow, oh;
x11_get_maxsize(&mw, &mh); x11_get_maxsize(&mw, &mh);
free_last();
pthread_mutex_lock(&vstatlock); pthread_mutex_lock(&vstatlock);
if (last) {
release_buffer(last);
last = NULL;
}
ow = vstat.winwidth; ow = vstat.winwidth;
oh = vstat.winheight; oh = vstat.winheight;
bitmap_drv_init_mode(mode, NULL, NULL, mw, mh); bitmap_drv_init_mode(mode, NULL, NULL, mw, mh);
...@@ -1374,13 +1377,13 @@ local_draw_rect(struct rectlist *rect) ...@@ -1374,13 +1377,13 @@ local_draw_rect(struct rectlist *rect)
yoff = 0; yoff = 0;
if (last && (last->w != dw || last->h != dh)) { if (last && (last->w != dw || last->h != dh)) {
release_buffer(last); free_last();
last = NULL;
} }
/* TODO: Translate into local colour depth */ /* TODO: Translate into local colour depth */
idx = 0; idx = 0;
pthread_mutex_lock(&last_mutex);
for (y = 0; y < dh; y++) { for (y = 0; y < dh; y++) {
for (x = 0; x < dw; x++) { for (x = 0; x < dw; x++) {
if (last) { if (last) {
...@@ -1485,6 +1488,7 @@ local_draw_rect(struct rectlist *rect) ...@@ -1485,6 +1488,7 @@ local_draw_rect(struct rectlist *rect)
#endif #endif
} }
last = source; last = source;
pthread_mutex_lock(&last_mutex);
} }
static void handle_resize_event(int width, int height, bool map) static void handle_resize_event(int width, int height, bool map)
...@@ -1539,10 +1543,7 @@ static void expose_rect(int x, int y, int width, int height) ...@@ -1539,10 +1543,7 @@ static void expose_rect(int x, int y, int width, int height)
x11.XFillRectangle(dpy, win, gc, 0, yoff + sh, w, h); x11.XFillRectangle(dpy, win, gc, 0, yoff + sh, w, h);
/* Since we're exposing, we *have* to redraw */ /* Since we're exposing, we *have* to redraw */
if (last) { free_last();
release_buffer(last);
last = NULL;
}
bitmap_drv_request_pixels(); bitmap_drv_request_pixels();
} }
...@@ -2271,6 +2272,8 @@ void x11_event_thread(void *args) ...@@ -2271,6 +2272,8 @@ void x11_event_thread(void *args)
return; return;
} }
sem_init(&event_thread_complete, 0, 0); sem_init(&event_thread_complete, 0, 0);
pthread_mutex_init(&last_mutex, NULL);
atexit(x11_terminate_event_thread); atexit(x11_terminate_event_thread);
if(local_pipe[0] > xfd) if(local_pipe[0] > xfd)
......
...@@ -12,6 +12,7 @@ Fix focus-follows-mouse behaviour in herbstluftwm ...@@ -12,6 +12,7 @@ Fix focus-follows-mouse behaviour in herbstluftwm
Fix SAUCE binary capture date Fix SAUCE binary capture date
Add Build Options menu item Add Build Options menu item
Fix saving non-integer scaling in GDI mode Fix saving non-integer scaling in GDI mode
Fix X11 race between Expose event and redraw
Version 1.2rc1 Version 1.2rc1
-------------- --------------
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment