From 833ea8d50280c2e30b246b82d631f193c2644d5e Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 9 Sep 2009 18:32:07 -0700 Subject: [PATCH] Fix an infinite loop in time2sub. The problem is that time_t is signed, and the original code relied on the fact that (X + c < X) in case of overflow for c >= 0. Unfortunately, this condition is only guaranteed by the standard for unsigned arithmetic, and the gcc 4.4.0 optimizer did completely remove the corresponding test from the code. This resulted in a missing boundary check, and an infinite loop. The problem is solved by testing explicitely for TIME_T_MIN and TIME_T_MAX in the loop that uses this. Also fix increment_overflow and long_increment_overflow which were buggy for exactly the same reasons. Also remove some compiler warnings. Note: a similar fix was performed in bionic/libc --- libcutils/tztime.c | 71 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/libcutils/tztime.c b/libcutils/tztime.c index 93bbb29da..d6448a1da 100644 --- a/libcutils/tztime.c +++ b/libcutils/tztime.c @@ -53,6 +53,31 @@ static char elsieid[] = "@(#)localtime.c 8.3"; #define OPEN_MODE O_RDONLY #endif /* !defined O_BINARY */ +/* Complex computations to determine the min/max of time_t depending + * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL. + * These macros cannot be used in pre-processor directives, so we + * let the C compiler do the work, which makes things a bit funky. + */ +static const time_t TIME_T_MAX = + TYPE_INTEGRAL(time_t) ? + ( TYPE_SIGNED(time_t) ? + ~((time_t)1 << (TYPE_BIT(time_t)-1)) + : + ~(time_t)0 + ) + : /* if time_t is a floating point number */ + ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX ); + +static const time_t TIME_T_MIN = + TYPE_INTEGRAL(time_t) ? + ( TYPE_SIGNED(time_t) ? + ((time_t)1 << (TYPE_BIT(time_t)-1)) + : + 0 + ) + : + ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN ); + #ifndef WILDABBR /* ** Someone might make incorrect use of a time zone abbreviation: @@ -158,7 +183,7 @@ static void gmtload P((struct state * sp)); static struct tm * gmtsub P((const time_t * timep, long offset, struct tm * tmp)); static struct tm * localsub P((const time_t * timep, long offset, - struct tm * tmp, struct state *sp)); + struct tm * tmp, const struct state *sp)); static int increment_overflow P((int * number, int delta)); static int leaps_thru_end_of P((int y)); static int long_increment_overflow P((long * number, int delta)); @@ -1157,7 +1182,7 @@ localsub(timep, offset, tmp, sp) const time_t * const timep; const long offset; struct tm * const tmp; -struct state * sp; +const struct state * sp; { register const struct ttinfo * ttisp; register int i; @@ -1553,26 +1578,36 @@ char * buf; static int increment_overflow(number, delta) -int * number; -int delta; +int * number; +int delta; { - int number0; + unsigned number0 = (unsigned)*number; + unsigned number1 = (unsigned)(number0 + delta); - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); + *number = (int)number1; + + if (delta >= 0) { + return ((int)number1 < (int)number0); + } else { + return ((int)number1 > (int)number0); + } } static int long_increment_overflow(number, delta) -long * number; -int delta; +long * number; +int delta; { - long number0; + unsigned long number0 = (unsigned long)*number; + unsigned long number1 = (unsigned long)(number0 + delta); - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); + *number = (long)number1; + + if (delta >= 0) { + return ((long)number1 < (long)number0); + } else { + return ((long)number1 > (long)number0); + } } static int @@ -1741,14 +1776,14 @@ const struct state * sp; } else dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (t == lo) { + if (t == TIME_T_MAX) + return WRONG; ++t; - if (t <= lo) - return WRONG; ++lo; } else if (t == hi) { + if (t == TIME_T_MIN) + return WRONG; --t; - if (t >= hi) - return WRONG; --hi; } if (lo > hi)