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