merge from open-source master
[android-sdk/platform-bionic.git] / libc / stdlib / strtod.c
index d2582b1ebfc6ec0a19cb751fb5b83bdc914b0220..9d599b05993a4e846bd2929dfadbe915a5f6ca22 100644 (file)
@@ -378,6 +378,24 @@ Bigint {
 #endif
 #endif
 
+/* Special value used to indicate an invalid Bigint value,
+ * e.g. when a memory allocation fails. The idea is that we
+ * want to avoid introducing NULL checks everytime a bigint
+ * computation is performed. Also the NULL value can also be
+ * already used to indicate "value not initialized yet" and
+ * returning NULL might alter the execution code path in
+ * case of OOM.
+ */
+#define  BIGINT_INVALID   ((Bigint *)&bigint_invalid_value)
+
+static const Bigint bigint_invalid_value;
+
+
+/* Return BIGINT_INVALID on allocation failure.
+ *
+ * Most of the code here depends on the fact that this function
+ * never returns NULL.
+ */
  static Bigint *
 Balloc
 #ifdef KR_headers
@@ -397,11 +415,15 @@ Balloc
        else {
                x = 1 << k;
                rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
+               if (rv == NULL) {
+                       rv = BIGINT_INVALID;
+                       goto EXIT;
+               }
                rv->k = k;
                rv->maxwds = x;
        }
        rv->sign = rv->wds = 0;
-
+EXIT:
        mutex_unlock(&freelist_mutex);
 
        return rv;
@@ -415,7 +437,7 @@ Bfree
        (Bigint *v)
 #endif
 {
-       if (v) {
+       if (v && v != BIGINT_INVALID) {
                mutex_lock(&freelist_mutex);
 
                v->next = freelist[v->k];
@@ -425,8 +447,23 @@ Bfree
        }
 }
 
-#define Bcopy(x,y) memcpy(&x->sign, &y->sign, \
-    y->wds*sizeof(Long) + 2*sizeof(int))
+#define Bcopy_valid(x,y) memcpy(&(x)->sign, &(y)->sign, \
+    (y)->wds*sizeof(Long) + 2*sizeof(int))
+
+#define Bcopy(x,y)  Bcopy_ptr(&(x),(y))
+
+ static void
+Bcopy_ptr(Bigint **px, Bigint *y)
+{
+       if (*px == BIGINT_INVALID)
+               return; /* no space to store copy */
+       if (y == BIGINT_INVALID) {
+               Bfree(*px); /* invalid input */
+               *px = BIGINT_INVALID;
+       } else {
+               Bcopy_valid(*px,y);
+       }
+}
 
  static Bigint *
 multadd
@@ -443,6 +480,9 @@ multadd
 #endif
        Bigint *b1;
 
+       if (b == BIGINT_INVALID)
+               return b;
+
        wds = b->wds;
        x = b->x;
        i = 0;
@@ -463,7 +503,11 @@ multadd
        if (a) {
                if (wds >= b->maxwds) {
                        b1 = Balloc(b->k+1);
-                       Bcopy(b1, b);
+                       if (b1 == BIGINT_INVALID) {
+                               Bfree(b);
+                               return b1;
+                       }
+                       Bcopy_valid(b1, b);
                        Bfree(b);
                        b = b1;
                        }
@@ -489,10 +533,15 @@ s2b
        for(k = 0, y = 1; x > y; y <<= 1, k++) ;
 #ifdef Pack_32
        b = Balloc(k);
+       if (b == BIGINT_INVALID)
+               return b;
        b->x[0] = y9;
        b->wds = 1;
 #else
        b = Balloc(k+1);
+       if (b == BIGINT_INVALID)
+               return b;
+
        b->x[0] = y9 & 0xffff;
        b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
 #endif
@@ -604,8 +653,10 @@ i2b
        Bigint *b;
 
        b = Balloc(1);
-       b->x[0] = i;
-       b->wds = 1;
+       if (b != BIGINT_INVALID) {
+               b->x[0] = i;
+               b->wds = 1;
+               }
        return b;
 }
 
@@ -625,6 +676,9 @@ mult
        ULong z2;
 #endif
 
