[PATCH 1/2] os: Fix buggy integer comparison.
Alan Coopersmith
alan.coopersmith at oracle.com
Sun Mar 6 12:04:53 PST 2011
On 03/ 6/11 11:39 AM, Cyril Brulebois wrote:
> - while (timers && (int) (timers->expires - now) <= 0)
> + while (timers && (timers->expires <= now))
That's restoring the original X11R6 code and undoing the bugfixes from
X11R6.6/XFree86 days to handle GetTimeInMillis wraparound.
http://www.mail-archive.com/xpert@xfree86.org/msg05383.html has some
information, and even more can be found in this bug reports from the old
closed X.Org database for this problem:
To: xbugs at x.org, patch at xfree86.org
Subject: Xserver: rollover condition in XdmcpWakeupHandler()
VERSION:
X.Org: R6.6
XFree86: Current 4.2 CVS tree as of 18-Feb-2002
CLIENT MACHINE and OPERATING SYSTEM:
HP-UX
DISPLAY TYPE:
N/A
WINDOW MANAGER:
N/A
COMPILER:
ANSI cc on HP-UX
Others?
AREA:
Xserver
SYNOPSIS:
It looks like there is a rollover condition in
xc/programs/Xserver/os/xdmcp.c:XdmcpWakeupHandler()
which can cause XDM sessions to be terminated.
DESCRIPTION:
The XDMCP code calculates its timeout time incorrectly
when the time wraps from 0xffffffff to 0x00000000.
The routine XdmcpWakeupHandler() currently has the following
comparison in its 'else if' condition:
else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
{
if (state == XDM_RUN_SESSION)
{
state = XDM_KEEPALIVE;
send_packet();
}
else
timeout();
}
A problem with this test occurs when we wrap back to 0 every 49+
days. When this occurs, Xservers with active XDMCP sessions
will send XDM_KEEPALIVE messages to the XDMCP host continually
for ~3 minutes. If the host computer cannot reply to all of the
keep-alive messages in time, the Xservers seem to assume that the
host is dead, and the server terminates any XDM sessions.
Whether or not the session is closed will depend on the network
load, etc.
If the test in the 'else if' branch is changed from:
else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
to:
else if (timeOutTime && (int)(GetTimeInMillis() - timeOutTime) >= 0)
the problem is avoided. As a result, the XDM_KEEPALIVE
sessions aren't sent continuously.
REPEAT BY:
You could wait the 49+ days for the rollover to occur. Or
the following sample program indicates the differences
in the two comparisons used in the 'else if' branch.
This might not reconstruct the problem exactly, but it
should indicate whether or not a compiler generates
code that will hit the problem.
#include <stdio.h>
#include <stdlib.h>
unsigned int timeOutTime, GetTimeInMillis, GetTimeInSec;
int millis;
main()
{
int test1, test2, timeOut;
int n; int days;
/* Start with time of day close to the value where
* (time_of_day_in_sec*1000) overflows an unsigned int.
*/
GetTimeInSec = 49*24*3600 + 16*3600; /* 49 days, 16 hours*/
GetTimeInMillis = 0;
millis = 0;
timeOut = 2; /* Always set time out to 2 millisec */
timeOutTime = GetTimeInMillis + timeOut;
n = 0;
for (;;)
{
test1=0;
test2=0;
if (timeOutTime && GetTimeInMillis >= timeOutTime) {
/* timeOutTime should always be > GetTimeInMillis */
test1 = 1;
}
if (timeOutTime && (int)(GetTimeInMillis-timeOutTime) >= 0 ) {
/* timeOutTime should always be > GetTimeInMillis */
test2 = 1;
}
if(test1!=0 || test2!=0) {
printf('test1 = 0, test2 = 0
', test1, test2);
if(test1!=0) {
printf('Test1 failed when time = 0 sec and 0 millisec
',
GetTimeInSec, millis);
}
if(test2!=0) {
printf('Test2 failed when time = 0 sec and 0 millisec
',
GetTimeInSec, millis);
}
printf('GetTimeInSec*1000 = 0x0
', GetTimeInSec*1000);
printf('GetTimeInMillis = 0x0
', GetTimeInMillis);
printf('timeOutTime = 0x0
', timeOutTime);
exit(1);
}
millis = millis +1;
if(millis == 1000) {
GetTimeInSec = GetTimeInSec + 1;
millis = 0;
}
GetTimeInMillis = GetTimeInSec*1000 + millis;
timeOutTime = GetTimeInMillis + timeOut;
n++;
if(n==0x100000) {
n=0;
printf('0 0
', GetTimeInMillis, timeOutTime);
}
}
}
Under HP-UX, the following output occurs:
ffd68400 ffd68402
ffe68400 ffe68402
fff68400 fff68402
test1 = 1, test2 = 0
Test1 failed when time = 4294967 sec and 295 millisec
GetTimeInSec*1000 = 0xfffffed8
GetTimeInMillis = 0xffffffff
timeOutTime = 0x1
This indicates that the two calculations differ every 4294967.295 sec.
This should be verified on other OSes and other compilers to
see how general a problem this is.
SAMPLE FIX:
The following diff is against the xdmcp.c file found in
the XFree86 4.2.0 release:
$ diff -c xdmcp.c.v4.2 xdmcp.c.fix
*** xdmcp.c.v4.2 Tue Feb 19 01:21:03 2002
--- xdmcp.c.fix Tue Feb 19 01:21:46 2002
***************
*** 726,732 ****
if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
}
! else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
{
if (state == XDM_RUN_SESSION)
{
--- 726,732 ----
if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
}
! else if (timeOutTime && (int)(GetTimeInMillis() - timeOutTime) >= 0)
{
if (state == XDM_RUN_SESSION)
{
Please feel free to contact me with any questions.
-paul
--
-Alan Coopersmith- alan.coopersmith at oracle.com
Oracle Solaris Platform Engineering: X Window System
More information about the xorg-devel
mailing list