Broken XNextEvent()(libX11 1.1.2 - 1.1.5)
walter harms
wharms at bfs.de
Tue Sep 30 02:41:35 PDT 2008
mmh,
i am not an expenrt on xorg internal but why not add
if (!XPending()) return; to XNextEvent(); ?
that would translate old stile loop into the new form
and leave other programs with 2 Pending() calls, what
should be harmless. in the long run the if would eliminate
the if XPending() from all the loops in the current programs.
re
wh
Fumihito YOSHIDA schrieb:
> Hi lists,
>
> In libX11 1.1.2 (and newer), XNextEvent() sometimes segfault by null
> exception.
>
> This problem look like come from _XReadEvents()/_XSend() behavior.
> The problem is not reproduce in 1.1.1 and old.
>
> Compiz and IIIMF fall under this problem, but these are typically
> example, I think that many programs stuck by this problem.
>
> Is it bug, or new specification?
>
> =====================
> Details:
> =====================
>
> A new implementation of _XReadEvents() is lockless, and compatible
> for olddays behavior, but it cause segfault at some conditions.
>
> (_XReadEvents() take least one events, but when XLostDisplay flag is
> true, _XReadEvents() does not returned any valid events.
> So, it cause segfault in XNextEvent() by null pointer exception.),
>
> For example, Florian Echtler said in below mail,
> http://lists.freedesktop.org/archives/xorg/2008-September/038344.html
> this crash is typicial pattern of this bug.
>
> This is *not* coding issue, but you can evade this problem with some
> coding design.
>
> Case1: Classical X event loop
> // It will cause segfault in some conditions....
>
> Display *pdisplay;
> XEvent event;
> pdisplay = XOpenDisplay(NULL);
>
> for (; ;){
> XNextEvent(pdisplay, &event);
> /* X Event Handler */
> }
>
> This code (rarely) causes segfault at XNextEvent().
> If you trace it, you will find below crash point.
>
> --- XNextEvent() ----------------------------------
> int
> XNextEvent (
> register Display *dpy,
> register XEvent *event)
> {
> register _XQEvent *qelt;
>
> LockDisplay(dpy);
>
> if (dpy->head == NULL)
> _XReadEvents(dpy); // <- it hope _XReadEvents return valid
> // handler, it believev
> dpy->head != null...
> qelt = dpy->head;
> *event = qelt->event; // <- but, dpy->head->event is null, CRASH.
> // Because dpy->head is null!
> _XDeq(dpy, NULL, qelt);
> UnlockDisplay(dpy);
> return 0;
> }
> --------------------------------------------------
>
> If you replace "if(dpy->head == null)" to "while(dpy->head == null)",
> the problem solved.
> // Notice: if => while replacement cause busy loop and possible infinite loop.
>
> This segfaults conditions are:
> a) X Event queue is empty.
> b) XDisplayIOError is true.
> You call XNextEvent() when (a && b), your program will segfault.
>
>
> Case2: Modern X event loop style is below:
> // It wont cause segfault, and lockless.
>
> Display *pdisplay;
> XEvent event;
> pdisplay = XOpenDisplay(NULL);
>
> for (; ;){
> if (XPending()){
> XNextEvent(pdisplay, &event);
> /* X Event Handler */
> }
> /* other event looping and some usleeps. */
> }
>
> Because this implement want evading XNextEvent()'s blocking.
> XNextEvent() always return least one events, but when X event
> queue is empty, cause blocking-wait for next new events.
>
> But, man XNextEvent(3) says:
> | The XNextEvent function copies the first event from the event queue
> | into the specified XEvent structure and then removes it from the queue.
> | If the event queue is empty, XNextEvent flushes the output buffer and
> | blocks until an event is received.
>
> Current implement is not "blocks", "sometimes blocks, sometimes crash".
>
> And we have big issue, the classical X event loop(Case1) are not failure
> in old-days, their coding were(are?) right. (But, their old style coding are not
> efficient, we need modern style.).
>
> We can find their classical event loop in many code asset, they will crash
> by this problem.....
>
> =====================
> Root cause:
> =====================
> It cause by xcb_io.c::_XReadEvents() and xcb_io.c::_XSend().
>
> When dpy->head is null, the XNextEvent() called _XReadEvents(),
> but xcb_io.c::_XReadEvents() and xcb_io.c::_XSend() has dpy->flags check,
> when XlibDiskpayIOError bit is set, their procedure return without any work.
>
> if(dpy->flags & XlibDisplayIOError)
> return;
>
> So, XNextEvent()'s dpy is still null, and crash.
>
> I suggest dirty hack.
> XlibDisplayIOError flag can be cleard with some wait times.
>
> --- NextEvent.c.orig
> +++ NextEvent.c
> @@ -45,9 +45,14 @@
> register _XQEvent *qelt;
>
> LockDisplay(dpy);
>
> - if (dpy->head == NULL)
> + while(dpy->head == NULL){
> _XReadEvents(dpy);
> + usleep(400);
> + }
> qelt = dpy->head;
> *event = qelt->event;
> _XDeq(dpy, NULL, qelt);
>
>
> Regards,
> _______________________________________________
> xorg mailing list
> xorg at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/xorg
>
>
More information about the xorg
mailing list