diff options
author | Dmitry Osipenko <digetx@gmail.com> | 2019-05-18 19:10:32 +0300 |
---|---|---|
committer | Adam Jackson <ajax@nwnk.net> | 2019-10-09 17:37:10 +0000 |
commit | f5ba2c632a4c84279bdd48c687271292f5dc4f87 (patch) | |
tree | d7ab475b62a67a1d7c0490ff68cc9dc589fbf765 /src | |
parent | 1f1ca0863fd81fd0538b104eb9d9841ddbc7c905 (diff) |
Fix lockup in _XReply() caused by recursive synchronization
This patch is based on a suggestion made by Uli Schlachter in a comment
to the bug report https://gitlab.freedesktop.org/xorg/lib/libx11/issues/93.
Explanation of the bug (given by Uli Schlachter as well):
An error was received and handled. Since there was an error callback set,
Xlib unlocks the display, runs the error callback, and then locks the display
again. This goes through _XLockDisplay and then calls _XSeqSyncFunction.
On this "lock the thing"-path, Xlib notices that sequence numbers are close to
wrap-around and tries to send a GetInputFocus request. However, the earlier
calls already registered themselves as "we are handling replies/errors, do
not interfere!" and so the code here waits for "that other thread" to be done
before it continues. Only that there is no other thread, but it is this thread
itself and thus a deadlock follows.
The bug is relatively easy to reproduce on any desktop environment by
using actively a touchscreen input that supports multitouch, i.e. practically
all mobile devices are affected.
Fixes: https://gitlab.freedesktop.org/xorg/lib/libx11/issues/93
Suggested-by: Uli Schlachter <psychon@znc.in>
Tested-by: Dmitry Osipenko <digetx@gmail.com>
Reported-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/OpenDis.c | 1 | ||||
-rw-r--r-- | src/XlibInt.c | 4 |
2 files changed, 4 insertions, 1 deletions
diff --git a/src/OpenDis.c b/src/OpenDis.c index 82723578..717de339 100644 --- a/src/OpenDis.c +++ b/src/OpenDis.c @@ -201,6 +201,7 @@ XOpenDisplay ( X_DPY_SET_LAST_REQUEST_READ(dpy, 0); dpy->default_screen = iscreen; /* Value returned by ConnectDisplay */ dpy->last_req = (char *)&_dummy_request; + dpy->req_seq_syncing = False; /* Initialize the display lock */ if (InitDisplayLock(dpy) != 0) { diff --git a/src/XlibInt.c b/src/XlibInt.c index 4e45e62b..e4fb4e5f 100644 --- a/src/XlibInt.c +++ b/src/XlibInt.c @@ -218,10 +218,12 @@ void _XSeqSyncFunction( xGetInputFocusReply rep; _X_UNUSED register xReq *req; - if ((X_DPY_GET_REQUEST(dpy) - X_DPY_GET_LAST_REQUEST_READ(dpy)) >= (65535 - BUFSIZE/SIZEOF(xReq))) { + if ((X_DPY_GET_REQUEST(dpy) - X_DPY_GET_LAST_REQUEST_READ(dpy)) >= (65535 - BUFSIZE/SIZEOF(xReq)) && !dpy->req_seq_syncing) { + dpy->req_seq_syncing = True; GetEmptyReq(GetInputFocus, req); (void) _XReply (dpy, (xReply *)&rep, 0, xTrue); sync_while_locked(dpy); + dpy->req_seq_syncing = False; } else if (sync_hazard(dpy)) _XSetPrivSyncFunction(dpy); } |