From a801118c04d3a8f26261a095cffda59635ef5b4d Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Sun, 3 Aug 2014 19:40:40 +0800 Subject: [PATCH] Bug fix: Fix X pixmap leakage in shadow_paint - Fix X pixmap leakage in shadow_paint. - Add the skeleton of a X resource leakage checker. --- Makefile | 6 +++++ src/common.h | 8 ++++-- src/compton.c | 9 ++++++- src/xrescheck.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/xrescheck.h | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 src/xrescheck.c create mode 100644 src/xrescheck.h diff --git a/Makefile b/Makefile index 86ffbe7..7795cba 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,12 @@ ifeq "$(NO_C2)" "" OBJS += c2.o endif +# ==== X resource checker ==== +ifneq "$(ENABLE_XRESCHECK)" "" + CFG += -DDEBUG_XRC + OBJS += xrescheck.o +endif + # === Version string === COMPTON_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1 --date=short --pretty=format:%cd) CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\"" diff --git a/src/common.h b/src/common.h index c1bae42..066284e 100644 --- a/src/common.h +++ b/src/common.h @@ -145,8 +145,6 @@ #define GLX_BACK_BUFFER_AGE_EXT 0x20F4 #endif -#endif - // === Macros === #define MSTR_(s) #s @@ -186,6 +184,11 @@ /// Macro used for shortening some debugging code. #define CASESTRRET(s) case s: return #s +// X resource checker +#ifdef DEBUG_XRC +#include "xrescheck.h" +#endif + // === Constants === #if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2) #error libXcomposite version unsupported @@ -2514,3 +2517,4 @@ hexdump(const char *data, int len) { fflush(stdout); } +#endif diff --git a/src/compton.c b/src/compton.c index f249b18..f545b0d 100644 --- a/src/compton.c +++ b/src/compton.c @@ -486,7 +486,9 @@ win_build_shadow(session_t *ps, win *w, double opacity) { shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width, shadow_image->height); + assert(!w->shadow_paint.pixmap); w->shadow_paint.pixmap = shadow_pixmap_argb; + assert(!w->shadow_paint.pict); w->shadow_paint.pict = shadow_picture_argb; // Sync it once and only once @@ -1826,7 +1828,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t // Painting shadow if (w->shadow) { // Lazy shadow building - if (!paint_isvalid(ps, &w->shadow_paint)) + if (!w->shadow_paint.pixmap) win_build_shadow(ps, w, 1); // Shadow is to be painted based on the ignore region of current @@ -7510,6 +7512,11 @@ session_destroy(session_t *ps) { // Flush all events XSync(ps->dpy, True); +#ifdef DEBUG_XRC + // Report about resource leakage + xrc_report_xid(); +#endif + // Free timeouts ps->tmout_unredir = NULL; timeout_clear(ps); diff --git a/src/xrescheck.c b/src/xrescheck.c new file mode 100644 index 0000000..6a63bed --- /dev/null +++ b/src/xrescheck.c @@ -0,0 +1,65 @@ +#include "xrescheck.h" + +static xrc_xid_record_t *gs_xid_records = NULL; + +#define HASH_ADD_XID(head, xidfield, add) \ + HASH_ADD(hh, head, xidfield, sizeof(xid), add) + +#define HASH_FIND_XID(head, findxid, out) \ + HASH_FIND(hh, head, findxid, sizeof(xid), out) + +#define M_CPY_POS_DATA(prec) \ + prec->file = file; \ + prec->func = func; \ + prec->line = line; \ + +/** + * @brief Add a record of given XID to the allocation table. + */ +void +xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS) { + xrc_xid_record_t *prec = cmalloc(1, xrc_xid_record_t); + prec->xid = xid; + prec->type = type; + M_CPY_POS_DATA(prec); + + HASH_ADD_XID(gs_xid_records, xid, prec); +} + +/** + * @brief Delete a record of given XID in the allocation table. + */ +void +xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS) { + xrc_xid_record_t *prec = NULL; + HASH_FIND_XID(gs_xid_records, &xid, prec); + if (!prec) { + printf_err("XRC: %s:%d %s(): Can't find XID %#010lx we want to delete.", + file, line, func, xid); + return; + } + HASH_DEL(gs_xid_records, prec); + free(prec); +} + +/** + * @brief Report about issues found in the XID allocation table. + */ +void +xrc_report_xid(void) { + for (xrc_xid_record_t *prec = gs_xid_records; prec; prec = prec->hh.next) + printf_dbg("XRC: %s:%d %s(): %#010lx (%s) not freed.\n", + prec->file, prec->line, prec->func, prec->xid, prec->type); +} + +/** + * @brief Clear the XID allocation table. + */ +void +xrc_clear_xid(void) { + xrc_xid_record_t *prec = NULL, *ptmp = NULL; + HASH_ITER(hh, gs_xid_records, prec, ptmp) { + HASH_DEL(gs_xid_records, prec); + free(prec); + } +} diff --git a/src/xrescheck.h b/src/xrescheck.h new file mode 100644 index 0000000..48f254b --- /dev/null +++ b/src/xrescheck.h @@ -0,0 +1,70 @@ +#ifndef COMPTON_XRESCHECK_H +#define COMPTON_XRESCHECK_H + +#include "common.h" +#include + +typedef struct { + XID xid; + const char *type; + const char *file; + const char *func; + int line; + UT_hash_handle hh; +} xrc_xid_record_t; + +#define M_POS_DATA_PARAMS const char *file, int line, const char *func +#define M_POS_DATA_PASSTHROUGH file, line, func +#define M_POS_DATA __FILE__, __LINE__, __func__ + +void +xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS); + +#define xrc_add_xid(xid, type) xrc_add_xid_(xid, type, M_POS_DATA) + +void +xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS); + +#define xrc_delete_xid(xid) xrc_delete_xid_(xid, M_POS_DATA) + +void +xrc_report_xid(void); + +void +xrc_clear_xid(void); + +// Pixmap + +static inline Pixmap +XCreatePixmap_(Display *dpy, Drawable drawable, + unsigned int width, unsigned int height, unsigned int depth, + M_POS_DATA_PARAMS) { + Pixmap ret = XCreatePixmap(dpy, drawable, width, height, depth); + if (ret) + xrc_add_xid_(ret, "Pixmap", M_POS_DATA_PASSTHROUGH); + return ret; +} + +#define XCreatePixmap(dpy, drawable, width, height, depth) \ + XCreatePixmap_(dpy, drawable, width, height, depth, M_POS_DATA) + +static inline Pixmap +XCompositeNameWindowPixmap_(Display *dpy, Window window, M_POS_DATA_PARAMS) { + Pixmap ret = XCompositeNameWindowPixmap(dpy, window); + if (ret) + xrc_add_xid_(ret, "PixmapC", M_POS_DATA_PASSTHROUGH); + return ret; +} + +#define XCompositeNameWindowPixmap(dpy, window) \ + XCompositeNameWindowPixmap_(dpy, window, M_POS_DATA) + +static inline void +XFreePixmap_(Display *dpy, Pixmap pixmap, M_POS_DATA_PARAMS) { + XFreePixmap(dpy, pixmap); + xrc_delete_xid_(pixmap, M_POS_DATA_PASSTHROUGH); +} + +#define XFreePixmap(dpy, pixmap) XFreePixmap_(dpy, pixmap, M_POS_DATA); + +#endif