bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

strftime.c problem with very big tm_year.


From: Tanaka Akira
Subject: strftime.c problem with very big tm_year.
Date: 16 Dec 2001 13:33:20 +0900
User-agent: T-gnus/6.14.5 (based on Gnus v5.8.7) (revision 08) SEMI/1.14.0 (Iburihashi) Deisui/1.14.0 (Kikuhime) APEL/10.3 Emacs/21.0.104 (i386-unknown-freebsd4.2) MULE/5.0 (SAKAKI)

I found a non-practical problem with strftime.c in gawk-3.1.0.
Strictly speaking, I think this is not a bug of gawk because I
couldn't produce the problem with the awk command.

strftime.c have a problem with very big tm_year which overflows 32bit
int.  I found this on Linux on Alpha, which have 64bit long/time_t and
32bit int.  64bit time_t can represent such year.

$ uname -mrsv
Linux 2.2.18pre21 #1 Wed Nov 22 05:08:09 CST 2000 alpha
$ cat tst.c
#include <stdio.h>
#include <time.h>

int main()
{
  struct tm tmp;
  char buf[128];

  tmp.tm_year = 2147483647;
  strftime(buf, 128, "%C %g %G %Y %v", &tmp);
  puts(buf);
  return 0;
}
$ gcc -DHAVE_TM_ZONE tst.c strftime.c 
$ ./a.out 
-21474817 -49 -2147481749 -2147481749 31-JAN--2147481749

It should be:

21474855 47 2147485547 2147485547 31-JAN-2147485547

This is caused by several occurence of `1900 + timeptr->tm_year' in
strftime.c.  Because 1900 and tm_year is 32bit int, the expression
overflows and the result is -21474817.  For example, the problem can
be avoided by using long as:

--- strftime.c- Sat Dec 15 20:08:43 2001
+++ strftime.c  Sat Dec 15 20:10:22 2001
@@ -126,7 +126,8 @@
        char *start = s;
        auto char tbuf[100];
        long off;
-       int i, w, y;
+       int i, w;
+       long y;
        static short first = 1;
 #ifdef POSIX_SEMANTICS
        static char *savetz = NULL;
@@ -263,7 +264,7 @@
 
                case 'C':
                century:
-                       sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100);
+                       sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 
100);
                        break;
 
                case 'd':       /* day of the month, 01 - 31 */
@@ -300,16 +301,16 @@
                         */
                        w = iso8601wknum(timeptr);
                        if (timeptr->tm_mon == 11 && w == 1)
-                               y = 1900 + timeptr->tm_year + 1;
+                               y = 1900L + timeptr->tm_year + 1;
                        else if (timeptr->tm_mon == 0 && w >= 52)
-                               y = 1900 + timeptr->tm_year - 1;
+                               y = 1900L + timeptr->tm_year - 1;
                        else
-                               y = 1900 + timeptr->tm_year;
+                               y = 1900L + timeptr->tm_year;
 
                        if (*format == 'G')
-                               sprintf(tbuf, "%d", y);
+                               sprintf(tbuf, "%ld", y);
                        else
-                               sprintf(tbuf, "%02d", y % 100);
+                               sprintf(tbuf, "%02ld", y % 100);
                        break;
 
                case 'h':       /* abbreviated month name */
@@ -433,7 +434,7 @@
 
                case 'Y':       /* year with century */
                fullyear:
-                       sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
+                       sprintf(tbuf, "%ld", 1900L + timeptr->tm_year);
                        break;
 
                /*
@@ -532,10 +533,10 @@
 
 #ifdef VMS_EXT
                case 'v':       /* date as dd-bbb-YYYY */
-                       sprintf(tbuf, "%2d-%3.3s-%4d",
+                       sprintf(tbuf, "%2d-%3.3s-%4ld",
                                range(1, timeptr->tm_mday, 31),
                                months_a[range(0, timeptr->tm_mon, 11)],
-                               timeptr->tm_year + 1900);
+                               timeptr->tm_year + 1900L);
                        for (i = 3; i < 6; i++)
                                if (islower(tbuf[i]))
                                        tbuf[i] = toupper(tbuf[i]);
@@ -568,7 +569,7 @@
 /* isleap --- is a year a leap year? */
 
 static int
-isleap(int year)
+isleap(long year)
 {
        return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
 }
@@ -651,7 +652,7 @@
                        dec31ly.tm_mon = 11;
                        dec31ly.tm_mday = 31;
                        dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
-                       dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900);
+                       dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L);
                        weeknum = iso8601wknum(& dec31ly);
 #endif
                }
-- 
Tanaka Akira



reply via email to

[Prev in Thread] Current Thread [Next in Thread]