+       if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+               return BIGINT_INVALID;
+
        if (a->wds < b->wds) {
                c = a;
                a = b;
@@ -637,6 +691,8 @@ mult
        if (wc > a->maxwds)
                k++;
        c = Balloc(k);
+       if (c == BIGINT_INVALID)
+               return c;
        for(x = c->x, xa = x + wc; x < xa; x++)
                *x = 0;
        xa = a->x;
@@ -711,6 +767,9 @@ pow5mult
        int i;
        static const int p05[3] = { 5, 25, 125 };
 
+       if (b == BIGINT_INVALID)
+               return b;
+
        if ((i = k & 3) != 0)
                b = multadd(b, p05[i-1], 0);
 
@@ -718,7 +777,12 @@ pow5mult
                return b;
        if (!(p5 = p5s)) {
                /* first time */
-               p5 = p5s = i2b(625);
+               p5 = i2b(625);
+               if (p5 == BIGINT_INVALID) {
+                       Bfree(b);
+                       return p5;
+               }
+               p5s = p5;
                p5->next = 0;
        }
        for(;;) {
@@ -730,7 +794,12 @@ pow5mult
                if (!(k = (unsigned int) k >> 1))
                        break;
                if (!(p51 = p5->next)) {
-                       p51 = p5->next = mult(p5,p5);
+                       p51 = mult(p5,p5);
+                       if (p51 == BIGINT_INVALID) {
+                               Bfree(b);
+                               return p51;
+                       }
+                       p5->next = p51;
                        p51->next = 0;
                }
                p5 = p51;
@@ -750,6 +819,9 @@ lshift
        Bigint *b1;
        ULong *x, *x1, *xe, z;
 
+       if (b == BIGINT_INVALID)
+               return b;
+
 #ifdef Pack_32
        n = (unsigned int)k >> 5;
 #else
@@ -760,6 +832,10 @@ lshift
        for(i = b->maxwds; n1 > i; i <<= 1)
                k1++;
        b1 = Balloc(k1);
+       if (b1 == BIGINT_INVALID) {
+               Bfree(b);
+               return b1;
+       }
        x1 = b1->x;
        for(i = 0; i < n; i++)
                *x1++ = 0;
@@ -809,6 +885,13 @@ cmp
        ULong *xa, *xa0, *xb, *xb0;
        int i, j;
 
+       if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+#ifdef DEBUG
+               Bug("cmp called with a or b invalid");
+#else
+               return 0; /* equal - the best we can do right now */
+#endif
+
        i = a->wds;
        j = b->wds;
 #ifdef DEBUG
@@ -848,11 +931,16 @@ diff
        Long z;
 #endif
 
+       if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+               return BIGINT_INVALID;
+
        i = cmp(a,b);
        if (!i) {
                c = Balloc(0);
-               c->wds = 1;
-               c->x[0] = 0;
+               if (c != BIGINT_INVALID) {
+                       c->wds = 1;
+                       c->x[0] = 0;
+                       }
                return c;
        }
        if (i < 0) {
@@ -864,6 +952,8 @@ diff
        else
                i = 0;
        c = Balloc(a->k);
+       if (c == BIGINT_INVALID)
+               return c;
        c->sign = i;
        wa = a->wds;
        xa = a->x;
@@ -972,6 +1062,9 @@ b2d
 #define d1 word1(d)
 #endif
 
+       if (a == BIGINT_INVALID)
+               return NAN;
+
        xa0 = a->x;
        xa = xa0 + a->wds;
        y = *--xa;
@@ -1054,6 +1147,8 @@ d2b
 #else
        b = Balloc(2);
 #endif
+       if (b == BIGINT_INVALID)
+               return b;
        x = b->x;
 
        z = d0 & Frac_mask;
@@ -1169,6 +1264,9 @@ ratio
        _double da, db;
        int k, ka, kb;
 
+       if (a == BIGINT_INVALID || b == BIGINT_INVALID)
+               return NAN; /* for lack of better value ? */
+
        value(da) = b2d(a, &ka);
        value(db) = b2d(b, &kb);
 #ifdef Pack_32
@@ -1820,6 +1918,9 @@ quorem
        ULong si, zs;
 #endif
 
+       if (b == BIGINT_INVALID || S == BIGINT_INVALID)
+               return 0;
+
        n = S->wds;
 #ifdef DEBUG
        /*debug*/ if (b->wds > n)
@@ -2046,6 +2147,8 @@ __dtoa
 #endif
                                "NaN";
                result = Balloc(strlen(s)+1);
+               if (result == BIGINT_INVALID)
+                       return NULL;
                s0 = (char *)(void *)result;
                strcpy(s0, s);
                if (rve)
@@ -2063,6 +2166,8 @@ __dtoa
        if (!value(d)) {
                *decpt = 1;
                result = Balloc(2);
+               if (result == BIGINT_INVALID)
+                       return NULL;
                s0 = (char *)(void *)result;
                strcpy(s0, "0");
                if (rve)
@@ -2198,6 +2303,10 @@ __dtoa
         // complicated way the block size need to be computed
         // buuurk....
        result = Balloc(result_k);
+       if (result == BIGINT_INVALID) {
+               Bfree(b);
+               return NULL;
+       }
        s = s0 = (char *)(void *)result;
 
        if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@@ -2425,13 +2534,18 @@ __dtoa
         * and for all and pass them and a shift to quorem, so it
         * can do shifts and ors to compute the numerator for q.
         */
+       if (S == BIGINT_INVALID) {
+               i = 0;
+       } else {
 #ifdef Pack_32
-       if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
-               i = 32 - i;
+               if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
+                       i = 32 - i;
 #else
-       if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
-               i = 16 - i;
+               if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+                       i = 16 - i;
 #endif
+       }
+
        if (i > 4) {
                i -= 4;
                b2 += i;