about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2012-03-16 03:14:03 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2012-05-23 14:36:24 -0700
commitce73d683974b3efc9e477cecb62d178e12cd1421 (patch)
treed4cbc6e969953e3e43c917892c28f4cb6a908d31
parent72a22e596cb1359fc7e05de6d5de6f35f3eb5785 (diff)
downloadglibc-ce73d683974b3efc9e477cecb62d178e12cd1421.tar.gz
glibc-ce73d683974b3efc9e477cecb62d178e12cd1421.tar.xz
glibc-ce73d683974b3efc9e477cecb62d178e12cd1421.zip
mktime: do not assume signed right shift propagates sign bit
* time/mktime.c (isdst_differ): New static function.
(__mktime_internal): No need to normalize tm_isdst now.
(__mktime_internal, not_equal_tm): Use isdst_differ to compare
tm_isdst values.
-rw-r--r--ChangeLog6
-rw-r--r--time/mktime.c18
2 files changed, 18 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 982d79ba9a..066a6dafbf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: do not assume signed right shift propagates sign bit
+	* time/mktime.c (isdst_differ): New static function.
+	(__mktime_internal): No need to normalize tm_isdst now.
+	(__mktime_internal, not_equal_tm): Use isdst_differ to compare
+	tm_isdst values.
+
 	mktime: merge another wrapv change from gnulib
 	* time/mktime.c (TYPE_MAXIMUM): Rework slightly to avoid diagnostics
 	from some compilers.
diff --git a/time/mktime.c b/time/mktime.c
index 61b230833e..dd7daaf948 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -177,6 +177,14 @@ const unsigned short int __mon_yday[2][13] =
 # include "mktime-internal.h"
 #endif
 
+/* Return 1 if the values A and B differ according to the rules for
+   tm_isdst: A and B differ if one is zero and the other positive.  */
+static int
+isdst_differ (int a, int b)
+{
+  return (!a != !b) && (0 <= a) && (0 <= b);
+}
+
 /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
    (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
    were not adjusted between the time stamps.
@@ -362,9 +370,7 @@ __mktime_internal (struct tm *tp,
   int mday = tp->tm_mday;
   int mon = tp->tm_mon;
   int year_requested = tp->tm_year;
-  /* Normalize the value.  */
-  int isdst = ((tp->tm_isdst >> (8 * sizeof (tp->tm_isdst) - 1))
-	       | (tp->tm_isdst != 0));
+  int isdst = tp->tm_isdst;
 
   /* 1 if the previous probe was DST.  */
   int dst2;
@@ -494,7 +500,7 @@ __mktime_internal (struct tm *tp,
 
   /* We have a match.  Check whether tm.tm_isdst has the requested
      value, if any.  */
-  if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
+  if (isdst_differ (isdst, tm.tm_isdst))
     {
       /* tm.tm_isdst has the wrong value.  Look for a neighboring
 	 time with the right value, and use its UTC offset.
@@ -532,7 +538,7 @@ __mktime_internal (struct tm *tp,
 	      time_t ot = t + delta * direction;
 	      struct tm otm;
 	      ranged_convert (convert, &ot, &otm);
-	      if (otm.tm_isdst == isdst)
+	      if (! isdst_differ (isdst, otm.tm_isdst))
 		{
 		  /* We found the desired tm_isdst.
 		     Extrapolate back to the desired time.  */
@@ -608,7 +614,7 @@ not_equal_tm (const struct tm *a, const struct tm *b)
 	  | (a->tm_mon ^ b->tm_mon)
 	  | (a->tm_year ^ b->tm_year)
 	  | (a->tm_yday ^ b->tm_yday)
-	  | (a->tm_isdst ^ b->tm_isdst));
+	  | isdst_differ (a->tm_isdst, b->tm_isdst));
 }
 
 static void