This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch, master, updated. glibc-2.15-1031-gf8591f8


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  f8591f8049a401c898737ca843d87872b93e6ccc (commit)
       via  94c7d826c97ec1ae6ced9f83fe1fe6cfcc235edb (commit)
       via  ce73d683974b3efc9e477cecb62d178e12cd1421 (commit)
       via  72a22e596cb1359fc7e05de6d5de6f35f3eb5785 (commit)
       via  68605433483b08e8a31541d833bf92ff3ecad75c (commit)
       via  03cf7fe31be5964707a54ed82969b9c181f8dd99 (commit)
       via  f04dfbc244efb683e395d40c08c86fb93e679167 (commit)
       via  62bdf9a68363655f0a3d03f930de2bda97a161cc (commit)
      from  5e292e4fa55177b858fa034ab5829de3f7587d76 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f8591f8049a401c898737ca843d87872b93e6ccc

commit f8591f8049a401c898737ca843d87872b93e6ccc
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 03:18:12 2012 -0700

    mktime: avoid signed integer overflow
    
    * time/mktime.c (__mktime_internal): Do not mishandle the case
    where diff == INT_MIN.

diff --git a/ChangeLog b/ChangeLog
index e795eca..71045db 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: avoid signed integer overflow
+	* time/mktime.c (__mktime_internal): Do not mishandle the case
+	where diff == INT_MIN.
+
 	mktime: simplify computation of average
 	* time/mktime.c (ranged_convert): Use new time_t_avg function
 	instead of rolling our own (probably-slower) code.
