[tz] [PATCH] Fix potential integer overflow in differ_by_repeat

Paul Eggert eggert at cs.ucla.edu
Mon Apr 26 00:28:47 UTC 2021


* localtime.c (differ_by_repeat): Remove, since the subtraction
t1 - t0 could in theory overflow in 64-bit TZif data.
(tzloadbody): Redo to avoid integer overflow.
* private.h (SECSPERREPEAT_BITS): Remove; no longer used.
---
 localtime.c | 30 ++++++++++++++----------------
 private.h   |  3 +--
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/localtime.c b/localtime.c
index 9dd496d..9840b89 100644
--- a/localtime.c
+++ b/localtime.c
@@ -334,14 +334,6 @@ scrub_abbrs(struct state *sp)
 	}
 }
 
-static bool
-differ_by_repeat(const time_t t1, const time_t t0)
-{
-	if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
-		return 0;
-	return t1 - t0 == SECSPERREPEAT;
-}
-
 /* Input buffer for data read from a compiled tz file.  */
 union input_buffer {
   /* The first part of the buffer, interpreted as a header.  */
@@ -660,20 +652,26 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 	if (sp->typecnt == 0)
 	  return EINVAL;
 	if (sp->timecnt > 1) {
+	    if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) {
+		time_t repeatat = sp->ats[0] + SECSPERREPEAT;
+		int repeattype = sp->types[0];
 		for (i = 1; i < sp->timecnt; ++i)
-			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
-				differ_by_repeat(sp->ats[i], sp->ats[0])) {
+		  if (sp->ats[i] == repeatat
+		      && typesequiv(sp, sp->types[i], repeattype)) {
 					sp->goback = true;
 					break;
-				}
+		  }
+	    }
+	    if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) {
+		time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT;
+		int repeattype = sp->types[sp->timecnt - 1];
 		for (i = sp->timecnt - 2; i >= 0; --i)
-			if (typesequiv(sp, sp->types[sp->timecnt - 1],
-				sp->types[i]) &&
-				differ_by_repeat(sp->ats[sp->timecnt - 1],
-				sp->ats[i])) {
+		  if (sp->ats[i] == repeatat
+		      && typesequiv(sp, sp->types[i], repeattype)) {
 					sp->goahead = true;
 					break;
-		}
+		  }
+	    }
 	}
 
 	/* Infer sp->defaulttype from the data.  Although this default
diff --git a/private.h b/private.h
index cee3b11..340a354 100644
--- a/private.h
+++ b/private.h
@@ -642,7 +642,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
 #define TIME_T_MAX_NO_PADDING MAXVAL(time_t, TYPE_BIT(time_t))
 
 /* The extreme time values.  These are macros, not constants, so that
-   any portability problem occur only when compiling .c files that use
+   any portability problems occur only when compiling .c files that use
    the macros, which is safer for applications that need only zdump and zic.
    This implementation assumes no padding if time_t is signed and
    either the compiler lacks support for _Generic or time_t is not one
@@ -727,7 +727,6 @@ char *ctime_r(time_t const *, char *);
 #define YEARSPERREPEAT		400	/* years before a Gregorian repeat */
 #define DAYSPERREPEAT		((int_fast32_t) 400 * 365 + 100 - 4 + 1)
 #define SECSPERREPEAT		((int_fast64_t) DAYSPERREPEAT * SECSPERDAY)
-#define SECSPERREPEAT_BITS	34	/* ceil(log2(SECSPERREPEAT)) */
 #define AVGSECSPERYEAR		(SECSPERREPEAT / YEARSPERREPEAT)
 
 #define TM_SUNDAY	0
-- 
2.27.0



More information about the tz mailing list