proposed change to 'zic' to support "outlandish" offsets
Paul Eggert
eggert at CS.UCLA.EDU
Thu May 3 22:34:08 UTC 2007
"Olson, Arthur David \(NIH/NCI\) [E]" <olsona at dc37a.nci.nih.gov> writes:
> One possibility is to eliminate checks on hours greater than 24 in zic.c
> (with warnings thrown in when they occur).
> This minimizes changes that folks writing alternate parsers would need
> to make; if we're really lucky, those folks aren't checking the range of
> hours now and so won't need to make any changes.
Yes, thanks, that should work. I read through that change and found
some portability issues:
* The compiled file can represent UTC offsets from -2**31 to 2**31-1
seconds, which is -596523:14:08 to 596523:14:07 in hh:mm:ss
notation, but the 596523 exceeds the integer limit on a host with
16-bit int.
* zic should guard against overflow when multiplying the hour count by
60*60, and also when adding (mm*60+ss) to (hh*60*60).
* On hosts with 64-bit 'long', zic silently truncates UTC
offsets that don't fit into 32 bits, when generating the output file.
Here is a proposed patch.
--- zic.c 2007/05/03 17:40:41 2007.5.1.1
+++ zic.c 2007/05/03 22:31:40 2007.5.0.3
@@ -926,7 +926,8 @@ const char * string;
const char * const errstring;
const int signable;
{
- int hh, mm, ss, sign;
+ long hh;
+ int mm, ss, sign;
if (string == NULL || *string == '\0')
return 0;
@@ -936,11 +937,11 @@ const int signable;
sign = -1;
++string;
} else sign = 1;
- if (sscanf(string, scheck(string, "%d"), &hh) == 1)
+ if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
mm = ss = 0;
- else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
+ else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
ss = 0;
- else if (sscanf(string, scheck(string, "%d:%d:%d"),
+ else if (sscanf(string, scheck(string, "%ld:%d:%d"),
&hh, &mm, &ss) != 3) {
error(errstring);
return 0;
@@ -951,14 +952,17 @@ const int signable;
error(errstring);
return 0;
}
+ if (LONG_MAX / SECSPERHOUR < hh) {
+ error(_("time overflow"));
+ return 0;
+ }
if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
warning(_("24:00 not handled by pre-1998 versions of zic"));
if (noise && (hh > HOURSPERDAY ||
(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
- return eitol(sign) *
- (eitol(hh * MINSPERHOUR + mm) *
- eitol(SECSPERMIN) + eitol(ss));
+ return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
+ eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
}
static void
@@ -2273,6 +2277,10 @@ const int ttisgmt;
error(_("too many local time types"));
exit(EXIT_FAILURE);
}
+ if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
+ error(_("UTC offset out of range"));
+ exit(EXIT_FAILURE);
+ }
gmtoffs[i] = gmtoff;
isdsts[i] = isdst;
ttisstds[i] = ttisstd;
More information about the tz
mailing list