"Olson, Arthur David \(NIH/NCI\) [E]" <olsona@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;