]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Ignore X11 BadMatch errors during cut buffer setup.
authorSimon Tatham <anakin@pobox.com>
Sun, 20 Mar 2016 18:16:43 +0000 (18:16 +0000)
committerSimon Tatham <anakin@pobox.com>
Sun, 20 Mar 2016 18:30:03 +0000 (18:30 +0000)
This is quite a pain, since it involves inventing an entire new piece
of infrastructure to install a custom Xlib error handler and give it a
queue of things to do. But it fixes a bug in which Unix pterm/PuTTY
crash out at startup if one of the root window's CUT_BUFFERn
properties contains something of a type other than STRING - in
particular, UTF8_STRING is not unheard-of.

For example, run
  xprop -root -format CUT_BUFFER3 8u -set CUT_BUFFER3 "thingy"
and then pterm without this fix would have crashed.

Recipe
unix/gtkwin.c
unix/x11misc.c [new file with mode: 0644]
unix/x11misc.h [new file with mode: 0644]

diff --git a/Recipe b/Recipe
index a480e3cdc0ddecb80a462e5628c1a0889759b2b9..b13b12f4f66cc00ac002820463ae461adebf4503 100644 (file)
--- a/Recipe
+++ b/Recipe
@@ -217,7 +217,7 @@ GUITERM  = TERMINAL window windlg winctrls sizetip winucs winprint
 
 # Same thing on Unix.
 UXTERM   = TERMINAL uxcfg sercfg uxucs uxprint timing callback miscucs
-GTKTERM  = UXTERM gtkwin gtkcfg gtkdlg gtkfont gtkcols gtkmisc xkeysym
+GTKTERM  = UXTERM gtkwin gtkcfg gtkdlg gtkfont gtkcols gtkmisc xkeysym x11misc
 OSXTERM  = UXTERM osxwin osxdlg osxctrls
 
 # Non-SSH back ends (putty, puttytel, plink).
index 192e20e170ac8e1667d04cd603ea8de5f51683b3..e711458e80dc69f4f8ca727efe11e73d21164826 100644 (file)
@@ -44,6 +44,8 @@
 #include <X11/Xatom.h>
 #endif
 
+#include "x11misc.h"
+
 #define CAT2(x,y) x ## y
 #define CAT(x,y) CAT2(x,y)
 #define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)}
@@ -2961,20 +2963,28 @@ void init_clipboard(struct gui_data *inst)
      */
     unsigned char empty[] = "";
     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, empty, 0);
+    x11_ignore_error(disp, BadMatch);
     XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, empty, 0);
 #endif
diff --git a/unix/x11misc.c b/unix/x11misc.c
new file mode 100644 (file)
index 0000000..b49aa48
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * x11misc.c: miscellaneous stuff for dealing directly with X servers.
+ */
+
+#include <ctype.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "putty.h"
+
+#ifndef NOT_X_WINDOWS
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include "x11misc.h"
+
+/* ----------------------------------------------------------------------
+ * Error handling mechanism which permits us to ignore specific X11
+ * errors from particular requests. We maintain a list of upcoming
+ * potential error events that we want to not treat as fatal errors.
+ */
+
+static int (*orig_x11_error_handler)(Display *thisdisp, XErrorEvent *err);
+
+struct x11_err_to_ignore {
+    Display *display;
+    unsigned char error_code;
+    unsigned long serial;
+};
+
+struct x11_err_to_ignore *errs;
+
+int nerrs, errsize;
+
+static int x11_error_handler(Display *thisdisp, XErrorEvent *err)
+{
+    int i;
+    for (i = 0; i < nerrs; i++) {
+        if (thisdisp == errs[i].display &&
+            err->serial == errs[i].serial &&
+            err->error_code == errs[i].error_code) {
+            /* Ok, this is an error we're happy to ignore */
+            return 0;
+        }
+    }
+
+    return (*orig_x11_error_handler)(thisdisp, err);
+}
+
+void x11_ignore_error(Display *disp, unsigned char errcode)
+{
+    /*
+     * Install our error handler, if we haven't already.
+     */
+    if (!orig_x11_error_handler)
+        orig_x11_error_handler = XSetErrorHandler(x11_error_handler);
+
+    /*
+     * This is as good a moment as any to winnow the ignore list based
+     * on requests we know to have been processed.
+     */
+    {
+        unsigned long last = LastKnownRequestProcessed(disp);
+        int i, j;
+        for (i = j = 0; i < nerrs; i++) {
+            if (errs[i].display == disp && errs[i].serial <= last)
+                continue;
+            errs[j++] = errs[i];
+        }
+        nerrs = j;
+    }
+
+    if (nerrs >= errsize) {
+        errsize = nerrs * 5 / 4 + 16;
+        errs = sresize(errs, errsize, struct x11_err_to_ignore);
+    }
+    errs[nerrs].display = disp;
+    errs[nerrs].error_code = errcode;
+    errs[nerrs].serial = NextRequest(disp);
+    nerrs++;
+}
+
+#endif
+
diff --git a/unix/x11misc.h b/unix/x11misc.h
new file mode 100644 (file)
index 0000000..0ad1476
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * x11misc.h: header file for functions that need to refer to Xlib
+ * data types. Has to be separate from unix.h so that we can include
+ * it only after including the X headers, which in turn has to be done
+ * after putty.h has told us whether NOT_X_WINDOWS is defined.
+ */
+
+#ifndef NOT_X_WINDOWS
+
+/*
+ * x11misc.c.
+ */
+void x11_ignore_error(Display *disp, unsigned char errcode);
+
+#endif