On Mon, May 09, 2011 at 10:01:08PM +0200, Stefan Sperling wrote: > On Fri, Apr 29, 2011 at 01:09:56PM +0200, Stefan Sperling wrote: > > Anyone? > > Updated diff following the vfwprintf() memory leak fix. > The previous version of this diff had the same bug.
ping > > Index: Makefile.inc > =================================================================== > RCS file: /cvs/src/lib/libc/stdio/Makefile.inc,v > retrieving revision 1.16 > diff -u -p -r1.16 Makefile.inc > --- Makefile.inc 28 Apr 2011 17:38:46 -0000 1.16 > +++ Makefile.inc 29 Apr 2011 12:52:29 -0000 > @@ -3,7 +3,7 @@ > # stdio sources > .PATH: ${LIBCSRCDIR}/stdio > > -CFLAGS+=-DFLOATING_POINT > +CFLAGS+=-DFLOATING_POINT -DPRINTF_WIDE_CHAR > > SRCS+= asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c > fgetc.c \ > fgetln.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \ > Index: vfprintf.c > =================================================================== > RCS file: /cvs/src/lib/libc/stdio/vfprintf.c,v > retrieving revision 1.60 > diff -u -p -r1.60 vfprintf.c > --- vfprintf.c 22 Dec 2010 14:54:44 -0000 1.60 > +++ vfprintf.c 8 May 2011 23:17:09 -0000 > @@ -49,6 +49,7 @@ > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > +#include <wchar.h> > > #include "local.h" > #include "fvwrite.h" > @@ -79,6 +80,8 @@ union arg { > double doublearg; > long double longdoublearg; > #endif > + wint_t wintarg; > + wchar_t *pwchararg; > }; > > static int __find_arguments(const char *fmt0, va_list ap, union arg > **argtable, > @@ -138,6 +141,72 @@ __sbprintf(FILE *fp, const char *fmt, va > return (ret); > } > > +#ifdef PRINTF_WIDE_CHAR > +/* > + * Convert a wide character string argument for the %ls format to a multibyte > + * string representation. If not -1, prec specifies the maximum number of > + * bytes to output, and also means that we can't assume that the wide char > + * string is null-terminated. > + */ > +static char * > +__wcsconv(wchar_t *wcsarg, int prec) > +{ > + mbstate_t mbs; > + char buf[MB_LEN_MAX]; > + wchar_t *p; > + char *convbuf; > + size_t clen, nbytes; > + > + /* Allocate space for the maximum number of bytes we could output. */ > + if (prec < 0) { > + memset(&mbs, 0, sizeof(mbs)); > + p = wcsarg; > + nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); > + if (nbytes == (size_t)-1) { > + errno = EILSEQ; > + return (NULL); > + } > + } else { > + /* > + * Optimisation: if the output precision is small enough, > + * just allocate enough memory for the maximum instead of > + * scanning the string. > + */ > + if (prec < 128) > + nbytes = prec; > + else { > + nbytes = 0; > + p = wcsarg; > + memset(&mbs, 0, sizeof(mbs)); > + for (;;) { > + clen = wcrtomb(buf, *p++, &mbs); > + if (clen == 0 || clen == (size_t)-1 || > + nbytes + clen > (size_t)prec) > + break; > + nbytes += clen; > + } > + if (clen == (size_t)-1) { > + errno = EILSEQ; > + return (NULL); > + } > + } > + } > + if ((convbuf = malloc(nbytes + 1)) == NULL) > + return (NULL); > + > + /* Fill the output buffer. */ > + p = wcsarg; > + memset(&mbs, 0, sizeof(mbs)); > + if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, > + nbytes, &mbs)) == (size_t)-1) { > + free(convbuf); > + errno = EILSEQ; > + return (NULL); > + } > + convbuf[nbytes] = '\0'; > + return (convbuf); > +} > +#endif > > #ifdef FLOATING_POINT > #include <float.h> > @@ -260,7 +329,9 @@ __vfprintf(FILE *fp, const char *fmt0, _ > size_t argtablesiz; > int nextarg; /* 1-based argument index */ > va_list orgap; /* original argument pointer */ > - > +#ifdef PRINTF_WIDE_CHAR > + char *convbuf; /* buffer for wide to multi-byte conversion */ > +#endif > /* > * Choose PADSIZE to trade efficiency vs. size. If larger printf > * fields occur frequently, increase PADSIZE and make the initialisers > @@ -402,7 +473,9 @@ __vfprintf(FILE *fp, const char *fmt0, _ > uio.uio_resid = 0; > uio.uio_iovcnt = 0; > ret = 0; > - > +#ifdef PRINTF_WIDE_CHAR > + convbuf = NULL; > +#endif > memset(&ps, 0, sizeof(ps)); > /* > * Scan the format for conversions (`%' character). > @@ -553,8 +626,28 @@ reswitch: switch (ch) { > flags |= SIZEINT; > goto rflag; > case 'c': > - *(cp = buf) = GETARG(int); > - size = 1; > +#ifdef PRINTF_WIDE_CHAR > + if (flags & LONGINT) { > + mbstate_t mbs; > + size_t mbseqlen; > + > + memset(&mbs, 0, sizeof(mbs)); > + mbseqlen = wcrtomb(buf, > + (wchar_t)GETARG(wint_t), &mbs); > + if (mbseqlen == (size_t)-1) { > + fp->_flags |= __SERR; > + errno = EILSEQ; > + goto error; > + } > + cp = buf; > + size = (int)mbseqlen; > + } else { > +#endif > + *(cp = buf) = GETARG(int); > + size = 1; > +#ifdef PRINTF_WIDE_CHAR > + } > +#endif > sign = '\0'; > break; > case 'D': > @@ -744,6 +837,26 @@ fp_common: > ox[1] = 'x'; > goto nosign; > case 's': > +#ifdef PRINTF_WIDE_CHAR > + if (flags & LONGINT) { > + wchar_t *wcp; > + > + if (convbuf != NULL) { > + free(convbuf); > + convbuf = NULL; > + } > + if ((wcp = GETARG(wchar_t *)) == NULL) { > + cp = "(null)"; > + } else { > + convbuf = __wcsconv(wcp, prec); > + if (convbuf == NULL) { > + fp->_flags = __SERR; > + goto error; > + } > + cp = convbuf; > + } > + } else > +#endif /* PRINTF_WIDE_CHAR */ > if ((cp = GETARG(char *)) == NULL) > cp = "(null)"; > if (prec >= 0) { > @@ -954,6 +1067,10 @@ overflow: > ret = -1; > > finish: > +#ifdef PRINTF_WIDE_CHAR > + if (convbuf) > + free(convbuf); > +#endif > #ifdef FLOATING_POINT > if (dtoaresult) > __freedtoa(dtoaresult); > @@ -995,6 +1112,8 @@ finish: > #define TP_MAXINT 24 > #define T_CHAR 25 > #define T_U_CHAR 26 > +#define T_WINT 27 > +#define TP_WCHAR 28 > > /* > * Find all arguments when a positional parameter is encountered. Returns a > @@ -1160,7 +1279,12 @@ reswitch: switch (ch) { > flags |= SIZEINT; > goto rflag; > case 'c': > - ADDTYPE(T_INT); > +#ifdef PRINTF_WIDE_CHAR > + if (flags & LONGINT) > + ADDTYPE(T_WINT); > + else > +#endif > + ADDTYPE(T_INT); > break; > case 'D': > flags |= LONGINT; > @@ -1210,7 +1334,12 @@ reswitch: switch (ch) { > ADDTYPE(TP_VOID); > break; > case 's': > - ADDTYPE(TP_CHAR); > +#ifdef PRINTF_WIDE_CHAR > + if (flags & LONGINT) > + ADDTYPE(TP_WCHAR); > + else > +#endif > + ADDTYPE(TP_CHAR); > break; > case 'U': > flags |= LONGINT; > @@ -1311,6 +1440,14 @@ done: > case TP_MAXINT: > (*argtable)[n].intmaxarg = va_arg(ap, intmax_t); > break; > +#ifdef PRINTF_WIDE_CHAR > + case T_WINT: > + (*argtable)[n].wintarg = va_arg(ap, wint_t); > + break; > + case TP_WCHAR: > + (*argtable)[n].pwchararg = va_arg(ap, wchar_t *); > + break; > +#endif > } > } > goto finish;