diff options
Diffstat (limited to 'missing')
| -rw-r--r-- | missing/dtoa.c | 314 | ||||
| -rw-r--r-- | missing/setproctitle.c | 45 |
2 files changed, 209 insertions, 150 deletions
diff --git a/missing/dtoa.c b/missing/dtoa.c index bce2cb22a1..ba8cd46ebd 100644 --- a/missing/dtoa.c +++ b/missing/dtoa.c @@ -98,17 +98,6 @@ * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked * directly -- and assumed always to succeed. - * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making - * memory allocations from a private pool of memory when possible. - * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, - * unless #defined to be a different length. This default length - * suffices to get rid of MALLOC calls except for unusual cases, - * such as decimal-to-binary conversion of a very long string of - * digits. The longest string dtoa can return is about 751 bytes - * long. For conversions by strtod of strings of 800 digits and - * all dtoa conversions in single-threaded executions with 8-byte - * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte - * pointers, PRIVATE_MEM >= 7112 appears adequate. * #define INFNAN_CHECK on IEEE systems to cause strtod to check for * Infinity and NaN (case insensitively). On some systems (e.g., * some HP systems), it may be necessary to #define NAN_WORD0 @@ -221,6 +210,29 @@ #include <locale.h> #endif +#if defined(HAVE_STDCKDINT_H) || !defined(__has_include) +#elif __has_include(<stdckdint.h>) +# define HAVE_STDCKDINT_H 1 +#endif +#ifdef HAVE_STDCKDINT_H +# include <stdckdint.h> +#endif + +#if !defined(ckd_add) +static inline int /* bool */ +ckd_add(int *result, int x, int y) +{ + if (x < 0) { + if (y < INT_MIN - x) return 1; + } + else if (x > 0) { + if (y > INT_MAX - x) return 1; + } + *result = x + y; + return 0; +} +#endif + #ifdef MALLOC extern void *MALLOC(size_t); #else @@ -235,14 +247,6 @@ extern void FREE(void*); #define NO_SANITIZE(x, y) y #endif -#ifndef Omit_Private_Memory -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 -#endif -#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; -#endif - #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_BIG_ENDIAN @@ -527,83 +531,29 @@ struct Bigint { typedef struct Bigint Bigint; -static Bigint *freelist[Kmax+1]; - -#define BLOCKING_BIGINT ((Bigint *)(-1)) - static Bigint * Balloc(int k) { int x; Bigint *rv; -#ifndef Omit_Private_Memory - size_t len; -#endif - - rv = 0; - ACQUIRE_DTOA_LOCK(0); - if (k <= Kmax) { - rv = freelist[k]; - while (rv) { - Bigint *rvn = rv; - rv = ATOMIC_PTR_CAS(freelist[k], rv, BLOCKING_BIGINT); - if (LIKELY(rv != BLOCKING_BIGINT && rvn == rv)) { - rvn = ATOMIC_PTR_CAS(freelist[k], BLOCKING_BIGINT, rv->next); - assert(rvn == BLOCKING_BIGINT); - ASSUME(rv); - break; - } - } - } - if (!rv) { - x = 1 << k; -#ifdef Omit_Private_Memory - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); -#else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) - /sizeof(double); - if (k <= Kmax) { - double *pnext = pmem_next; - while (pnext - private_mem + len <= PRIVATE_mem) { - double *p = pnext; - pnext = ATOMIC_PTR_CAS(pmem_next, pnext, pnext + len); - if (LIKELY(p == pnext)) { - rv = (Bigint*)pnext; - ASSUME(rv); - break; - } - } - } - if (!rv) - rv = (Bigint*)MALLOC(len*sizeof(double)); -#endif - rv->k = k; - rv->maxwds = x; - } - FREE_DTOA_LOCK(0); + + x = 1 << k; + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) return NULL; + rv->k = k; + rv->maxwds = x; rv->sign = rv->wds = 0; return rv; } static void -Bfree(Bigint *v) +Bclear(Bigint **vp) { - Bigint *vn; - if (v) { - if (v->k > Kmax) { - FREE(v); - return; - } - ACQUIRE_DTOA_LOCK(0); - do { - do { - vn = ATOMIC_PTR_CAS(freelist[v->k], 0, 0); - } while (UNLIKELY(vn == BLOCKING_BIGINT)); - v->next = vn; - } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn)); - FREE_DTOA_LOCK(0); - } + Bigint *v = *vp; + *vp = NULL; + if (v) FREE(v); } +#define Bfree(v) Bclear(&(v)) #define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \ (y)->wds*sizeof(Long) + 2*sizeof(int)) @@ -649,6 +599,10 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */ if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); + if (!b1) { + Bfree(b); + return NULL; + } Bcopy(b1, b); Bfree(b); b = b1; @@ -670,10 +624,12 @@ s2b(const char *s, int nd0, int nd, ULong y9) for (k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(k); + if (!b) return NULL; b->x[0] = y9; b->wds = 1; #else b = Balloc(k+1); + if (!b) return NULL; b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif @@ -683,13 +639,16 @@ s2b(const char *s, int nd0, int nd, ULong y9) s += 9; do { b = multadd(b, 10, *s++ - '0'); + if (!b) return NULL; } while (++i < nd0); s++; } else s += 10; - for (; i < nd; i++) + for (; i < nd; i++) { b = multadd(b, 10, *s++ - '0'); + if (!b) return NULL; + } return b; } @@ -771,11 +730,14 @@ i2b(int i) Bigint *b; b = Balloc(1); + if (!b) return NULL; b->x[0] = i; b->wds = 1; return b; } +#define Bzero_p(b) (!(b)->x[0] && (b)->wds <= 1) + static Bigint * mult(Bigint *a, Bigint *b) { @@ -792,6 +754,14 @@ mult(Bigint *a, Bigint *b) #endif #endif + if (Bzero_p(a) || Bzero_p(b)) { + c = Balloc(0); + if (!c) return NULL; + c->wds = 1; + c->x[0] = 0; + return c; + } + if (a->wds < b->wds) { c = a; a = b; @@ -804,6 +774,7 @@ mult(Bigint *a, Bigint *b) if (wc > a->maxwds) k++; c = Balloc(k); + if (!c) return NULL; for (x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; @@ -883,50 +854,47 @@ static Bigint * pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; - Bigint *p5tmp; int i; static const int p05[3] = { 5, 25, 125 }; - if ((i = k & 3) != 0) + if ((i = k & 3) != 0) { b = multadd(b, p05[i-1], 0); + if (!b) return NULL; + } + +#define b_cache(var, addr, new_expr) \ + if ((var = addr) != 0) {} else { \ + Bigint *tmp = 0; \ + ACQUIRE_DTOA_LOCK(1); \ + if (!(var = addr) && (var = (new_expr)) != 0) { \ + var->next = 0; \ + tmp = ATOMIC_PTR_CAS(addr, NULL, var); \ + } \ + FREE_DTOA_LOCK(1); \ + if (UNLIKELY(tmp)) { \ + Bfree(var); \ + var = tmp; \ + } \ + else if (!var) { \ + Bfree(b); \ + return NULL; \ + } \ + } if (!(k >>= 2)) return b; - if (!(p5 = p5s)) { - /* first time */ - ACQUIRE_DTOA_LOCK(1); - if (!(p5 = p5s)) { - p5 = i2b(625); - p5->next = 0; - p5tmp = ATOMIC_PTR_CAS(p5s, NULL, p5); - if (UNLIKELY(p5tmp)) { - Bfree(p5); - p5 = p5tmp; - } - } - FREE_DTOA_LOCK(1); - } + /* first time */ + b_cache(p5, p5s, i2b(625)); for (;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; + if (!b) return NULL; } if (!(k >>= 1)) break; - if (!(p51 = p5->next)) { - ACQUIRE_DTOA_LOCK(1); - if (!(p51 = p5->next)) { - p51 = mult(p5,p5); - p51->next = 0; - p5tmp = ATOMIC_PTR_CAS(p5->next, NULL, p51); - if (UNLIKELY(p5tmp)) { - Bfree(p51); - p51 = p5tmp; - } - } - FREE_DTOA_LOCK(1); - } + b_cache(p51, p5->next, mult(p5, p5)); p5 = p51; } return b; @@ -939,6 +907,8 @@ lshift(Bigint *b, int k) Bigint *b1; ULong *x, *x1, *xe, z; + if (!k || Bzero_p(b)) return b; + #ifdef Pack_32 n = k >> 5; #else @@ -949,6 +919,10 @@ lshift(Bigint *b, int k) for (i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); + if (!b1) { + Bfree(b); + return NULL; + } x1 = b1->x; for (i = 0; i < n; i++) *x1++ = 0; @@ -1034,6 +1008,7 @@ diff(Bigint *a, Bigint *b) i = cmp(a,b); if (!i) { c = Balloc(0); + if (!c) return NULL; c->wds = 1; c->x[0] = 0; return c; @@ -1047,6 +1022,7 @@ diff(Bigint *a, Bigint *b) else i = 0; c = Balloc(a->k); + if (!c) return NULL; c->sign = i; wa = a->wds; xa = a->x; @@ -1232,6 +1208,7 @@ d2b(double d_, int *e, int *bits) #else b = Balloc(2); #endif + if (!b) return NULL; x = b->x; z = d0 & Frac_mask; @@ -1552,7 +1529,7 @@ break2: aadj = 1.0; nd0 = -4; - if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if (!*++s || (!(s1 = strchr(hexdigit, *s)) && *s != '.')) goto ret0; if (*s == '0') { while (*++s == '0'); if (!*s) goto ret; @@ -1566,9 +1543,7 @@ break2: } while (*++s && (s1 = strchr(hexdigit, *s))); } - if (*s == '.') { - dsign = 1; - if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if ((*s == '.') && *++s && (s1 = strchr(hexdigit, *s))) { if (nd0 < 0) { while (*s == '0') { s++; @@ -1583,9 +1558,6 @@ break2: } } } - else { - dsign = 0; - } if (*s == 'P' || *s == 'p') { dsign = 0x2C - *++s; /* +: 2B, -: 2D */ @@ -1608,9 +1580,6 @@ break2: } while ('0' <= c && c <= '9'); nd0 += nd * dsign; } - else { - if (dsign) goto ret0; - } dval(rv) = ldexp(adj, nd0); goto ret; } @@ -1647,9 +1616,9 @@ break2: } #endif if (c == '.') { - if (!ISDIGIT(s[1])) - goto dig_done; c = *++s; + if (!ISDIGIT(c)) + goto dig_done; if (!nd) { for (; c == '0'; c = *++s) nz++; @@ -1990,12 +1959,16 @@ undfl: /* Put digits into bd: true value = bd * 10^e */ bd0 = s2b(s0, nd0, nd, y); + if (!bd0) goto ret; for (;;) { bd = Balloc(bd0->k); + if (!bd) goto retfree; Bcopy(bd, bd0); bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ + if (!bb) goto retfree; bs = i2b(1); + if (!bs) goto retfree; if (e >= 0) { bb2 = bb5 = 0; @@ -2052,19 +2025,30 @@ undfl: } if (bb5 > 0) { bs = pow5mult(bs, bb5); + if (!bs) goto retfree; bb1 = mult(bs, bb); Bfree(bb); bb = bb1; + if (!bb) goto retfree; } - if (bb2 > 0) + if (bb2 > 0) { bb = lshift(bb, bb2); - if (bd5 > 0) + if (!bb) goto retfree; + } + if (bd5 > 0) { bd = pow5mult(bd, bd5); - if (bd2 > 0) + if (!bd) goto retfree; + } + if (bd2 > 0) { bd = lshift(bd, bd2); - if (bs2 > 0) + if (!bd) goto retfree; + } + if (bs2 > 0) { bs = lshift(bs, bs2); + if (!bs) goto retfree; + } delta = diff(bb, bd); + if (!delta) goto retfree; dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); @@ -2097,6 +2081,7 @@ undfl: #endif { delta = lshift(delta,Log2P); + if (!delta) goto nomem; if (cmp(delta, bs) <= 0) adj = -0.5; } @@ -2186,6 +2171,7 @@ apply_adj: break; } delta = lshift(delta,Log2P); + if (!delta) goto retfree; if (cmp(delta, bs) > 0) goto drop_down; break; @@ -2588,6 +2574,7 @@ nrv_alloc(const char *s, char **rve, size_t n) char *rv, *t; t = rv = rv_alloc(n); + if (!rv) return NULL; while ((*t = *s++) != 0) t++; if (rve) *rve = t; @@ -2760,6 +2747,7 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) #endif b = d2b(dval(d), &be, &bbits); + if (!b) return NULL; #ifdef Sudden_Underflow i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else @@ -2879,13 +2867,20 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) leftright = 0; /* no break */ case 5: - i = ndigits + k + 1; + if (ckd_add(&i, ndigits, k + 1)) { /* k + 1 should be safe */ + Bfree(b); + return NULL; + } ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } s = s0 = rv_alloc(i+1); + if (!s) { + Bfree(b); + return NULL; + } #ifdef Honor_FLT_ROUNDS if (mode > 1 && rounding != 1) @@ -3066,6 +3061,7 @@ bump_up: b2 += i; s2 += i; mhi = i2b(1); + if (!mhi) goto nomem; } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; @@ -3077,19 +3073,28 @@ bump_up: if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); + if (!mhi) goto nomem; b1 = mult(mhi, b); Bfree(b); b = b1; + if (!b) goto nomem; } - if ((j = b5 - m5) != 0) + if ((j = b5 - m5) != 0) { b = pow5mult(b, j); + if (!b) goto nomem; + } } - else + else { b = pow5mult(b, b5); + if (!b) goto nomem; + } } S = i2b(1); - if (s5 > 0) + if (!S) goto nomem; + if (s5 > 0) { S = pow5mult(S, s5); + if (!S) goto nomem; + } /* Check for special case that d is a normalized power of 2. */ @@ -3137,16 +3142,23 @@ bump_up: m2 += i; s2 += i; } - if (b2 > 0) + if (b2 > 0) { b = lshift(b, b2); - if (s2 > 0) + if (!b) goto nomem; + } + if (s2 > 0) { S = lshift(S, s2); + if (!S) goto nomem; + } if (k_check) { if (cmp(b,S) < 0) { k--; b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) + if (!b) goto nomem; + if (leftright) { mhi = multadd(mhi, 10, 0); + if (!mhi) goto nomem; + } ilim = ilim1; } } @@ -3163,8 +3175,10 @@ one_digit: goto ret; } if (leftright) { - if (m2 > 0) + if (m2 > 0) { mhi = lshift(mhi, m2); + if (!mhi) goto nomem; + } /* Compute mlo -- check for special case * that d is a normalized power of 2. @@ -3173,8 +3187,10 @@ one_digit: mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); + if (!mhi) goto nomem; Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); + if (!mhi) goto nomem; } for (i = 1;;i++) { @@ -3184,6 +3200,7 @@ one_digit: */ j = cmp(b, mlo); delta = diff(S, mhi); + if (!delta) goto nomem; j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); #ifndef ROUND_BIASED @@ -3224,6 +3241,7 @@ one_digit: #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(b, 1); + if (!b) goto nomem; j1 = cmp(b, S); if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') goto round_9_up; @@ -3252,11 +3270,16 @@ keep_dig: if (i == ilim) break; b = multadd(b, 10, 0); - if (mlo == mhi) + if (!b) goto nomem; + if (mlo == mhi) { mlo = mhi = multadd(mhi, 10, 0); + if (!mlo) goto nomem; + } else { mlo = multadd(mlo, 10, 0); + if (!mlo) goto nomem; mhi = multadd(mhi, 10, 0); + if (!mhi) goto nomem; } } } @@ -3272,6 +3295,7 @@ keep_dig: if (i >= ilim) break; b = multadd(b, 10, 0); + if (!b) goto nomem; } /* Round off last digit */ @@ -3283,6 +3307,7 @@ keep_dig: } #endif b = lshift(b, 1); + if (!b) goto nomem; j = cmp(b, S); if (j > 0 || (j == 0 && (dig & 1))) { roundoff: @@ -3324,6 +3349,16 @@ ret1: if (rve) *rve = s; return s0; + nomem: + if (S) Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + if (b) Bfree(b); + FREE(s0); + return NULL; } /*- @@ -3432,6 +3467,7 @@ hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rv */ bufsize = (ndigits > 0) ? ndigits : SIGFIGS; s0 = rv_alloc(bufsize+1); + if (!s0) return NULL; /* Round to the desired number of digits. */ if (SIGFIGS > ndigits && ndigits > 0) { diff --git a/missing/setproctitle.c b/missing/setproctitle.c index f90886671c..5b2dfa65ce 100644 --- a/missing/setproctitle.c +++ b/missing/setproctitle.c @@ -87,7 +87,30 @@ static char **argv1_addr = NULL; #endif #if ALLOCATE_ENVIRON +/* system_environ is the value of environ before we allocate a custom buffer. + * + * We use this to restore environ in ruby_free_proctitle. + */ +static char **system_environ = NULL; +/* orig_environ is the buffer we allocate for environ. + * + * We use this to free this buffer in ruby_free_proctitle. When we add new + * environment variables using setenv, the system may change environ to a + * different buffer and will not free the original buffer, so we need to hold + * onto this so we can free it in ruby_free_proctitle. + * + * We must not free any of the contents because it may change if the system + * updates existing environment variables. + */ static char **orig_environ = NULL; +/* alloc_environ is a copy of orig_environ. + * + * We use this to free all the original string copies that were in orig_environ. + * Since environ could be changed to point to strings allocated by the system + * if environment variables are updated, so we need this to point to the + * original strings. + */ +static char **alloc_environ = NULL; #endif void @@ -112,6 +135,9 @@ compat_init_setproctitle(int argc, char *argv[]) /* Fail if we can't allocate room for the new environment */ for (i = 0; envp[i] != NULL; i++); + system_environ = environ; + + alloc_environ = xcalloc(i + 1, sizeof(*environ)); orig_environ = environ = xcalloc(i + 1, sizeof(*environ)); if (environ == NULL) { environ = envp; /* put it back */ @@ -140,8 +166,8 @@ compat_init_setproctitle(int argc, char *argv[]) argv_env_len = lastenvp - argv[0]; for (i = 0; envp[i] != NULL; i++) - environ[i] = ruby_strdup(envp[i]); - environ[i] = NULL; + alloc_environ[i] = environ[i] = ruby_strdup(envp[i]); + alloc_environ[i] = environ[i] = NULL; #endif /* SPT_REUSEARGV */ } @@ -153,16 +179,13 @@ ruby_free_proctitle(void) if (!orig_environ) return; /* environ is allocated by OS */ - /* ruby_setenv could allocate a new environ, so we need to free orig_environ - * in that case. */ - if (environ != orig_environ) { - for (int i = 0; orig_environ[i] != NULL; i++) { - xfree(orig_environ[i]); - } - - xfree(orig_environ); - orig_environ = NULL; + for (int i = 0; alloc_environ[i] != NULL; i++) { + xfree(alloc_environ[i]); } + xfree(alloc_environ); + xfree(orig_environ); + + environ = system_environ; #endif } |
