1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-07 06:43:00 +03:00

(vfprintf): Avoid crashing for ridiculously large widths and precisions.

This commit is contained in:
Ulrich Drepper
2002-03-11 20:59:45 +00:00
parent 8eb095dd9d
commit 44e6a481fa

View File

@@ -253,6 +253,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
/* Buffer intermediate results. */ /* Buffer intermediate results. */
CHAR_T work_buffer[1000]; CHAR_T work_buffer[1000];
CHAR_T *workstart = NULL;
CHAR_T *workend; CHAR_T *workend;
/* State for restartable multibyte character handling functions. */ /* State for restartable multibyte character handling functions. */
@@ -1040,10 +1041,14 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
\ \
/* Allocate dynamically an array which definitely is long \ /* Allocate dynamically an array which definitely is long \
enough for the wide character version. */ \ enough for the wide character version. */ \
if (len < 8192 \ if (len < 8192) \
|| ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \
== NULL)) \
string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \ string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \
else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \
== NULL) \
{ \
done = -1; \
goto all_done; \
} \
else \ else \
string_malloced = 1; \ string_malloced = 1; \
\ \
@@ -1198,9 +1203,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (prec >= 0) \ if (prec >= 0) \
{ \ { \
/* The string `s2' might not be NUL terminated. */ \ /* The string `s2' might not be NUL terminated. */ \
if (prec < 32768 \ if (prec < 32768) \
|| (string = (char *) malloc (prec)) == NULL) \
string = (char *) alloca (prec); \ string = (char *) alloca (prec); \
else if ((string = (char *) malloc (prec)) == NULL) \
{ \
done = -1; \
goto all_done; \
} \
else \ else \
string_malloced = 1; \ string_malloced = 1; \
len = __wcsrtombs (string, &s2, prec, &mbstate); \ len = __wcsrtombs (string, &s2, prec, &mbstate); \
@@ -1212,9 +1221,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
{ \ { \
assert (__mbsinit (&mbstate)); \ assert (__mbsinit (&mbstate)); \
s2 = (const wchar_t *) string; \ s2 = (const wchar_t *) string; \
if (len + 1 < 32768 \ if (len + 1 < 32768) \
|| (string = (char *) malloc (len + 1)) == NULL) \
string = (char *) alloca (len + 1); \ string = (char *) alloca (len + 1); \
else if ((string = (char *) malloc (len + 1)) == NULL) \
{ \
done = -1; \
goto all_done; \
} \
else \ else \
string_malloced = 1; \ string_malloced = 1; \
(void) __wcsrtombs (string, &s2, len + 1, &mbstate); \ (void) __wcsrtombs (string, &s2, len + 1, &mbstate); \
@@ -1350,6 +1363,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
UCHAR_T pad = L_(' ');/* Padding character. */ UCHAR_T pad = L_(' ');/* Padding character. */
CHAR_T spec; CHAR_T spec;
workstart = NULL;
workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
/* Get current character in format string. */ /* Get current character in format string. */
@@ -1431,11 +1445,25 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
left = 1; left = 1;
} }
if (width + 32 >= (int) (sizeof (work_buffer) / sizeof (work_buffer[0]))) if (width + 32 >= (int) (sizeof (work_buffer)
/* We have to use a special buffer. The "32" is just a safe / sizeof (work_buffer[0])))
bet for all the output which is not counted in the width. */ {
workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T)) /* We have to use a special buffer. The "32" is just a safe
+ (width + 32)); bet for all the output which is not counted in the width. */
if (width < 32768 / sizeof (CHAR_T))
workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
+ (width + 32));
else
{
workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T));
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + (width + 32);
}
}
} }
JUMP (*f, step1_jumps); JUMP (*f, step1_jumps);
@@ -1444,10 +1472,23 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
width = read_int (&f); width = read_int (&f);
if (width + 32 >= (int) (sizeof (work_buffer) / sizeof (work_buffer[0]))) if (width + 32 >= (int) (sizeof (work_buffer) / sizeof (work_buffer[0])))
/* 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. */ /* We have to use a special buffer. The "32" is just a safe
workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T)) bet for all the output which is not counted in the width. */
+ (width + 32)); if (width < 32768 / sizeof (CHAR_T))
workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
+ (width + 32));
else
{
workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T));
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + (width + 32);
}
}
if (*f == L_('$')) if (*f == L_('$'))
/* Oh, oh. The argument comes from a positional parameter. */ /* Oh, oh. The argument comes from a positional parameter. */
goto do_positional; goto do_positional;
@@ -1476,7 +1517,20 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
prec = 0; prec = 0;
if (prec > width if (prec > width
&& prec + 32 > (int)(sizeof (work_buffer) / sizeof (work_buffer[0]))) && prec + 32 > (int)(sizeof (work_buffer) / sizeof (work_buffer[0])))
workend = alloca (spec + 32) + (spec + 32); {
if (spec < 32768 / sizeof (CHAR_T))
workend = alloca (spec + 32) + (spec + 32);
else
{
workstart = (CHAR_T *) malloc ((spec + 32) * sizeof (CHAR_T));
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + (spec + 32);
}
}
JUMP (*f, step2_jumps); JUMP (*f, step2_jumps);
/* Process 'h' modifier. There might another 'h' following. */ /* Process 'h' modifier. There might another 'h' following. */
@@ -1539,6 +1593,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
/* The format is correctly handled. */ /* The format is correctly handled. */
++nspecs_done; ++nspecs_done;
free (workstart);
workstart = NULL;
/* Look for next format specifier. */ /* Look for next format specifier. */
#ifdef COMPILE_WPRINTF #ifdef COMPILE_WPRINTF
f = find_spec ((end_of_spec = ++f)); f = find_spec ((end_of_spec = ++f));
@@ -1739,6 +1796,7 @@ do_positional:
int use_outdigits = specs[nspecs_done].info.i18n; int use_outdigits = specs[nspecs_done].info.i18n;
char pad = specs[nspecs_done].info.pad; char pad = specs[nspecs_done].info.pad;
CHAR_T spec = specs[nspecs_done].info.spec; CHAR_T spec = specs[nspecs_done].info.spec;
CHAR_T *workstart = NULL;
/* Fill in last information. */ /* Fill in last information. */
if (specs[nspecs_done].width_arg != -1) if (specs[nspecs_done].width_arg != -1)
@@ -1772,10 +1830,20 @@ do_positional:
} }
/* Maybe the buffer is too small. */ /* Maybe the buffer is too small. */
if (MAX (prec, width) + 32 > (int) (sizeof (work_buffer) / sizeof (CHAR_T))) if (MAX (prec, width) + 32 > (int) (sizeof (work_buffer)
workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32) / sizeof (CHAR_T)))
* sizeof (CHAR_T)) {
+ (MAX (prec, width) + 32)); if (MAX (prec, width) < 32768 / sizeof (CHAR_T))
workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
* sizeof (CHAR_T))
+ (MAX (prec, width) + 32));
else
{
workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
* sizeof (CHAR_T));
workend = workstart + (MAX (prec, width) + 32);
}
}
/* Process format specifiers. */ /* Process format specifiers. */
while (1) while (1)
@@ -1823,6 +1891,9 @@ do_positional:
break; break;
} }
free (workstart);
workstart = NULL;
/* Write the following constant string. */ /* Write the following constant string. */
outstring (specs[nspecs_done].end_of_fmt, outstring (specs[nspecs_done].end_of_fmt,
specs[nspecs_done].next_fmt specs[nspecs_done].next_fmt
@@ -1831,6 +1902,7 @@ do_positional:
} }
all_done: all_done:
free (workstart);
/* Unlock the stream. */ /* Unlock the stream. */
#ifdef USE_IN_LIBIO #ifdef USE_IN_LIBIO
_IO_funlockfile (s); _IO_funlockfile (s);