diff --git a/libX11-race-condition.patch b/libX11-race-condition.patch new file mode 100644 index 0000000..c01c3a0 --- /dev/null +++ b/libX11-race-condition.patch @@ -0,0 +1,109 @@ +diff --git a/src/Xxcbint.h b/src/Xxcbint.h +index 4ef13d2f..d8293259 100644 +--- a/src/Xxcbint.h ++++ b/src/Xxcbint.h +@@ -27,6 +27,7 @@ typedef struct _X11XCBPrivate { + PendingRequest *pending_requests; + PendingRequest *pending_requests_tail; + xcb_generic_event_t *next_event; ++ void *next_response; + char *real_bufmax; + char *reply_data; + int reply_length; +diff --git a/src/xcb_io.c b/src/xcb_io.c +index 0bd1fdf9..4be75408 100644 +--- a/src/xcb_io.c ++++ b/src/xcb_io.c +@@ -282,22 +282,83 @@ static xcb_generic_reply_t *poll_for_event(Display *dpy, Bool queued_only) + static xcb_generic_reply_t *poll_for_response(Display *dpy) + { + void *response; +- xcb_generic_error_t *error; ++ xcb_generic_reply_t *event; + PendingRequest *req; +- while(!(response = poll_for_event(dpy, False)) && +- (req = dpy->xcb->pending_requests) && +- !req->reply_waiter) ++ ++ while(1) + { ++ xcb_generic_error_t *error = NULL; + uint64_t request; ++ Bool poll_queued_only = dpy->xcb->next_response != NULL; + +- if(!xcb_poll_for_reply64(dpy->xcb->connection, req->sequence, +- &response, &error)) { +- /* xcb_poll_for_reply64 may have read events even if +- * there is no reply. */ +- response = poll_for_event(dpy, True); ++ /* Step 1: is there an event in our queue before the next ++ * reply/error? Return that first. ++ * ++ * If we don't have a reply/error saved from an earlier ++ * invocation we check incoming events too, otherwise only ++ * the ones already queued. ++ */ ++ response = poll_for_event(dpy, poll_queued_only); ++ if(response) + break; ++ ++ /* Step 2: ++ * Response is NULL, i.e. we have no events. ++ * If we are not waiting for a reply or some other thread ++ * had dibs on the next reply, exit. ++ */ ++ req = dpy->xcb->pending_requests; ++ if(!req || req->reply_waiter) ++ break; ++ ++ /* Step 3: ++ * We have some response (error or reply) related to req ++ * saved from an earlier invocation of this function. Let's ++ * use that one. ++ */ ++ if(dpy->xcb->next_response) ++ { ++ if (((xcb_generic_reply_t*)dpy->xcb->next_response)->response_type == X_Error) ++ { ++ error = dpy->xcb->next_response; ++ response = NULL; ++ } ++ else ++ { ++ response = dpy->xcb->next_response; ++ error = NULL; ++ } ++ dpy->xcb->next_response = NULL; ++ } ++ else ++ { ++ /* Step 4: pull down the next response from the wire. This ++ * should be the 99% case. ++ * xcb_poll_for_reply64() may also pull down events that ++ * happened before the reply. ++ */ ++ if(!xcb_poll_for_reply64(dpy->xcb->connection, req->sequence, ++ &response, &error)) { ++ /* if there is no reply/error, xcb_poll_for_reply64 ++ * may have read events. Return that. */ ++ response = poll_for_event(dpy, True); ++ break; ++ } ++ ++ /* Step 5: we have a new response, but we may also have some ++ * events that happened before that response. Return those ++ * first and save our reply/error for the next invocation. ++ */ ++ event = poll_for_event(dpy, True); ++ if(event) ++ { ++ dpy->xcb->next_response = error ? error : response; ++ response = event; ++ break; ++ } + } + ++ /* Step 6: actually handle the reply/error now... */ + request = X_DPY_GET_REQUEST(dpy); + if(XLIB_SEQUENCE_COMPARE(req->sequence, >, request)) + { diff --git a/libX11.spec b/libX11.spec index 8f6d50f..67cd044 100644 --- a/libX11.spec +++ b/libX11.spec @@ -5,7 +5,7 @@ Summary: Core X11 protocol client library Name: libX11 Version: 1.6.12 -Release: 2%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} +Release: 3%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} License: MIT URL: http://www.x.org @@ -18,6 +18,8 @@ Source0: https://xorg.freedesktop.org/archive/individual/lib/%{name}-%{version}. %endif Patch2: dont-forward-keycode-0.patch +# diff from https://gitlab.freedesktop.org/xorg/lib/libx11/-/merge_requests/53 +Patch3: libX11-race-condition.patch BuildRequires: make BuildRequires: xorg-x11-util-macros >= 1.11 @@ -57,6 +59,7 @@ libX11/libxcb interoperability library %prep %setup -q -n %{tarball}-%{?gitdate:%{gitdate}}%{!?gitdate:%{version}} %patch2 -p1 -b .dont-forward-keycode-0 +%patch3 -p1 -b .race-condition %build autoreconf -v --install --force @@ -122,6 +125,9 @@ make %{?_smp_mflags} check %{_mandir}/man5/*.5* %changelog +* Mon Nov 09 2020 Peter Hutterer 1.6.12-3 +- Fix a race-condition in poll_for_response (#1758384) + * Thu Nov 5 11:12:56 AEST 2020 Peter Hutterer - 1.6.12-2 - Add BuildRequires for make