summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2022-08-05 15:19:08 -0400
committerAdam Jackson <ajax@nwnk.net>2022-11-02 14:05:38 +0000
commit79775575418fd6f8ee1c5e5bbe403df4606fb5b6 (patch)
tree9b8a09d27db72afacba7a5f5b6fd9d34da64d625
parent0d1d65bdd98966f52bcac4077f94827b20b229dd (diff)
downloadxorg-lib-libX11-79775575418fd6f8ee1c5e5bbe403df4606fb5b6.tar.gz
Allow X*IfEvent() to reenter libX11
The documentation for this family of functions very clearly says not to call into xlib in your predicate function, but historically single threaded apps could get away with it just fine, and now that we've forced thread-safety on the world such apps will now deadlock instead. That's not an acceptable regression even if the app is technically broken. This has been reported with XFCE and FVWM, and Motif's cut-and-paste code has the same bug by inspection, so this does need to be addressed. This change nerfs LockDisplay/UnlockDisplay while inside the critical bit of an IfEvent function. This is still safe in the sense that the display remains locked and no other thread should be able to change it from under us, but the loop that scans the event queue might not be robust against it being modified as a side effect of protocol emitted by the predicate callback. But that's not new, non-XInitThreads'd xlib would have the same caveat. Closes: xorg/lib/libx11#157
-rw-r--r--include/X11/Xlibint.h1
-rw-r--r--src/ChkIfEv.c3
-rw-r--r--src/IfEvent.c2
-rw-r--r--src/OpenDis.c1
-rw-r--r--src/PeekIfEv.c2
-rw-r--r--src/locking.c30
6 files changed, 39 insertions, 0 deletions
diff --git a/include/X11/Xlibint.h b/include/X11/Xlibint.h
index cbf3aac3..b4275ebd 100644
--- a/include/X11/Xlibint.h
+++ b/include/X11/Xlibint.h
@@ -207,6 +207,7 @@ struct _XDisplay
XIOErrorExitHandler exit_handler;
void *exit_handler_data;
+ Bool in_ifevent;
};
#define XAllocIDs(dpy,ids,n) (*(dpy)->idlist_alloc)(dpy,ids,n)
diff --git a/src/ChkIfEv.c b/src/ChkIfEv.c
index 876a850e..327b5eaf 100644
--- a/src/ChkIfEv.c
+++ b/src/ChkIfEv.c
@@ -50,6 +50,7 @@ Bool XCheckIfEvent (
int n; /* time through count */
LockDisplay(dpy);
+ dpy->in_ifevent = True;
prev = NULL;
for (n = 3; --n >= 0;) {
for (qelt = prev ? prev->next : dpy->head;
@@ -60,6 +61,7 @@ Bool XCheckIfEvent (
*event = qelt->event;
_XDeq(dpy, prev, qelt);
_XStoreEventCookie(dpy, event);
+ dpy->in_ifevent = False;
UnlockDisplay(dpy);
return True;
}
@@ -78,6 +80,7 @@ Bool XCheckIfEvent (
/* another thread has snatched this event */
prev = NULL;
}
+ dpy->in_ifevent = False;
UnlockDisplay(dpy);
return False;
}
diff --git a/src/IfEvent.c b/src/IfEvent.c
index ead93dca..a0aed7e3 100644
--- a/src/IfEvent.c
+++ b/src/IfEvent.c
@@ -49,6 +49,7 @@ XIfEvent (
unsigned long qe_serial = 0;
LockDisplay(dpy);
+ dpy->in_ifevent = True;
prev = NULL;
while (1) {
for (qelt = prev ? prev->next : dpy->head;
@@ -59,6 +60,7 @@ XIfEvent (
*event = qelt->event;
_XDeq(dpy, prev, qelt);
_XStoreEventCookie(dpy, event);
+ dpy->in_ifevent = False;
UnlockDisplay(dpy);
return 0;
}
diff --git a/src/OpenDis.c b/src/OpenDis.c
index 5017b040..e1bc2a30 100644
--- a/src/OpenDis.c
+++ b/src/OpenDis.c
@@ -189,6 +189,7 @@ XOpenDisplay (
dpy->xcmisc_opcode = 0;
dpy->xkb_info = NULL;
dpy->exit_handler_data = NULL;
+ dpy->in_ifevent = False;
/*
* Setup other information in this display structure.
diff --git a/src/PeekIfEv.c b/src/PeekIfEv.c
index 207cd119..c4e8af0d 100644
--- a/src/PeekIfEv.c
+++ b/src/PeekIfEv.c
@@ -50,6 +50,7 @@ XPeekIfEvent (
unsigned long qe_serial = 0;
LockDisplay(dpy);
+ dpy->in_ifevent = True;
prev = NULL;
while (1) {
for (qelt = prev ? prev->next : dpy->head;
@@ -63,6 +64,7 @@ XPeekIfEvent (
_XStoreEventCookie(dpy, &copy);
*event = copy;
}
+ dpy->in_ifevent = False;
UnlockDisplay(dpy);
return 0;
}
diff --git a/src/locking.c b/src/locking.c
index ea5000e1..36530691 100644
--- a/src/locking.c
+++ b/src/locking.c
@@ -455,6 +455,32 @@ static void _XDisplayLockWait(
static void _XLockDisplay(
Display *dpy
XTHREADS_FILE_LINE_ARGS
+ );
+
+static void _XIfEventLockDisplay(
+ Display *dpy
+ XTHREADS_FILE_LINE_ARGS
+ )
+{
+ /* assert(dpy->in_ifevent); */
+}
+
+static void _XIfEventUnlockDisplay(
+ Display *dpy
+ XTHREADS_FILE_LINE_ARGS
+ )
+{
+ if (dpy->in_ifevent)
+ return;
+
+ dpy->lock_fns->lock_display = _XLockDisplay;
+ dpy->lock_fns->unlock_display = _XUnlockDisplay;
+ UnlockDisplay(dpy);
+}
+
+static void _XLockDisplay(
+ Display *dpy
+ XTHREADS_FILE_LINE_ARGS
)
{
#ifdef XTHREADS
@@ -478,6 +504,10 @@ static void _XLockDisplay(
#endif
_XIDHandler(dpy);
_XSeqSyncFunction(dpy);
+ if (dpy->in_ifevent) {
+ dpy->lock_fns->lock_display = _XIfEventLockDisplay;
+ dpy->lock_fns->unlock_display = _XIfEventUnlockDisplay;
+ }
}
/*