Commit f5ba2c63 authored by Dmitry Osipenko's avatar Dmitry Osipenko Committed by Adam Jackson

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 #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: #93Suggested-by: Uli Schlachter's avatarUli Schlachter <psychon@znc.in>
Tested-by: Dmitry Osipenko's avatarDmitry Osipenko <digetx@gmail.com>
Reported-by: Dmitry Osipenko's avatarDmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dmitry Osipenko's avatarDmitry Osipenko <digetx@gmail.com>
parent 1f1ca086
......@@ -202,6 +202,9 @@ struct _XDisplay
unsigned long last_request_read_upper32bit;
unsigned long request_upper32bit;
#endif
/* avoid recursion on requests sequence number synchronization */
Bool req_seq_syncing; /* requests syncing is in-progress */
};
#define XAllocIDs(dpy,ids,n) (*(dpy)->idlist_alloc)(dpy,ids,n)
......
......@@ -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) {
......
......@@ -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);
}
......
  • I was able to compile the libX11-1.6.9 build from libX11-1.6.9.tar.gz in the https://www.x.org/releases/individual/lib/ and freeze it by increasing the CPU load of the Qt Application by quickly switching two buttons in the HMI through touch, Note: only libX11.so.6.3.0 from make install command was copied to the target /usr/lib64/ and made sure that is indeed loaded by running the lsof command.

    Other related components in the machine are as follows,Qt 5.9.7, KWIN 4.11.19-8, libXi 1.7.9-1 , xinput 1.6.2 and x11-server 1.20.1-5.6

    [local@bues3-sun724 ~]$ pstack 2883 Thread 3 (Thread 0x7f994c3af700 (LWP 2885)): #0 0x00007f995cafd20d in poll () from /lib64/libc.so.6

    #1 0x00007f995539c082 in _xcb_conn_wait () from /lib64/libxcb.so.1

    #2 0x00007f995539de6f in xcb_wait_for_event () from /lib64/libxcb.so.1

    #3 0x00007f994eb6fe19 in QXcbEventReader::run() () from /lib64/libQt5XcbQpa.so.5

    #4 0x00007f995d85be71 in QThreadPrivate::start(void*) () from /lib64/libQt5Core.so.5

    #5 (closed) 0x00007f995d2f6dd5 in start_thread () from /lib64/libpthread.so.0

    #6 0x00007f995cb07ead in clone () from /lib64/libc.so.6

    Thread 2 (Thread 0x7f9949d6b700 (LWP 3041)): #0 0x00007f995cafd20d in poll () from /lib64/libc.so.6

    #1 0x00007f9958bf5c4c in g_main_context_iterate.isra.22 () from /lib64/libglib-2.0.so.0

    #2 0x00007f9958bf5d7c in g_main_context_iteration () from /lib64/libglib-2.0.so.0

    #3 0x00007f995da5445c in QEventDispatcherGlib::processEvents(QFlagsQEventLoop::ProcessEventsFlag) () from /lib64/libQt5Core.so.5

    #4 0x00007f995da046db in QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) () from /lib64/libQt5Core.so.5 #5 (closed) 0x00007f995d8577f8 in QThread::exec() () from /lib64/libQt5Core.so.5

    #6 0x00007f994eabb3b5 in QDBusConnectionManager::run() () from /lib64/libQt5DBus.so.5

    #7 0x00007f995d85be71 in QThreadPrivate::start(void*) () from /lib64/libQt5Core.so.5

    #8 (moved) 0x00007f995d2f6dd5 in start_thread () from /lib64/libpthread.so.0

    #9 0x00007f995cb07ead in clone () from /lib64/libc.so.6

    Thread 1 (Thread 0x7f995ff27900 (LWP 2883)): #0 0x00007f995d2fa965 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0

    #1 0x00007f995603a685 in _XReply (dpy=dpy@entry=0xb3dd60, rep=rep@entry=0x7ffcea17fbc0, extra=extra@entry=0, discard=discard@entry=1) at xcb_io.c:603

    #2 0x00007f995603cf33 in _XSeqSyncFunction (dpy=0xb3dd60) at XlibInt.c:224

    #3 0x00007f995603c753 in _XError (dpy=dpy@entry=0xb3dd60, rep=rep@entry=0x7f9944004500) at XlibInt.c:1493

    #4 0x00007f9956039867 in handle_error (dpy=0xb3dd60, err=0x7f9944004500, in_XReply=) at xcb_io.c:199

    #5 (closed) 0x00007f9956039915 in handle_response (dpy=0xb3dd60, response=0x7f9944004500, in_XReply=) at xcb_io.c:324

    #6 0x00007f995603a75a in _XReply (dpy=0xb3dd60, rep=0x7ffcea17fdf0, extra=0, discard=0) at xcb_io.c:656 #7 0x00007f994e69e2fe in XIQueryDevice () from /lib64/libXi.so.6

    #8 (moved) 0x00007f994eb972bf in QXcbConnection::handleEnterEvent() () from /lib64/libQt5XcbQpa.so.5

    #9 0x00007f994eb82c47 in QXcbWindow::handleEnterNotifyEvent(int, int, int, int, unsigned char, unsigned char, unsigned int) () from /lib64/libQt5XcbQpa.so.5

    #10 0x00007f994eb83193 in QXcbWindow::handleXIEnterLeave(xcb_ge_event_t*) () from /lib64/libQt5XcbQpa.so.5

    #11 0x00007f994eb99f8c in QXcbConnection::xi2HandleEvent(xcb_ge_event_t*) () from /lib64/libQt5XcbQpa.so.5 #12 0x00007f994eb6e2a2 in QXcbConnection::handleXcbEvent(xcb_generic_event_t*) () from /lib64/libQt5XcbQpa.so.5 #13 0x00007f994eb7019e in QXcbConnection::processXcbEvents() () from /lib64/libQt5XcbQpa.so.5 #14 0x00007f995da2f1de in QObject::event(QEvent*) () from /lib64/libQt5Core.so.5 #15 0x00007f995e3fdd8c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /lib64/libQt5Widgets.so.5 #16 0x00007f995e404f68 in QApplication::notify(QObject*, QEvent*) () from /lib64/libQt5Widgets.so.5 #17 0x00007f995da05be6 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /lib64/libQt5Core.so.5 #18 (closed) 0x00007f995da08503 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () from /lib64/libQt5Core.so.5 #19 0x00007f995da54ab3 in postEventSourceDispatch(_GSource*, int ()(void), void*) () from /lib64/libQt5Core.so.5 #20 0x00007f9958bf5969 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0 #21 0x00007f9958bf5cc8 in g_main_context_iterate.isra.22 () from /lib64/libglib-2.0.so.0 #22 0x00007f9958bf5d7c in g_main_context_iteration () from /lib64/libglib-2.0.so.0 #23 0x00007f995da5445c in QEventDispatcherGlib::processEvents(QFlagsQEventLoop::ProcessEventsFlag) () from /lib64/libQt5Core.so.5 #24 0x00007f995da046db in QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) () from /lib64/libQt5Core.so.5 #25 0x00007f995da0cc04 in QCoreApplication::exec() () from /lib64/libQt5Core.so.5 #26 0x00000000004263a9 in main () [local@bues3-sun724 ~]$

  • Dmitry Osipenko @digetx

    mentioned in merge request !29

    ·

    mentioned in merge request !29

    Toggle commit list
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment