Browse Source

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.
Richard Grenville 4 years ago
parent
commit
ebab3dc506
4 changed files with 149 additions and 3 deletions
  1. 6
    2
      common.h
  2. 8
    1
      compton.c
  3. 65
    0
      xrescheck.c
  4. 70
    0
      xrescheck.h

+ 6
- 2
common.h View File

@@ -145,8 +145,6 @@
145 145
 #define GLX_BACK_BUFFER_AGE_EXT 0x20F4
146 146
 #endif
147 147
 
148
-#endif
149
-
150 148
 // === Macros ===
151 149
 
152 150
 #define MSTR_(s)        #s
@@ -186,6 +184,11 @@
186 184
 /// Macro used for shortening some debugging code.
187 185
 #define CASESTRRET(s)   case s: return #s
188 186
 
187
+// X resource checker
188
+#ifdef DEBUG_XRC
189
+#include "xrescheck.h"
190
+#endif
191
+
189 192
 // === Constants ===
190 193
 #if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2)
191 194
 #error libXcomposite version unsupported
@@ -2514,3 +2517,4 @@ hexdump(const char *data, int len) {
2514 2517
   fflush(stdout);
2515 2518
 }
2516 2519
 
2520
+#endif

+ 8
- 1
compton.c View File

@@ -486,7 +486,9 @@ win_build_shadow(session_t *ps, win *w, double opacity) {
486 486
       shadow_picture_argb, 0, 0, 0, 0, 0, 0,
487 487
       shadow_image->width, shadow_image->height);
488 488
 
489
+  assert(!w->shadow_paint.pixmap);
489 490
   w->shadow_paint.pixmap = shadow_pixmap_argb;
491
+  assert(!w->shadow_paint.pict);
490 492
   w->shadow_paint.pict = shadow_picture_argb;
491 493
 
492 494
   // Sync it once and only once
@@ -1826,7 +1828,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
1826 1828
     // Painting shadow
1827 1829
     if (w->shadow) {
1828 1830
       // Lazy shadow building
1829
-      if (!paint_isvalid(ps, &w->shadow_paint))
1831
+      if (!w->shadow_paint.pixmap)
1830 1832
         win_build_shadow(ps, w, 1);
1831 1833
 
1832 1834
       // Shadow is to be painted based on the ignore region of current
@@ -7510,6 +7512,11 @@ session_destroy(session_t *ps) {
7510 7512
   // Flush all events
7511 7513
   XSync(ps->dpy, True);
7512 7514
 
7515
+#ifdef DEBUG_XRC
7516
+  // Report about resource leakage
7517
+  xrc_report_xid();
7518
+#endif
7519
+
7513 7520
   // Free timeouts
7514 7521
   ps->tmout_unredir = NULL;
7515 7522
   timeout_clear(ps);

+ 65
- 0
xrescheck.c View File

@@ -0,0 +1,65 @@
1
+#include "xrescheck.h"
2
+
3
+static xrc_xid_record_t *gs_xid_records = NULL;
4
+
5
+#define HASH_ADD_XID(head, xidfield, add) \
6
+  HASH_ADD(hh, head, xidfield, sizeof(xid), add)
7
+
8
+#define HASH_FIND_XID(head, findxid, out) \
9
+  HASH_FIND(hh, head, findxid, sizeof(xid), out)
10
+
11
+#define M_CPY_POS_DATA(prec) \
12
+  prec->file = file; \
13
+  prec->func = func; \
14
+  prec->line = line; \
15
+
16
+/**
17
+ * @brief Add a record of given XID to the allocation table.
18
+ */
19
+void
20
+xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS) {
21
+  xrc_xid_record_t *prec = cmalloc(1, xrc_xid_record_t);
22
+  prec->xid = xid;
23
+  prec->type = type;
24
+  M_CPY_POS_DATA(prec);
25
+
26
+  HASH_ADD_XID(gs_xid_records, xid, prec);
27
+}
28
+
29
+/**
30
+ * @brief Delete a record of given XID in the allocation table.
31
+ */
32
+void
33
+xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS) {
34
+  xrc_xid_record_t *prec = NULL;
35
+  HASH_FIND_XID(gs_xid_records, &xid, prec);
36
+  if (!prec) {
37
+    printf_err("XRC: %s:%d %s(): Can't find XID %#010lx we want to delete.",
38
+        file, line, func, xid);
39
+    return;
40
+  }
41
+  HASH_DEL(gs_xid_records, prec);
42
+  free(prec);
43
+}
44
+
45
+/**
46
+ * @brief Report about issues found in the XID allocation table.
47
+ */
48
+void
49
+xrc_report_xid(void) {
50
+  for (xrc_xid_record_t *prec = gs_xid_records; prec; prec = prec->hh.next)
51
+    printf_dbg("XRC: %s:%d %s(): %#010lx (%s) not freed.\n",
52
+        prec->file, prec->line, prec->func, prec->xid, prec->type);
53
+}
54
+
55
+/**
56
+ * @brief Clear the XID allocation table.
57
+ */
58
+void
59
+xrc_clear_xid(void) {
60
+  xrc_xid_record_t *prec = NULL, *ptmp = NULL;
61
+  HASH_ITER(hh, gs_xid_records, prec, ptmp) {
62
+    HASH_DEL(gs_xid_records, prec);
63
+    free(prec);
64
+  }
65
+}

