kern/128714: gmtime infinty loop

Giorgos Keramidas keramida at freebsd.org
Mon Nov 10 21:20:06 PST 2008


The following reply was made to PR kern/128714; it has been noted by GNATS.

From: Giorgos Keramidas <keramida at freebsd.org>
To: Bruce Cran <bruce at cran.org.uk>
Cc: bug-followup at 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 at 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];
 %%%


More information about the freebsd-bugs mailing list