X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fstdio%2Fvfprintf.c;h=ea257720bf8088fb2e1106590fbe7f7df609eaba;hb=0206f596d5156af560e8af10e950d3cb2f29b73d;hp=1e7e6a477faeba521537d9146e003596ccaeba3e;hpb=835f9f950e2f6059532bd9ab9857a856ed21a4fd;p=musl diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c index 1e7e6a47..ea257720 100644 --- a/src/stdio/vfprintf.c +++ b/src/stdio/vfprintf.c @@ -13,8 +13,6 @@ #define MAX(a,b) ((a)>(b) ? (a) : (b)) #define MIN(a,b) ((a)<(b) ? (a) : (b)) -#define CONCAT2(x,y) x ## y -#define CONCAT(x,y) CONCAT2(x,y) /* Convenient bit representation for modifier flags, which all fall * within 31 codepoints of the space character. */ @@ -198,9 +196,17 @@ static char *fmt_u(uintmax_t x, char *s) return s; } +/* Do not override this check. The floating point printing code below + * depends on the float.h constants being right. If they are wrong, it + * may overflow the stack. */ +#if LDBL_MANT_DIG == 53 +typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; +#endif + static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) { - uint32_t big[(LDBL_MAX_EXP+LDBL_MANT_DIG)/9+1]; + uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion + + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion uint32_t *a, *d, *r, *z; int e2=0, e, i, j, l; char buf[9+LDBL_MANT_DIG/4], *s; @@ -300,13 +306,13 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) *d = x % 1000000000; carry = x / 1000000000; } - if (!z[-1] && z>a) z--; if (carry) *--a = carry; + while (z>a && !z[-1]) z--; e2-=sh; } while (e2<0) { uint32_t carry=0, *b; - int sh=MIN(9,-e2); + int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9; for (d=a; d>sh) + carry; @@ -316,7 +322,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) if (carry) *z++ = carry; /* Avoid (slow!) computation past requested precision */ b = (t|32)=='f' ? r : a; - if (z-b > 2+p/9) z = b+2+p/9; + if (z-b > need) z = b+need; e2+=sh; } @@ -335,7 +341,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) x = *d % i; /* Are there any significant digits past j? */ if (x || d+1!=z) { - long double round = CONCAT(0x1p,LDBL_MANT_DIG); + long double round = 2/LDBL_EPSILON; long double small; if (*d/i & 1) round += 2; if (x 999999999) { *d--=0; + if (d=i; i*=10, e++); } } if (z>d+1) z=d+1; - for (; !z[-1] && z>a; z--); } + for (; z>a && !z[-1]; z--); if ((t|32)=='g') { if (!p) p++; @@ -523,7 +529,6 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, /* Check validity of argument type (nl/normal) */ if (st==NOARG) { if (argpos>=0) return -1; - else if (!f) continue; } else { if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; else if (f) pop_arg(&arg, st, ap); @@ -653,8 +658,12 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) unsigned char internal_buf[80], *saved_buf = 0; int ret; + /* the copy allows passing va_list* even if va_list is an array */ va_copy(ap2, ap); - if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1; + if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { + va_end(ap2); + return -1; + } FLOCK(f); if (!f->buf_size) {