+ 70
- 0
xrescheck.h View File

@@ -0,0 +1,70 @@
1
+#ifndef COMPTON_XRESCHECK_H
2
+#define COMPTON_XRESCHECK_H
3
+
4
+#include "common.h"
5
+#include <uthash.h>
6
+
7
+typedef struct {
8
+  XID xid;
9
+  const char *type;
10
+  const char *file;
11
+  const char *func;
12
+  int line;
13
+  UT_hash_handle hh;
14
+} xrc_xid_record_t;
15
+
16
+#define M_POS_DATA_PARAMS const char *file, int line, const char *func
17
+#define M_POS_DATA_PASSTHROUGH file, line, func
18
+#define M_POS_DATA __FILE__, __LINE__, __func__
19
+
20
+void
21
+xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS);
22
+
23
+#define xrc_add_xid(xid, type) xrc_add_xid_(xid, type, M_POS_DATA)
24
+
25
+void
26
+xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS);
27
+
28
+#define xrc_delete_xid(xid) xrc_delete_xid_(xid, M_POS_DATA)
29
+
30
+void
31
+xrc_report_xid(void);
32
+
33
+void
34
+xrc_clear_xid(void);
35
+
36
+// Pixmap
37
+
38
+static inline Pixmap
39
+XCreatePixmap_(Display *dpy, Drawable drawable,
40
+    unsigned int width, unsigned int height, unsigned int depth,
41
+    M_POS_DATA_PARAMS) {
42
+  Pixmap ret = XCreatePixmap(dpy, drawable, width, height, depth);
43
+  if (ret)
44
+    xrc_add_xid_(ret, "Pixmap", M_POS_DATA_PASSTHROUGH);
45
+  return ret;
46
+}
47
+
48
+#define XCreatePixmap(dpy, drawable, width, height, depth) \
49
+  XCreatePixmap_(dpy, drawable, width, height, depth, M_POS_DATA)
50
+
51
+static inline Pixmap
52
+XCompositeNameWindowPixmap_(Display *dpy, Window window, M_POS_DATA_PARAMS) {
53
+  Pixmap ret = XCompositeNameWindowPixmap(dpy, window);
54
+  if (ret)
55
+    xrc_add_xid_(ret, "PixmapC", M_POS_DATA_PASSTHROUGH);
56
+  return ret;
57
+}
58
+
59
+#define XCompositeNameWindowPixmap(dpy, window) \
60
+  XCompositeNameWindowPixmap_(dpy, window, M_POS_DATA)
61
+
62
+static inline void
63
+XFreePixmap_(Display *dpy, Pixmap pixmap, M_POS_DATA_PARAMS) {
64
+  XFreePixmap(dpy, pixmap);
65
+  xrc_delete_xid_(pixmap, M_POS_DATA_PASSTHROUGH);
66
+}
67
+
68
+#define XFreePixmap(dpy, pixmap) XFreePixmap_(dpy, pixmap, M_POS_DATA);
69
+
70
+#endif

Loading…
Cancel
Save