diff --git a/ChangeLog b/ChangeLog index 435c18dca2..01737dfeec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +1999-02-23 Ulrich Drepper + + * stdio-common/vfprintf.c (vfprintf): If precision or width if too + large for work_buffer, allocate new buffer. + (printf_unknown): Likewise. [PR libc/988] + 1999-02-22 Ulrich Drepper * sysdeps/unix/sysv/linux/ttyname.c: Use __xstat and __fxstat diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index d9cd620853..b61b637af9 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -227,7 +227,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* Buffer intermediate results. */ char work_buffer[1000]; -#define workend (&work_buffer[sizeof (work_buffer) - 1]) + char *workend; /* State for restartable multibyte character handling functions. */ mbstate_t mbstate; @@ -1084,6 +1084,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) char pad = ' '; /* Padding character. */ CHAR_T spec; + workend = &work_buffer[sizeof (work_buffer) - 1]; + /* Get current character in format string. */ JUMP (*++f, step0_jumps); @@ -1157,12 +1159,22 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) pad = L_(' '); left = 1; } + + if (width + 32 >= sizeof (work_buffer)) + /* We have to use a special buffer. The "32" is just a safe + bet for all the output which is not counted in the width. */ + workend = alloca (width + 32) + (width + 31); } JUMP (*f, step1_jumps); /* Given width in format string. */ LABEL (width): width = read_int (&f); + + if (width + 32 >= sizeof (work_buffer)) + /* We have to use a special buffer. The "32" is just a safe + bet for all the output which is not counted in the width. */ + workend = alloca (width + 32) + (width + 31); if (*f == L_('$')) /* Oh, oh. The argument comes from a positional parameter. */ goto do_positional; @@ -1189,6 +1201,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) prec = read_int (&f); else prec = 0; + if (prec > width && prec + 32 > sizeof (work_buffer)) + workend = alloca (spec + 32) + (spec + 31); JUMP (*f, step2_jumps); /* Process 'h' modifier. There might another 'h' following. */ @@ -1471,6 +1485,10 @@ do_positional: prec = specs[nspecs_done].info.prec; } + /* Maybe the buffer is too small. */ + if (MAX (prec, width) + 32 > sizeof (work_buffer)) + workend = alloca (MAX (prec, width) + 32) + (MAX (prec, width) + 31); + /* Process format specifiers. */ while (1) { @@ -1558,7 +1576,8 @@ printf_unknown (FILE *s, const struct printf_info *info, { int done = 0; - char work_buffer[BUFSIZ]; + char work_buffer[MAX (info->width, info->spec) + 32]; + char *const workend = &work_buffer[sizeof (work_buffer) - 1]; register char *w; outchar ('%');