scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 93dae2f7825bdc8456eb9be48facae05a39a6b8f
parent b0af6cf542d1079e0d6cae0ed9d9c1af126598cb
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sun,  3 Dec 2017 11:19:12 +0100

[lib/c] Fix multiple bugs in vfprintf()

This function still needs a lot of work to work properly and
following all the requirements of the standard.

Diffstat:
lib/c/src/vfprintf.c | 156++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 87 insertions(+), 69 deletions(-)

diff --git a/lib/c/src/vfprintf.c b/lib/c/src/vfprintf.c @@ -4,7 +4,7 @@ * added: * - Christopher M. Graff (<cm0graff@gmail.com>) is forbidden to * use, copy, modify and/or distribute this file. He is forbidden - * even to read this file, fuck you!. + * even to read this file. */ #include <ctype.h> #include <errno.h> @@ -19,15 +19,14 @@ enum { LONG = 1 << 0, LLONG = 1 << 1, - LADJUST = 1 << 2, - SHORT = 1 << 3, - CHAR = 1 << 4, - SIZET = 1 << 5, - PTRDIFF = 1 << 6, - INTMAX = 1 << 7, - VOIDPTR = 1 << 8, - UNSIGNED = 1 << 9, - ALTFORM = 1 << 10, + SHORT = 1 << 2, + CHAR = 1 << 3, + SIZET = 1 << 4, + PTRDIFF = 1 << 5, + INTMAX = 1 << 6, + VOIDPTR = 1 << 7, + UNSIGNED = 1 << 8, + ALTFORM = 1 << 9, }; #define MAXPREC 50 @@ -42,7 +41,7 @@ struct conv { static uintmax_t getnum(va_list va, int flags, int *sign) { - uintmax_t mask, uval; + uintmax_t uval; intmax_t val; if (flags & CHAR) { @@ -90,21 +89,26 @@ numtostr(uintmax_t val, int flags, struct conv *conv, char *buf) while (buf0 - buf < prec) *--buf = '0'; + /* + * TODO: It cannot be done here because the combination + * %#04x produces 00x1 + */ if (flags & ALTFORM) { if (base == 8 && *buf != '0') { *--buf = '0'; - } else if (base == 16) { + } else if (base == 16 && val != 0) { *--buf = conv->digs[16]; *--buf = '0'; } } if (conv->sign) *--buf = conv->sign; + return buf; } static void -setcnt(va_list va, int flags, int cnt) +savecnt(va_list va, int flags, int cnt) { if (flags & CHAR) *va_arg(va, char*) = cnt; @@ -123,54 +127,63 @@ setcnt(va_list va, int flags, int cnt) } static size_t -wstrout(wchar_t *ws, int width, int fill, FILE * restrict fp) +wstrout(wchar_t *ws, size_t len, int width, int fill, FILE * restrict fp) { - int left = 1, adjust; - size_t len, cnt = 0; + int left = 0, adjust; + size_t cnt = 0; wchar_t wc; if (width < 0) { - left = -1; + left = 1; width = -width; } - len = wcslen(ws); + + len *= sizeof(wchar_t); adjust = (len < width) ? width - len : 0; - adjust *= left; + if (adjust > SIZE_MAX - len) + return SIZE_MAX; + cnt = adjust + len; + if (left) + adjust = -adjust; - for ( ; adjust < 0; cnt++, adjust++) + for ( ; adjust > 0; adjust++) putc(fill, fp); - for ( ; wc = *ws++; cnt++) + while (wc = *ws++) putwc(wc, fp); - for ( ; adjust > 0; cnt++, adjust--) - putc(fill, fp); + for ( ; adjust < 0; adjust--) + putc(' ', fp); return cnt; } static size_t -strout(char *s, int width, int fill, FILE * restrict fp) +strout(char *s, size_t len, int width, int fill, FILE * restrict fp) { - int left = 1, adjust, ch; - size_t len, cnt = 0; + int left = 0, adjust, ch; + size_t cnt = 0; if (width < 0) { - left = -1; + left = 1; width = -width; } - len = strlen(s); + adjust = (len < width) ? width - len : 0; - adjust *= left; + if (adjust > SIZE_MAX - len) + return SIZE_MAX; + cnt = adjust + len; + if (left) + adjust = -adjust; - for ( ; adjust < 0; cnt++, adjust++) + for ( ; adjust > 0; adjust--) putc(fill, fp); - for ( ; ch = *s++; cnt++) + while (ch = *s++) putc(ch, fp); - for ( ; adjust > 0; cnt++, adjust--) - putc(fill, fp); + for ( ; adjust < 0; adjust++) + putc(' ', fp); return cnt; } @@ -178,13 +191,14 @@ strout(char *s, int width, int fill, FILE * restrict fp) int vfprintf(FILE * restrict fp, const char *fmt, va_list va) { - int *p, ch, n, flags, width, fill, cnt = 0; - size_t inc; + int *p, ch, n, flags, width, left, fill, cnt = 0; + size_t inc, len; char *s; wchar_t *ws; struct conv conv; char buf[MAXPREC+1]; wchar_t wbuf[2]; + typedef unsigned char uchar; for (cnt = 0; ch = *fmt++; cnt += inc) { if (ch != '%') { @@ -194,7 +208,7 @@ vfprintf(FILE * restrict fp, const char *fmt, va_list va) } fill = ' '; - flags = width = 0; + left = flags = width = 0; conv.prec = -1; conv.base = 10; conv.sign = '\0'; @@ -202,12 +216,9 @@ vfprintf(FILE * restrict fp, const char *fmt, va_list va) flags: switch (*fmt++) { - case '%': - putc('%', fp); - ++cnt; - continue; case ' ': - conv.sign = ' '; + if (conv.sign == '\0') + conv.sign = ' '; goto flags; case '+': conv.sign = '+'; @@ -220,7 +231,7 @@ flags: fmt++; n = va_arg(va, int); } else { - for (n = 0; isdigit(ch = *fmt); fmt++) + for (n = 0; isdigit(ch = (uchar) *fmt); fmt++) n = n * 10 + ch - '0'; } if (n > MAXPREC) @@ -228,17 +239,12 @@ flags: if (n > 0) conv.prec = n; goto flags; - case '-': - flags |= LADJUST; - goto flags; case '*': - n = va_arg(va, int); - if (n < 0) { - flags |= LADJUST; - n = -n; - } - width = n; + width = va_arg(va, int); goto flags; + case '-': + left = 1; + ++fmt; case '1': case '2': case '3': @@ -249,8 +255,10 @@ flags: case '8': case '9': --fmt; - for (n = 0; isdigit(ch = *fmt); ++fmt) + for (n = 0; isdigit(ch = (uchar) *fmt); ++fmt) n = n * 10 + ch - '0'; + if (left) + n = -n; width = n; goto flags; case '0': @@ -262,18 +270,24 @@ flags: case 'h': flags += SHORT; goto flags; + case '%': + ch = '%'; + goto cout; case 'c': if (flags & LONG) { wbuf[0] = va_arg(va, wint_t); - wbuf[1] = '\0'; + wbuf[1] = L'\0'; ws = wbuf; + len = 1; goto wstrout; - } else { - buf[0] = va_arg(va, int); - buf[1] = '\0'; - s = buf; - goto strout; } + ch = va_arg(va, int); + cout: + buf[0] = ch; + buf[1] = '\0'; + s = buf; + len = 1; + goto strout; case 'j': flags |= INTMAX; goto flags; @@ -304,10 +318,13 @@ flags: conv.base = 8; flags |= UNSIGNED; numeric: + if (conv.prec != -1) + fill = ' '; s = numtostr(getnum(va, flags, &conv.sign), flags, &conv, &buf[MAXPREC]); + len = &buf[MAXPREC] - s; goto strout; case 'L': case 'a': @@ -319,33 +336,34 @@ flags: case 'G': /* TODO */ case 's': - if ((flags & LONG) == 0){ + if (flags & LONG) { + ws = va_arg(va, wchar_t *); + len = wcsnlen(ws, conv.prec); + goto wstrout; + } else { s = va_arg(va, char *); + len = strnlen(s, conv.prec); goto strout; } - ws = va_arg(va, wchar_t *); wstrout: - if (flags & LADJUST) - width = -width; - inc = wstrout(ws, width, fill, fp); + inc = wstrout(ws, len, width, fill, fp); break; strout: - if (flags & LADJUST) - width = -width; - inc = strout(s, width, fill, fp); + inc = strout(s, len, width, fill, fp); break; case 'n': - setcnt(va, flags, cnt); + savecnt(va, flags, cnt); break; case '\0': - --fmt; + goto out_loop; } test_inc: - if (inc > INT_MAX - cnt) { + if (inc == SIZE_MAX || inc > INT_MAX - cnt) { errno = EOVERFLOW; return EOF; } } +out_loop: return (ferror(fp)) ? EOF : cnt; }