Date: Tue, 11 Nov 2008 05:20:05 GMT From: Giorgos Keramidas <keramida@freebsd.org> To: freebsd-bugs@FreeBSD.org Subject: Re: kern/128714: gmtime infinty loop Message-ID: <200811110520.mAB5K5lI073797@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/128714; it has been noted by GNATS. From: Giorgos Keramidas <keramida@freebsd.org> To: Bruce Cran <bruce@cran.org.uk> Cc: bug-followup@freebsd.org Subject: Re: kern/128714: gmtime infinty loop Date: Tue, 11 Nov 2008 07:00:06 +0200 On Mon, 10 Nov 2008 07:45:37 -0800, Bruce Cran <bruce@cran.org.uk> wrote: > On an 8-CURRENT amd64 machine I get the stack trace: > > #0 0x00000008007053df in atexit () from /lib/libc.so.7 > #1 0x0000000800706c8e in timeoff () from /lib/libc.so.7 > #2 0x0000000800707355 in gmtime () from /lib/libc.so.7 > #3 0x0000000000400638 in test (t=-33884019326476801) at test.c:7 > #4 0x0000000000400686 in main () at test.c:15 This looks like an exit() handler, running after ^C was pressed or similar. The real bug seems to be in localtime.ctimesub(). When the last second of a non-leap year is passed to timesub() it starts 'oscillating' between days = -1 and days = 365: $ env LD_PRELOAD=$HOME/obj-amd64/$HOME/ws/head/lib/libc/libc.so.7 \ ./foo 2>&1 | head -30 days -392176149613 : y 1970 yleap 1 ylen 366 days 260555599 : y -1074453235 yleap 0 ylen 365 days -172760 : y -1073739385 yleap 0 ylen 365 days 365 : y -1073739859 yleap 0 ylen 365 days -1 : y -1073739858 yleap 0 ylen 365 days 365 : y -1073739859 yleap 0 ylen 365 days -1 : y -1073739858 yleap 0 ylen 365 [repeat...] The following patch fixes this for me on ref8-amd64 at freebsd.org, but I want to write a mode detailed description of the changes, and test it a bit more before it is anywhere near 'committable' state. A slightly less "hacky" version of the patch is probably a good idea too. I don't like the exception of ``days == year_lengths[yleap]'' near line 1380, and there's probably a slightly cleaner way to make sure the iteration converges to the correct date after a finite number of iterations. The patch is... %%% Try to avoid 'oscillating' between -1 and 365 days in timesub(). XXX: A more detailed explanation of why this happens is needed here. Submitted by: Vladimir Timfeev PR: kern/128714 Index: lib/libc/stdtime/localtime.c =================================================================== --- lib/libc/stdtime/localtime.c (revision 184823) +++ lib/libc/stdtime/localtime.c (working copy) @@ -1366,7 +1366,7 @@ tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) - while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { + while (days < 0 || days > (long)year_lengths[yleap = isleap(y)]) { long newy; newy = y + days / DAYSPERNYEAR; @@ -1377,6 +1377,8 @@ LEAPS_THRU_END_OF(y - 1); y = newy; } + if (days == (long)year_lengths[yleap]) + days--; tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap]; %%%
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200811110520.mAB5K5lI073797>