<html>
<head>
<meta content="text/html; charset=iso-8859-15"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">Hi Keith,<br>
<br>
(2nd try)<br>
<br>
I went back in time and found your last post regarding this topic.
You did make some suggestions that got lost, probably due to my
discontinuing. Sorry about that. So let me pick it up again from
there, in order to hopefully get the case going.<br>
<br>
I will post an updated patch including your suggestions. Please
see my inline comments in this mail,
<meta http-equiv="content-type" content="text/html;
charset=iso-8859-15">
particularly on your last point.<br>
<br>
I tested the patch against a fresh Ubuntu Desktop 14.04.1 i386
(libx11-1.6.2). I verified that your test (nop.c) will fail before
and succeed after applying the patch.<br>
<br>
<br>
Am 30.12.2013 um 21:04 schrieb Keith Packard:<br>
</div>
<blockquote cite="mid:86vby65cmq.fsf@miki.keithp.com" type="cite">
<pre wrap="">Jonas Petersen <a class="moz-txt-link-rfc2396E" href="mailto:jnsptrsn1@gmail.com"><jnsptrsn1@gmail.com></a> writes:
</pre>
<blockquote type="cite">
<pre wrap="">By design, on 32-bit systems, the Xlib internal 32-bit request sequence
numbers may wrap. There is two locations within xcb_io.c that are not
wrap-safe though. The value of last_flushed relies on request to be
sequential all the time. This is not given in the moment when the sequence
has just wrapped. Applications may then crash with a "Fatal IO error 11
(Resource temporarily unavailable)".
This patch fixes this by "unwrapping" the sequence number when needed to
retain the sequence relative to last_flushed.
</pre>
</blockquote>
<pre wrap="">Reviewed-by: Keith Packard <a class="moz-txt-link-rfc2396E" href="mailto:keithp@keithp.com"><keithp@keithp.com></a>
There are some subtleties here which might be mentioned in comments:
</pre>
<blockquote type="cite">
<pre wrap="">+ unwrapped_request = dpy->request;
+ /* If there was a sequence number wrap since our last flush,
+ * make sure the sequence number we use, stays in sequence
+ * with dpy->xcb->last_flush. */
+ if (sizeof(uint64_t) > sizeof(unsigned long) && dpy->request < dpy->xcb->last_flushed)
+ unwrapped_request += UINT64_C(1) << 32;
</pre>
</blockquote>
<pre wrap="">The sizeof(uint64_t) > sizeof (unsigned long) test is an optimization;
dpy->request will *never* be less than last_flushed on a 64-bit system
(well, until we have to deal with 64-bit wrap). However, the check is
also useful to understand the append_pending_request call below.</pre>
</blockquote>
<br>
Yes, it's an optimization. It will have an effect at compile time
and it will make it end up only in 32-bit binaries. Actually there
was some discussion about that at some other branch of this topic.<br>
<br>
<blockquote cite="mid:86vby65cmq.fsf@miki.keithp.com" type="cite"><br>
<blockquote type="cite">
<pre wrap=""> uint64_t sequence;
- for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy->request; ++sequence)
+ for(sequence = dpy->xcb->last_flushed + 1; sequence <= unwrapped_request; ++sequence)
append_pending_request(dpy, sequence);
</pre>
</blockquote>
<pre wrap="">Here, we're passing a 64-bit sequence which may be 'unwrapped', in that
it can contain values above the maximum possible unsigned long sequence
number. However, that only happens (see check above) where unsigned long
is 32 bits. The 'sequence' formal in append_pending_request is an
unsigned long, and so any time the sequence passed might have a high
sequence value, it will get trimmed off by the type conversion.
Do we want an '(unsigned long)' cast in the actual here? It would be
strictly for documentation. Probably best to just mention what's
happening in a comment instead</pre>
</blockquote>
<br>
Agreed, I will add a comment.<br>
<br>
<blockquote cite="mid:86vby65cmq.fsf@miki.keithp.com" type="cite">
<blockquote type="cite">
<pre wrap=""> }
- requests = dpy->request - dpy->xcb->last_flushed;
+ requests = unwrapped_request - dpy->xcb->last_flushed;
dpy->xcb->last_flushed = dpy->request;
</pre>
</blockquote>
<pre wrap="">I think last_flushed should be changed from uint64_t to unsigned long to
match all of the Xlib types. </pre>
</blockquote>
<br>
By examining the usages of last_flushed, I'd say it makes a lot of
sense changing it to unsigned long. Added it to the patch.<br>
<br>
<blockquote cite="mid:86vby65cmq.fsf@miki.keithp.com" type="cite">
<pre wrap="">That would require a cast in the loop
above:
+ for(sequence = (uint64_t) dpy->xcb->last_flushed + 1; sequence <= unwrapped_request; ++sequence)</pre>
</blockquote>
<br>
Added that as well.<br>
<br>
<blockquote cite="mid:86vby65cmq.fsf@miki.keithp.com" type="cite">
<pre wrap="">I think there's also a problem in require_socket -- it compares a 64-bit
value from xcb with a 32-bit local value. I think we need to change that
to:
uint64_t sent64;
unsigned long sent;
sent = sent64
if ((long) (sent - dpy->last_request_read) < 0)
throw_thread_fail_assert("sequence wrapped")
This would only allow for 31-bit differences.
</pre>
</blockquote>
<br>
Here I'm not sure if I really get what you mean. So you would
introduce another local variable instead of casting where
appropriate? Please see my patch if I applied that right.<br>
<br>
By the way, the line following next...<br>
<br>
dpy->xcb->last_flushed = dpy->request = sent;<br>
<br>
...now also is much more obvious. Because before it was a
64-32-64-bit assignment. Now it is 32-32-32. In my ealier patches I
had added a comment to that line (which now would be obsolete):<br>
<br>
/* Note: The following line will truncate the 64bit 'sent'<br>
* to 32bit for 'dpy->request'. This truncated value will<br>
* then be assigned to the 64-bit 'dpy->xcb->last_flushed'<br>
* (which is intended). */<br>
dpy->xcb->last_flushed = dpy->request = sent;<br>
<br>
Regards<br>
Jonas<br>
</body>
</html>