[tz] [PROPOSED PATCH 4/9] mktime: guess better near transitions where tm_isdst does not change

Paul Eggert eggert at cs.ucla.edu
Mon Aug 25 06:59:48 UTC 2014


* localtime.c (SMALLEST): New macro.
(time2sub) [TM_GMTOFF && !UNINIT_TRAP]:
If the UTC offset doesn't match the request, try the requested offset.
This catches a problem caught by -DTYPECHECK with a time stamp
near a transition from LMT to standard time, where both sides of
the transition have tm_isdst == 0.  If !defined TM_GMTOFF ||
UNINIT_TRAP you're out of luck: mktime will still conform
to its spec but it'll be more likely to guess wrong on these
ambiguous inputs.
* private.h (UNINIT_TRAP): New macro that defaults to 0.
* Makefile, NEWS: Document this.
---
 Makefile    |  2 ++
 NEWS        |  8 ++++++++
 localtime.c | 30 ++++++++++++++++++++++++++++++
 private.h   |  4 ++++
 4 files changed, 44 insertions(+)

diff --git a/Makefile b/Makefile
index 26e8ab7..968773f 100644
--- a/Makefile
+++ b/Makefile
@@ -134,6 +134,8 @@ LDLIBS=
 #	the default is system-supplied, typically "/usr/lib/locale"
 #  -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
 #	DST transitions if the time zone files cannot be accessed
+#  -DUNINIT_TRAP=1 if reading uninitialized storage can cause problems
+#	other than simply getting garbage data
 #  -DZIC_MAX_ABBR_LEN_WO_WARN=3
 #	(or some other number) to set the maximum time zone abbreviation length
 #	that zic will accept without a warning (the default is 6)
diff --git a/NEWS b/NEWS
index 9912856..3d69b1f 100644
--- a/NEWS
+++ b/NEWS
@@ -59,6 +59,14 @@ Unreleased, experimental changes
     already defined, to make it easier to configure on common platforms.
     Define NO_TM_GMTOFF and NO_TM_ZONE to suppress this.
 
+    Unless the new macro UNINIT_TRAP is defined to 0, the tz code now
+    assumes that reading uninitialized memory yields garbage values
+    but does not cause other problems such as traps.
+
+    If TM_GMTOFF is defined and UNINIT_TRAP is not 0, mktime is now
+    more likely to guess right for ambiguous time stamps near
+    transitions where tm_isdst does not change.
+
     tzselect -c now uses a hybrid distance measure that works better
     in Africa.  (Thanks to Alan Barrett for noting the problem.)
 
diff --git a/localtime.c b/localtime.c
index 7b22f72..e60842e 100644
--- a/localtime.c
+++ b/localtime.c
@@ -103,6 +103,7 @@ struct lsinfo {				/* leap second information */
 	int_fast64_t	ls_corr;	/* correction to apply */
 };
 
+#define SMALLEST(a, b)	(((a) < (b)) ? (a) : (b))
 #define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
 
 #ifdef TZNAME_MAX
@@ -1817,6 +1818,35 @@ time2sub(struct tm *const tmp,
 			else	lo = t;
 			continue;
 		}
+#if defined TM_GMTOFF && ! UNINIT_TRAP
+		if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
+		    && (yourtm.TM_GMTOFF < 0
+			? (-SECSPERDAY <= yourtm.TM_GMTOFF
+			   && (mytm.TM_GMTOFF <=
+			       (SMALLEST (INT_FAST32_MAX, LONG_MAX)
+				+ yourtm.TM_GMTOFF)))
+			: (yourtm.TM_GMTOFF <= SECSPERDAY
+			   && ((BIGGEST (INT_FAST32_MIN, LONG_MIN)
+				+ yourtm.TM_GMTOFF)
+			       <= mytm.TM_GMTOFF)))) {
+		  /* MYTM matches YOURTM except with the wrong UTC offset.
+		     YOURTM.TM_GMTOFF is plausible, so try it instead.
+		     It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
+		     since the guess gets checked.  */
+		  time_t altt = t;
+		  int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
+		  if (!increment_overflow_time(&altt, diff)) {
+		    struct tm alttm;
+		    if (funcp(&altt, offset, &alttm)
+			&& alttm.tm_isdst == mytm.tm_isdst
+			&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
+			&& tmcomp(&alttm, &yourtm) == 0) {
+		      t = altt;
+		      mytm = alttm;
+		    }
+		  }
+		}
+#endif
 		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
 			break;
 		/*
diff --git a/private.h b/private.h
index 14a9d53..31239e1 100644
--- a/private.h
+++ b/private.h
@@ -413,6 +413,10 @@ static time_t const time_t_max =
 # define INITIALIZE(x)
 #endif
 
+#ifndef UNINIT_TRAP
+# define UNINIT_TRAP 0
+#endif
+
 /*
 ** For the benefit of GNU folk...
 ** '_(MSGID)' uses the current locale's message library string for MSGID.
-- 
1.9.1



More information about the tz mailing list