Ignore X11 BadMatch errors during cut buffer setup.

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.
This commit is contained in:
Simon Tatham 2016-03-20 18:16:43 +00:00
Родитель ca68700570
Коммит 36ddc57084
4 изменённых файлов: 114 добавлений и 1 удалений

2
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).

Просмотреть файл

@ -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

88
unix/x11misc.c Normal file
Просмотреть файл

@ -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

15
unix/x11misc.h Normal file
Просмотреть файл

@ -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