OSDN Git Service

Fix an infinite loop in time2sub.
authorDavid 'Digit' Turner <digit@google.com>
Thu, 10 Sep 2009 00:41:59 +0000 (17:41 -0700)
committerDavid 'Digit' Turner <digit@google.com>
Thu, 10 Sep 2009 00:45:00 +0000 (17:45 -0700)
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.

Note: a similar fix is needed for system/core/libcutils

libc/tzcode/localtime.c

index 9c5f218..83c1011 100644 (file)
@@ -75,6 +75,31 @@ static __inline__ void _tzUnlock(void)
         pthread_mutex_unlock(&_tzMutex);
 }
 
+/* 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:
@@ -1683,11 +1708,16 @@ increment_overflow(number, delta)
 int *   number;
 int delta;
 {
-    int number0;
+    unsigned  number0 = (unsigned)*number;
+    unsigned  number1 = (unsigned)(number0 + delta);
+
+    *number = (int)number1;
 
-    number0 = *number;
-    *number += delta;
-    return (*number < number0) != (delta < 0);
+    if (delta >= 0) {
+        return ((int)number1 < (int)number0);
+    } else {
+        return ((int)number1 > (int)number0);
+    }
 }
 
 static int
@@ -1695,11 +1725,16 @@ long_increment_overflow(number, delta)
 long *  number;
 int delta;
 {
-    long    number0;
+    unsigned long  number0 = (unsigned long)*number;
+    unsigned long  number1 = (unsigned long)(number0 + delta);
+
+    *number = (long)number1;
 
-    number0 = *number;
-    *number += delta;
-    return (*number < number0) != (delta < 0);
+    if (delta >= 0) {
+        return ((long)number1 < (long)number0);
+    } else {
+        return ((long)number1 > (long)number0);
+    }
 }
 
 static int
@@ -1868,14 +1903,14 @@ const int       do_norm_secs;
         } else  dir = tmcomp(&mytm, &yourtm);
         if (dir != 0) {
             if (t == lo) {
-                ++t;
-                if (t <= lo)
+                if (t == TIME_T_MAX)
                     return WRONG;
+                ++t;
                 ++lo;
             } else if (t == hi) {
-                --t;
-                if (t >= hi)
+                if (t == TIME_T_MIN)
                     return WRONG;
+                --t;
                 --hi;
             }
             if (lo > hi)