prevent invalid reads of nl_arg in printf_core
[musl] / src / stdio / vfprintf.c
index 15356f5..4555795 100644 (file)
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <wchar.h>
 #include <inttypes.h>
 #include <math.h>
@@ -220,6 +221,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
                else re=LDBL_MANT_DIG/4-1-p;
 
                if (re) {
+                       round *= 1<<(LDBL_MANT_DIG%4);
                        while (re--) round*=16;
                        if (*prefix=='-') {
                                y=-y;
@@ -476,8 +478,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
                if (*s=='*') {
                        if (isdigit(s[1]) && s[2]=='$') {
                                l10n=1;
-                               nl_type[s[1]-'0'] = INT;
-                               w = nl_arg[s[1]-'0'].i;
+                               if (!f) nl_type[s[1]-'0'] = INT, w = 0;
+                               else w = nl_arg[s[1]-'0'].i;
                                s+=3;
                        } else if (!l10n) {
                                w = f ? va_arg(*ap, int) : 0;
@@ -489,8 +491,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
                /* Read precision */
                if (*s=='.' && s[1]=='*') {
                        if (isdigit(s[2]) && s[3]=='$') {
-                               nl_type[s[2]-'0'] = INT;
-                               p = nl_arg[s[2]-'0'].i;
+                               if (!f) nl_type[s[2]-'0'] = INT, p = 0;
+                               else p = nl_arg[s[2]-'0'].i;
                                s+=4;
                        } else if (!l10n) {
                                p = f ? va_arg(*ap, int) : 0;
@@ -519,8 +521,10 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
                if (st==NOARG) {
                        if (argpos>=0) goto inval;
                } else {
-                       if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
-                       else if (f) pop_arg(&arg, st, ap);
+                       if (argpos>=0) {
+                               if (!f) nl_type[argpos]=st;
+                               else arg=nl_arg[argpos];
+                       } else if (f) pop_arg(&arg, st, ap);
                        else return 0;
                }
 
@@ -559,7 +563,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
                        if (0) {
                case 'o':
                        a = fmt_o(arg.i, z);
-                       if ((fl&ALT_FORM) && p<z-a+1) prefix+=5, pl=1;
+                       if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1;
                        } if (0) {
                case 'd': case 'i':
                        pl=1;
@@ -574,7 +578,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
                        a = fmt_u(arg.i, z);
                        }
                        if (xp && p<0) goto overflow;
-                       if (p>=0) fl &= ~ZERO_PAD;
+                       if (xp) fl &= ~ZERO_PAD;
                        if (!arg.i && !p) {
                                a=z;
                                break;
@@ -673,11 +677,12 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
        if (f->mode < 1) f->flags &= ~F_ERR;
        if (!f->buf_size) {
                saved_buf = f->buf;
-               f->wpos = f->wbase = f->buf = internal_buf;
+               f->buf = internal_buf;
                f->buf_size = sizeof internal_buf;
-               f->wend = internal_buf + sizeof internal_buf;
+               f->wpos = f->wbase = f->wend = 0;
        }
-       ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
+       if (!f->wend && __towrite(f)) ret = -1;
+       else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
        if (saved_buf) {
                f->write(f, 0, 0);
                if (!f->wpos) ret = -1;