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 "nsExceptionHandler.h"
#include "nsDebug.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/X11Util.h"
#include <X11/Xlib.h>
#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" {
int X11Error(Display* display, XErrorEvent* event) {
// 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);
} else {
// Extension request
// 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 use another
// temporary Display to request extension information. This assumes on
// the DISPLAY environment variable has been set and matches what was used
// 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);
for (XExtension& ext : sXExtensions) {
if (ext.major_opcode == event->request_code) {
message.Append(ext.name);
message.Append('.');
message.AppendInt(event->minor_code);
break;
}
XCloseDisplay(tmpDisplay);
}
}
@ -130,9 +143,9 @@ int X11Error(Display* display, XErrorEvent* event) {
void InstallX11ErrorHandler() {
XSetErrorHandler(X11Error);
if (PR_GetEnv("MOZ_X_SYNC")) {
Display* display = mozilla::DefaultXDisplay();
if (display) {
if (Display* display = mozilla::DefaultXDisplay()) {
QueryXExtensions(display);
if (PR_GetEnv("MOZ_X_SYNC")) {
XSynchronize(display, X11True);
}
}