Bug 1774916 - Avoid opening temporary X display in error handler. r=aosmond,gfx-reviewers,nical

Differential Revision: https://phabricator.services.mozilla.com/D150401
This commit is contained in:
Lee Salzman 2022-06-27 16:29:50 +00:00
parent a504ef6021
commit 8f14cd2cd5

View file

@ -9,12 +9,46 @@
#include "nsXULAppAPI.h" #include "nsXULAppAPI.h"
#include "nsExceptionHandler.h" #include "nsExceptionHandler.h"
#include "nsDebug.h" #include "nsDebug.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/X11Util.h" #include "mozilla/X11Util.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#define BUFSIZE 2048 // What Xlib uses with XGetErrorDatabaseText #define BUFSIZE 2048 // What Xlib uses with XGetErrorDatabaseText
struct XExtension {
nsCString name;
int major_opcode;
XExtension(const char* aName, int aCode) : name(aName), major_opcode(aCode) {}
};
static nsTArray<XExtension> sXExtensions;
// man XSetErrorHandler says "the error handler should not call any
// functions (directly or indirectly) on the display that will generate
// protocol requests or that will look for input events" so we query the
// extension list early to avoid problems.
static void QueryXExtensions(Display* aDisplay) {
if (!aDisplay) {
return;
}
int nExts = 0;
char** extNames = XListExtensions(aDisplay, &nExts);
if (!extNames) {
return;
}
for (int i = 0; i < nExts; ++i) {
int major_opcode, first_event, first_error;
if (XQueryExtension(aDisplay, extNames[i], &major_opcode, &first_event,
&first_error)) {
sXExtensions.EmplaceBack(extNames[i], major_opcode);
}
}
XFreeExtensionList(extNames);
}
extern "C" { extern "C" {
int X11Error(Display* display, XErrorEvent* event) { int X11Error(Display* display, XErrorEvent* event) {
// Get an indication of how long ago the request that caused the error was // Get an indication of how long ago the request that caused the error was
@ -28,34 +62,13 @@ int X11Error(Display* display, XErrorEvent* event) {
message.AppendInt(event->request_code); message.AppendInt(event->request_code);
} else { } else {
// Extension request // Extension request
for (XExtension& ext : sXExtensions) {
// man XSetErrorHandler says "the error handler should not call any if (ext.major_opcode == event->request_code) {
// functions (directly or indirectly) on the display that will generate message.Append(ext.name);
// protocol requests or that will look for input events" so we use another message.Append('.');
// temporary Display to request extension information. This assumes on message.AppendInt(event->minor_code);
// the DISPLAY environment variable has been set and matches what was used break;
// to open |display|.
Display* tmpDisplay = XOpenDisplay(nullptr);
if (tmpDisplay) {
int nExts;
char** extNames = XListExtensions(tmpDisplay, &nExts);
int first_error;
if (extNames) {
for (int i = 0; i < nExts; ++i) {
int major_opcode, first_event;
if (XQueryExtension(tmpDisplay, extNames[i], &major_opcode,
&first_event, &first_error) &&
major_opcode == event->request_code) {
message.Append(extNames[i]);
message.Append('.');
message.AppendInt(event->minor_code);
break;
}
}
XFreeExtensionList(extNames);
} }
XCloseDisplay(tmpDisplay);
} }
} }
@ -130,9 +143,9 @@ int X11Error(Display* display, XErrorEvent* event) {
void InstallX11ErrorHandler() { void InstallX11ErrorHandler() {
XSetErrorHandler(X11Error); XSetErrorHandler(X11Error);
if (PR_GetEnv("MOZ_X_SYNC")) { if (Display* display = mozilla::DefaultXDisplay()) {
Display* display = mozilla::DefaultXDisplay(); QueryXExtensions(display);
if (display) { if (PR_GetEnv("MOZ_X_SYNC")) {
XSynchronize(display, X11True); XSynchronize(display, X11True);
} }
} }