[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- strftime.c problem with very big tm_year.,
Tanaka Akira <=