diff --git a/time/mktime.c b/time/mktime.c
index f4d9cf1..e1fbf9e 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -445,7 +445,7 @@ __mktime_internal (struct tm *tp,
 
       int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
       int diff = approx_biennia - approx_requested_biennia;
-      int abs_diff = diff < 0 ? - diff : diff;
+      int approx_abs_diff = diff < 0 ? -1 - diff : diff;
 
       /* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
 	 gives a positive value of 715827882.  Setting a variable
@@ -456,15 +456,15 @@ __mktime_internal (struct tm *tp,
       time_t overflow_threshold =
 	(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
 
-      if (overflow_threshold < abs_diff)
+      if (overflow_threshold < approx_abs_diff)
 	{
 	  /* Overflow occurred.  Try repairing it; this might work if
 	     the time zone offset is enough to undo the overflow.  */
 	  time_t repaired_t0 = -1 - t0;
 	  approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
 	  diff = approx_biennia - approx_requested_biennia;
-	  abs_diff = diff < 0 ? - diff : diff;
-	  if (overflow_threshold < abs_diff)
+	  approx_abs_diff = diff < 0 ? -1 - diff : diff;
+	  if (overflow_threshold < approx_abs_diff)
 	    return -1;
 	  guessed_offset += repaired_t0 - t0;
 	  t0 = repaired_t0;

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=94c7d826c97ec1ae6ced9f83fe1fe6cfcc235edb

commit 94c7d826c97ec1ae6ced9f83fe1fe6cfcc235edb
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 03:15:57 2012 -0700

    mktime: simplify computation of average
    
    * time/mktime.c (ranged_convert): Use new time_t_avg function
    instead of rolling our own (probably-slower) code.

diff --git a/ChangeLog b/ChangeLog
index 066a6da..e795eca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: simplify computation of average
+	* time/mktime.c (ranged_convert): Use new time_t_avg function
+	instead of rolling our own (probably-slower) code.
+
 	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.
diff --git a/time/mktime.c b/time/mktime.c
index dd7daaf..f4d9cf1 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -319,9 +319,7 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
 	 they differ by 1.  */
       while (bad != ok + (bad < 0 ? -1 : 1))
 	{
-	  time_t mid = *t = (bad < 0
-			     ? bad + ((ok - bad) >> 1)
-			     : ok + ((bad - ok) >> 1));
+	  time_t mid = *t = time_t_avg (ok, bad);
 	  r = convert (t, tp);
 	  if (r)
 	    ok = mid;

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ce73d683974b3efc9e477cecb62d178e12cd1421

commit ce73d683974b3efc9e477cecb62d178e12cd1421
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 03:14:03 2012 -0700

    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.

diff --git a/ChangeLog b/ChangeLog
index 982d79b..066a6da 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 61b2308..dd7daaf 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

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=72a22e596cb1359fc7e05de6d5de6f35f3eb5785

commit 72a22e596cb1359fc7e05de6d5de6f35f3eb5785
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 03:04:42 2012 -0700

    mktime: merge another wrapv change from gnulib
    
    * time/mktime.c (TYPE_MAXIMUM): Rework slightly to avoid diagnostics
    from some compilers.

diff --git a/ChangeLog b/ChangeLog
index a970b58..982d79b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: merge another wrapv change from gnulib
+	* time/mktime.c (TYPE_MAXIMUM): Rework slightly to avoid diagnostics
+	from some compilers.
+
 	mktime: remove incorrect attempt at unusual arithmetics
 	* time/mktime.c (TYPE_ONES_COMPLEMENT, TYPE_SIGNED_MAGNITUDE): Remove.
 	The code didn't really work on such machines anyway.
diff --git a/time/mktime.c b/time/mktime.c
index 652a0f2..61b2308 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -121,7 +121,7 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
 #define TYPE_MAXIMUM(t) \
   ((t) (! TYPE_SIGNED (t) \
 	? (t) -1 \
-	: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+	: ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
 
 #ifndef TIME_T_MIN
 # define TIME_T_MIN TYPE_MINIMUM (time_t)

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=68605433483b08e8a31541d833bf92ff3ecad75c

commit 68605433483b08e8a31541d833bf92ff3ecad75c
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 03:00:48 2012 -0700

    mktime: remove incorrect attempt at unusual arithmetics
    
    * time/mktime.c (TYPE_ONES_COMPLEMENT, TYPE_SIGNED_MAGNITUDE): Remove.
    The code didn't really work on such machines anyway.
    (TYPE_MINIMUM): Assume two's complement.
    (twos_complement_arithmetic): Verify that long_int and time_t
    are two's complement (or unsigned, in the latter case).

diff --git a/ChangeLog b/ChangeLog
index b5cf376..a970b58 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: remove incorrect attempt at unusual arithmetics
+	* time/mktime.c (TYPE_ONES_COMPLEMENT, TYPE_SIGNED_MAGNITUDE): Remove.
+	The code didn't really work on such machines anyway.
+	(TYPE_MINIMUM): Assume two's complement.
+	(twos_complement_arithmetic): Verify that long_int and time_t
+	are two's complement (or unsigned, in the latter case).
+
 	mktime: check signed shifts on long_int and time_t, too
 	* time/mktime.c (SHR): Check that shifts work as desired
 	on the types long_int and time_t too, as SHR is used on
diff --git a/time/mktime.c b/time/mktime.c
index 5144987..652a0f2 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -104,12 +104,8 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
 
 /* True if negative values of the signed integer type T use two's
-   complement, ones' complement, or signed magnitude representation,
-   respectively.  Much GNU code assumes two's complement, but some
-   people like to be portable to all possible C hosts.  */
+   complement, or if T is an unsigned integer type.  */
 #define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
-#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
-#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
 
 /* True if the arithmetic type T is signed.  */
 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
@@ -121,9 +117,7 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
 #define TYPE_MINIMUM(t) \
   ((t) (! TYPE_SIGNED (t) \
 	? (t) 0 \
-	: TYPE_SIGNED_MAGNITUDE (t) \
-	? ~ (t) 0 \
-	: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
+	: ~ TYPE_MAXIMUM (t)))
 #define TYPE_MAXIMUM(t) \
   ((t) (! TYPE_SIGNED (t) \
 	? (t) -1 \
@@ -138,7 +132,10 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
 #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
 
 verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
-verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
+verify (twos_complement_arithmetic,
+	(TYPE_TWOS_COMPLEMENT (int)
+	 && TYPE_TWOS_COMPLEMENT (long_int)
+	 && TYPE_TWOS_COMPLEMENT (time_t)));
 
 #define EPOCH_YEAR 1970
 #define TM_YEAR_BASE 1900

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=03cf7fe31be5964707a54ed82969b9c181f8dd99

commit 03cf7fe31be5964707a54ed82969b9c181f8dd99
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 02:57:35 2012 -0700

    mktime: check signed shifts on long_int and time_t, too
    
    * time/mktime.c (SHR): Check that shifts work as desired
    on the types long_int and time_t too, as SHR is used on
    such types.

diff --git a/ChangeLog b/ChangeLog
index 5b99dac..b5cf376 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: check signed shifts on long_int and time_t, too
+	* time/mktime.c (SHR): Check that shifts work as desired
+	on the types long_int and time_t too, as SHR is used on
+	such types.
+
 	mktime: do not assume 'long' is wide enough
 	* time/mktime.c (verify): Move decl up.
 	(long_int): New type.
diff --git a/time/mktime.c b/time/mktime.c
index 6d4db69..5144987 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -89,9 +89,11 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
    right in the usual way when A < 0, so SHR falls back on division if
    ordinary A >> B doesn't seem to be the usual signed shift.  */
-#define SHR(a, b)	\
-  (-1 >> 1 == -1	\
-   ? (a) >> (b)		\
+#define SHR(a, b)                                               \
+  ((-1 >> 1 == -1                                               \
+    && (long_int) -1 >> 1 == -1                                 \
+    && ((time_t) -1 >> 1 == -1 || ! TYPE_SIGNED (time_t)))      \
+   ? (a) >> (b)                                                 \
    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
 
 /* The extra casts in the following macros work around compiler bugs,

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f04dfbc244efb683e395d40c08c86fb93e679167

commit f04dfbc244efb683e395d40c08c86fb93e679167
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 02:48:38 2012 -0700

    mktime: do not assume 'long' is wide enough
    
    * time/mktime.c (verify): Move decl up.
    (long_int): New type.
    (leapyear, ydhms_diff, guess_time_tm, __mktime_internal): Use it,
    to remove assumption in the code that 'long' is wide enough to
    store year values.  This assumption is not true on x32 and on
    some non-glibc platforms.

diff --git a/ChangeLog b/ChangeLog
index 3888b87..5b99dac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
 
+	mktime: do not assume 'long' is wide enough
+	* time/mktime.c (verify): Move decl up.
+	(long_int): New type.
+	(leapyear, ydhms_diff, guess_time_tm, __mktime_internal): Use it,
+	to remove assumption in the code that 'long' is wide enough to
+	store year values.  This assumption is not true on x32 and on
+	some non-glibc platforms.
+
 	mktime: merge wrapv change from gnulib
 	* time/mktime.c (WRAPV): New macro.
 	(time_t_avg, time_t_add_ok, time_t_int_add_ok): New static functions.
diff --git a/time/mktime.c b/time/mktime.c
index 8a2b228..6d4db69 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -68,6 +68,17 @@
 # endif
 #endif
 
+/* Verify a requirement at compile-time (unlike assert, which is runtime).  */
+#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
+
+/* A signed type that is at least one bit wider than int.  */
+#if INT_MAX <= LONG_MAX / 2
+typedef long int long_int;
+#else
+typedef long long int long_int;
+#endif
+verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
+
 /* Shift A right by B bits portably, by dividing A by 2**B and
    truncating towards minus infinity.  A and B should be free of side
    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
@@ -124,9 +135,6 @@
 #endif
 #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
 
-/* Verify a requirement at compile-time (unlike assert, which is runtime).  */
-#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
-
 verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
 verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
 
@@ -136,7 +144,7 @@ verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
 
 /* Return 1 if YEAR + TM_YEAR_BASE is a leap year.  */
 static inline int
-leapyear (long int year)
+leapyear (long_int year)
 {
   /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
      Also, work even if YEAR is negative.  */
@@ -182,12 +190,10 @@ const unsigned short int __mon_yday[2][13] =
    detect overflow.  */
 
 static inline time_t
-ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
+ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
 	    int year0, int yday0, int hour0, int min0, int sec0)
 {
   verify (C99_integer_division, -1 / 2 == 0);
-  verify (long_int_year_and_yday_are_wide_enough,
-	  INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
 
   /* Compute intervening leap days correctly even if year is negative.
      Take care to avoid integer overflow here.  */
@@ -265,7 +271,7 @@ time_t_int_add_ok (time_t a, int b)
    If overflow occurs, yield the minimal or maximal value, except do not
    yield a value equal to *T.  */
 static time_t
-guess_time_tm (long int year, long int yday, int hour, int min, int sec,
+guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
 	       const time_t *t, const struct tm *tp)
 {
   if (tp)
@@ -368,8 +374,8 @@ __mktime_internal (struct tm *tp,
   int mon_remainder = mon % 12;
   int negative_mon_remainder = mon_remainder < 0;
   int mon_years = mon / 12 - negative_mon_remainder;
-  long int lyear_requested = year_requested;
-  long int year = lyear_requested + mon_years;
+  long_int lyear_requested = year_requested;
+  long_int year = lyear_requested + mon_years;
 
   /* The other values need not be in range:
      the remaining code handles minor overflows correctly,
@@ -381,8 +387,8 @@ __mktime_internal (struct tm *tp,
   int mon_yday = ((__mon_yday[leapyear (year)]
 		   [mon_remainder + 12 * negative_mon_remainder])
 		  - 1);
-  long int lmday = mday;
-  long int yday = mon_yday + lmday;
+  long_int lmday = mday;
+  long_int yday = mon_yday + lmday;
 
   time_t guessed_offset = *offset;
 

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=62bdf9a68363655f0a3d03f930de2bda97a161cc

commit 62bdf9a68363655f0a3d03f930de2bda97a161cc
Author: Paul Eggert <eggert@cs.ucla.edu>
Date:   Fri Mar 16 02:36:14 2012 -0700

    mktime: merge wrapv change from gnulib
    
    * time/mktime.c (WRAPV): New macro.
    (time_t_avg, time_t_add_ok, time_t_int_add_ok): New static functions.
    (guess_time_tm, __mktime_internal): Do not assume that signed
    integer overflow wraps around; modern compilers generate code
    where this assumption is no longer valid.

diff --git a/ChangeLog b/ChangeLog
index 18e65a3..3888b87 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2012-05-23  Paul Eggert  <eggert@cs.ucla.edu>
+
+	mktime: merge wrapv change from gnulib
+	* time/mktime.c (WRAPV): New macro.
+	(time_t_avg, time_t_add_ok, time_t_int_add_ok): New static functions.
+	(guess_time_tm, __mktime_internal): Do not assume that signed
+	integer overflow wraps around; modern compilers generate code
+	where this assumption is no longer valid.
+
 2012-05-23  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* sysdeps/unix/sysv/linux/i386/sysdep.h (SYSCALL_ERROR_HANDLER):
diff --git a/time/mktime.c b/time/mktime.c
index 5058c4f..8a2b228 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -46,6 +46,28 @@
 # define mktime my_mktime
 #endif /* DEBUG */
 
+/* Some of the code in this file assumes that signed integer overflow
+   silently wraps around.  This assumption can't easily be programmed
+   around, nor can it be checked for portably at compile-time or
+   easily eliminated at run-time.
+
+   Define WRAPV to 1 if the assumption is valid and if
+     #pragma GCC optimize ("wrapv")
+   does not trigger GCC bug 51793
+   <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51793>.
+   Otherwise, define it to 0; this forces the use of slower code that,
+   while not guaranteed by the C Standard, works on all production
+   platforms that we know about.  */
+#ifndef WRAPV
+# if (((__GNUC__ == 4 && 4 <= __GNUC_MINOR__) || 4 < __GNUC__) \
+      && defined __GLIBC__)
+#  pragma GCC optimize ("wrapv")
+#  define WRAPV 1
+# else
+#  define WRAPV 0
+# endif
+#endif
+
 /* Shift A right by B bits portably, by dividing A by 2**B and
    truncating towards minus infinity.  A and B should be free of side
    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
@@ -107,9 +129,6 @@
 
 verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
 verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
-/* The code also assumes that signed integer overflow silently wraps
-   around, but this assumption can't be stated without causing a
-   diagnostic on some hosts.  */
 
 #define EPOCH_YEAR 1970
 #define TM_YEAR_BASE 1900
@@ -191,6 +210,53 @@ ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
   return seconds;
 }
 
+/* Return the average of A and B, even if A + B would overflow.  */
+static time_t
+time_t_avg (time_t a, time_t b)
+{
+  return SHR (a, 1) + SHR (b, 1) + (a & b & 1);
+}
+
+/* Return 1 if A + B does not overflow.  If time_t is unsigned and if
+   B's top bit is set, assume that the sum represents A - -B, and
+   return 1 if the subtraction does not wrap around.  */
+static int
+time_t_add_ok (time_t a, time_t b)
+{
+  if (! TYPE_SIGNED (time_t))
+    {
+      time_t sum = a + b;
+      return (sum < a) == (TIME_T_MIDPOINT <= b);
+    }
+  else if (WRAPV)
+    {
+      time_t sum = a + b;
+      return (sum < a) == (b < 0);
+    }
+  else
+    {
+      time_t avg = time_t_avg (a, b);
+      return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
+    }
+}
+
+/* Return 1 if A + B does not overflow.  */
+static int
+time_t_int_add_ok (time_t a, int b)
+{
+  verify (int_no_wider_than_time_t, INT_MAX <= TIME_T_MAX);
+  if (WRAPV)
+    {
+      time_t sum = a + b;
+      return (sum < a) == (b < 0);
+    }
+  else
+    {
+      int a_odd = a & 1;
+      time_t avg = SHR (a, 1) + (SHR (b, 1) + (a_odd & b));
+      return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
+    }
+}
 
 /* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
    assuming that *T corresponds to *TP and that no clock adjustments
@@ -207,9 +273,8 @@ guess_time_tm (long int year, long int yday, int hour, int min, int sec,
       time_t d = ydhms_diff (year, yday, hour, min, sec,
 			     tp->tm_year, tp->tm_yday,
 			     tp->tm_hour, tp->tm_min, tp->tm_sec);
-      time_t t1 = *t + d;
-      if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
-	return t1;
+      if (time_t_add_ok (*t, d))
+	return *t + d;
     }
 
   /* Overflow occurred one way or another.  Return the nearest result
@@ -457,22 +522,20 @@ __mktime_internal (struct tm *tp,
 
       for (delta = stride; delta < delta_bound; delta += stride)
 	for (direction = -1; direction <= 1; direction += 2)
-	  {
-	    time_t ot = t + delta * direction;
-	    if ((ot < t) == (direction < 0))
-	      {
-		struct tm otm;
-		ranged_convert (convert, &ot, &otm);
-		if (otm.tm_isdst == isdst)
-		  {
-		    /* We found the desired tm_isdst.
-		       Extrapolate back to the desired time.  */
-		    t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
-		    ranged_convert (convert, &t, &tm);
-		    goto offset_found;
-		  }
-	      }
-	  }
+	  if (time_t_int_add_ok (t, delta * direction))
+	    {
+	      time_t ot = t + delta * direction;
+	      struct tm otm;
+	      ranged_convert (convert, &ot, &otm);
+	      if (otm.tm_isdst == isdst)
+		{
+		  /* We found the desired tm_isdst.
+		     Extrapolate back to the desired time.  */
+		  t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
+		  ranged_convert (convert, &t, &tm);
+		  goto offset_found;
+		}
+	    }
     }
 
  offset_found:
@@ -483,11 +546,13 @@ __mktime_internal (struct tm *tp,
       /* Adjust time to reflect the tm_sec requested, not the normalized value.
 	 Also, repair any damage from a false match due to a leap second.  */
       int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
+      if (! time_t_int_add_ok (t, sec_requested))
+	return -1;
       t1 = t + sec_requested;
+      if (! time_t_int_add_ok (t1, sec_adjustment))
+	return -1;
       t2 = t1 + sec_adjustment;
-      if (((t1 < t) != (sec_requested < 0))
-	  | ((t2 < t1) != (sec_adjustment < 0))
-	  | ! convert (&t2, &tm))
+      if (! convert (&t2, &tm))
 	return -1;
       t = t2;
     }

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog     |   47 ++++++++++++++
 time/mktime.c |  198 +++++++++++++++++++++++++++++++++++++++------------------
 2 files changed, 183 insertions(+), 62 deletions(-)


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]