From 62bdf9a68363655f0a3d03f930de2bda97a161cc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 02:36:14 -0700 Subject: 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. --- ChangeLog | 9 +++++ time/mktime.c | 115 +++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 18e65a34d5..3888b871b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2012-05-23 Paul Eggert + + 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 * sysdeps/unix/sysv/linux/i386/sysdep.h (SYSCALL_ERROR_HANDLER): diff --git a/time/mktime.c b/time/mktime.c index 5058c4f27d..8a2b22881b 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 + . + 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; } -- cgit 1.4.1 From f04dfbc244efb683e395d40c08c86fb93e679167 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 02:48:38 -0700 Subject: 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. --- ChangeLog | 8 ++++++++ time/mktime.c | 30 ++++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3888b871b2..5b99dac31f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2012-05-23 Paul Eggert + 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 8a2b22881b..6d4db69da2 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; -- cgit 1.4.1 From 03cf7fe31be5964707a54ed82969b9c181f8dd99 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 02:57:35 -0700 Subject: 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. --- ChangeLog | 5 +++++ time/mktime.c | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5b99dac31f..b5cf376857 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-05-23 Paul Eggert + 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 6d4db69da2..5144987708 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, -- cgit 1.4.1 From 68605433483b08e8a31541d833bf92ff3ecad75c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 03:00:48 -0700 Subject: 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). --- ChangeLog | 7 +++++++ time/mktime.c | 15 ++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index b5cf376857..a970b584ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2012-05-23 Paul Eggert + 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 5144987708..652a0f2d4a 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 -- cgit 1.4.1 From 72a22e596cb1359fc7e05de6d5de6f35f3eb5785 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 03:04:42 -0700 Subject: mktime: merge another wrapv change from gnulib * time/mktime.c (TYPE_MAXIMUM): Rework slightly to avoid diagnostics from some compilers. --- ChangeLog | 4 ++++ time/mktime.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a970b584ca..982d79ba9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-05-23 Paul Eggert + 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 652a0f2d4a..61b230833e 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) -- cgit 1.4.1 From ce73d683974b3efc9e477cecb62d178e12cd1421 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 03:14:03 -0700 Subject: 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. --- ChangeLog | 6 ++++++ time/mktime.c | 18 ++++++++++++------ 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 + 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 -- cgit 1.4.1 From 94c7d826c97ec1ae6ced9f83fe1fe6cfcc235edb Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 03:15:57 -0700 Subject: mktime: simplify computation of average * time/mktime.c (ranged_convert): Use new time_t_avg function instead of rolling our own (probably-slower) code. --- ChangeLog | 4 ++++ time/mktime.c | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 066a6dafbf..e795eca881 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-05-23 Paul Eggert + 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 dd7daaf948..f4d9cf1528 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; -- cgit 1.4.1 From f8591f8049a401c898737ca843d87872b93e6ccc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Mar 2012 03:18:12 -0700 Subject: mktime: avoid signed integer overflow * time/mktime.c (__mktime_internal): Do not mishandle the case where diff == INT_MIN. --- ChangeLog | 4 ++++ time/mktime.c | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index e795eca881..71045dbd47 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2012-05-23 Paul Eggert + 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 f4d9cf1528..e1fbf9ea19 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; -- cgit 1.4.1