diff options
author | David 'Digit' Turner <digit@google.com> | 2010-03-22 15:45:32 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-03-22 15:45:32 -0700 |
commit | 709a898de82128c065381e258e8e71f0a55df976 (patch) | |
tree | 74fb234b3c8058ccb5a9b56ecd49eb9fdb6cce4f | |
parent | 88f06cd84a70f8a5212cb03272ec2c7cf0017afa (diff) | |
parent | 8132626b71b319c71c7c4710f0c57c417badf8c0 (diff) | |
download | bionic-709a898de82128c065381e258e8e71f0a55df976.zip bionic-709a898de82128c065381e258e8e71f0a55df976.tar.gz bionic-709a898de82128c065381e258e8e71f0a55df976.tar.bz2 |
Merge "Fix strtod security bug."
-rw-r--r-- | libc/stdlib/strtod.c | 170 |
1 files changed, 142 insertions, 28 deletions
diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c index 7fb7112..b1f5868 100644 --- a/libc/stdlib/strtod.c +++ b/libc/stdlib/strtod.c @@ -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 @@ -1821,6 +1919,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,15 +2147,17 @@ __dtoa !word1(d) && !(word0(d) & 0xfffff) ? "Infinity" : #endif "NaN"; - result = Balloc(strlen(s)+1); - s0 = (char *)(void *)result; - strcpy(s0, s); - if (rve) - *rve = + result = Balloc(strlen(s)+1); + if (result == BIGINT_INVALID) + return NULL; + s0 = (char *)(void *)result; + strcpy(s0, s); + if (rve) + *rve = #ifdef IEEE_Arith - s0[3] ? s0 + 8 : + s0[3] ? s0 + 8 : #endif - s0 + 3; + s0 + 3; return s0; } #endif @@ -2063,12 +2166,14 @@ __dtoa #endif if (!value(d)) { *decpt = 1; - result = Balloc(2); - s0 = (char *)(void *)result; - strcpy(s0, "0"); - if (rve) - *rve = s0 + 1; - return s0; + result = Balloc(2); + if (result == BIGINT_INVALID) + return NULL; + s0 = (char *)(void *)result; + strcpy(s0, "0"); + if (rve) + *rve = s0 + 1; + return s0; } b = d2b(value(d), &be, &bbits); @@ -2199,6 +2304,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) { @@ -2426,13 +2535,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; |