summaryrefslogtreecommitdiff
path: root/stdio-common/vfprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common/vfprintf.c')
-rw-r--r--stdio-common/vfprintf.c54
1 files changed, 14 insertions, 40 deletions
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 0592e70603..6829d4dc8e 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2015 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -24,11 +24,12 @@
#include <string.h>
#include <errno.h>
#include <wchar.h>
-#include <bits/libc-lock.h>
+#include <libc-lock.h>
#include <sys/param.h>
#include <_itoa.h>
#include <locale/localeinfo.h>
#include <stdio.h>
+#include <scratch_buffer.h>
/* This code is shared between the standard stdio implementation found
in GNU C library and the libio implementation originally found in
@@ -1698,18 +1699,15 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
void *args_malloced = NULL;
/* For positional argument handling. */
- struct printf_spec *specs;
-
- /* Track if we malloced the SPECS array and thus must free it. */
- bool specs_malloced = false;
+ struct scratch_buffer specsbuf;
+ scratch_buffer_init (&specsbuf);
+ struct printf_spec *specs = specsbuf.data;
+ size_t specs_limit = specsbuf.length / sizeof (specs[0]);
/* Array with information about the needed arguments. This has to
be dynamically extensible. */
size_t nspecs = 0;
- /* A more or less arbitrary start value. */
- size_t nspecs_size = 32 * sizeof (struct printf_spec);
- specs = alloca (nspecs_size);
/* The number of arguments the format string requests. This will
determine the size of the array needed to store the argument
attributes. */
@@ -1746,42 +1744,15 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
f = specs[nspecs++].next_fmt)
{
- if (nspecs * sizeof (*specs) >= nspecs_size)
+ if (nspecs == specs_limit)
{
- /* Extend the array of format specifiers. */
- if (nspecs_size * 2 < nspecs_size)
+ if (!scratch_buffer_grow_preserve (&specsbuf))
{
- __set_errno (ENOMEM);
done = -1;
goto all_done;
}
- struct printf_spec *old = specs;
- if (__libc_use_alloca (2 * nspecs_size))
- specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
- else
- {
- nspecs_size *= 2;
- specs = malloc (nspecs_size);
- if (specs == NULL)
- {
- __set_errno (ENOMEM);
- specs = old;
- done = -1;
- goto all_done;
- }
- }
-
- /* Copy the old array's elements to the new space. */
- memmove (specs, old, nspecs * sizeof (*specs));
-
- /* If we had previously malloc'd space for SPECS, then
- release it after the copy is complete. */
- if (specs_malloced)
- free (old);
-
- /* Now set SPECS_MALLOCED if needed. */
- if (!__libc_use_alloca (nspecs_size))
- specs_malloced = true;
+ specs = specsbuf.data;
+ specs_limit = specsbuf.length / sizeof (specs[0]);
}
/* Parse the format specifier. */
@@ -2091,8 +2062,11 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
- specs[nspecs_done].end_of_fmt);
}
all_done:
+ if (__glibc_unlikely (args_malloced != NULL))
+ free (args_malloced);
if (__glibc_unlikely (workstart != NULL))
free (workstart);
+ scratch_buffer_free (&specsbuf);
return done;
}