From cfdb946992a40992cd8820d55975f1c629bbdf0d Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 14 Jul 2016 16:43:20 -0400 Subject: [PATCH] Avoid using window id as identifier in finish_destroy_win Under extreme race conditions (window A close at the same time as window B create), there can be multiple windows with same id in compton's window list. If at this point window B closes itself as well, finish_destroy_win might destroy a different window as what's passed to destroy_callback. This can be a problem because someone can still hold a reference to that window (e.g. 't' in paint_preprocess), and there's no way to clear that reference. If finish_destroy_win always destroy the same window passed to destroy_callback, this will not be a problem. --- src/compton.c | 15 ++++++++------- src/compton.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/compton.c b/src/compton.c index df2b5ad3..23606fb4 100644 --- a/src/compton.c +++ b/src/compton.c @@ -3206,17 +3206,18 @@ circulate_win(session_t *ps, XCirculateEvent *ce) { } static void -finish_destroy_win(session_t *ps, Window id) { - win **prev = NULL, *w = NULL; +finish_destroy_win(session_t *ps, win *w) { + assert(w->destroyed); + win **prev = NULL, *i = NULL; #ifdef DEBUG_EVENTS - printf_dbgf("(%#010lx): Starting...\n", id); + printf_dbgf("(%#010lx): Starting...\n", w->id); #endif - for (prev = &ps->list; (w = *prev); prev = &w->next) { - if (w->id == id && w->destroyed) { + for (prev = &ps->list; (i = *prev); prev = &i->next) { + if (w == i) { #ifdef DEBUG_EVENTS - printf_dbgf("(%#010lx \"%s\"): %p\n", id, w->name, w); + printf_dbgf("(%#010lx \"%s\"): %p\n", w->id, w->name, w); #endif finish_unmap_win(ps, w); @@ -3242,7 +3243,7 @@ finish_destroy_win(session_t *ps, Window id) { static void destroy_callback(session_t *ps, win *w) { - finish_destroy_win(ps, w->id); + finish_destroy_win(ps, w); } static void diff --git a/src/compton.h b/src/compton.h index 0e27a759..24ef2d5a 100644 --- a/src/compton.h +++ b/src/compton.h @@ -919,7 +919,7 @@ static void circulate_win(session_t *ps, XCirculateEvent *ce); static void -finish_destroy_win(session_t *ps, Window id); +finish_destroy_win(session_t *ps, win *w); static void destroy_callback(session_t *ps, win *w);