[tz] [PROPOSED PATCH 1/5] Port to platforms with leap seconds and unsigned time_t.

Paul Eggert eggert at cs.ucla.edu
Tue Aug 19 19:52:38 UTC 2014


* localtime.c (tzload): On platforms where time_t is unsigned,
don't mishandle zones that contain leap seconds but no ordinary
transitions after 1970.  This problem can be reproduced by running
'zdump -v right/Asia/Dubai' on a platform where time_t is an
unsigned 32-bit integer.
---
 localtime.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/localtime.c b/localtime.c
index 8a66650..a1e6601 100644
--- a/localtime.c
+++ b/localtime.c
@@ -395,28 +395,28 @@ tzload(register const char *name, register struct state *const sp,
 			ttisstdcnt +			/* ttisstds */
 			ttisgmtcnt)			/* ttisgmts */
 				goto oops;
+
+		/* Read transitions, discarding those out of time_t range.
+		   But pretend the last transition before time_t_min
+		   occurred at time_t_min.  */
 		timecnt = 0;
 		for (i = 0; i < sp->timecnt; ++i) {
 			int_fast64_t at
 			  = stored == 4 ? detzcode(p) : detzcode64(p);
-			sp->types[i] = ((TYPE_SIGNED(time_t)
-					 ? time_t_min <= at
-					 : 0 <= at)
-					&& at <= time_t_max);
+			sp->types[i] = at <= time_t_max;
 			if (sp->types[i]) {
-				if (i && !timecnt && at != time_t_min) {
-					/*
-					** Keep the earlier record, but tweak
-					** it so that it starts with the
-					** minimum time_t value.
-					*/
-					sp->types[i - 1] = 1;
-					sp->ats[timecnt++] = time_t_min;
-				}
-				sp->ats[timecnt++] = at;
+			  time_t attime
+			    = ((TYPE_SIGNED(time_t) ? at < time_t_min : at < 0)
+			       ? time_t_min : at);
+			  if (timecnt && sp->ats[timecnt - 1] == attime) {
+			    sp->types[i - 1] = 0;
+			    timecnt--;
+			  }
+			  sp->ats[timecnt++] = attime;
 			}
 			p += stored;
 		}
+
 		timecnt = 0;
 		for (i = 0; i < sp->timecnt; ++i) {
 			unsigned char typ = *p++;
-- 
1.9.1



More information about the tz mailing list