mktime: systematically normalize tm_isdst comparisons
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 30 Jan 2011 07:00:55 +0000 (23:00 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 30 Jan 2011 07:01:22 +0000 (23:01 -0800)
* lib/mktime.c (isdst_differ): New function.
(__mktime_internal): Use it systematically for all isdst comparisons.
This completes the fix for libc BZ #6723, and removes the need for
normalizing tm_isdst.  See
<http://sourceware.org/bugzilla/show_bug.cgi?id=6723>
(not_equal_tm) [DEBUG]: Use isdst_differ here, too.

ChangeLog
lib/mktime.c

index 56a7b45..252c1c4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2011-01-29  Paul Eggert  <eggert@cs.ucla.edu>
 
+       mktime: systematically normalize tm_isdst comparisons
+       * lib/mktime.c (isdst_differ): New function.
+       (__mktime_internal): Use it systematically for all isdst comparisons.
+       This completes the fix for libc BZ #6723, and removes the need for
+       normalizing tm_isdst.  See
+       <http://sourceware.org/bugzilla/show_bug.cgi?id=6723>
+       (not_equal_tm) [DEBUG]: Use isdst_differ here, too.
+
        mktime: fix some integer overflow issues and sidestep the rest
 
        This was prompted by a bug report by Benjamin Lindner for MinGW
index 6eb9bfc..ef49814 100644 (file)
@@ -171,6 +171,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.
@@ -356,9 +364,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;
@@ -488,7 +494,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.
@@ -526,7 +532,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.  */
@@ -602,7 +608,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