[PATCH v5 3/3] stdio-common: Optimize %ms expansion for best fit
Rocket Ma
marocketbd@gmail.com
Tue Apr 14 02:17:08 GMT 2026
* stdio-common/vfscanf-internal.c: Add grow_to_fit to calculate the size
of expanded string during %ms/%m[ scan for best fit.
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
---
stdio-common/vfscanf-internal.c | 63 ++++++++++++++++++++++-----------
1 file changed, 42 insertions(+), 21 deletions(-)
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 3d11ac261e..8eec294a98 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -265,6 +265,17 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
*buffer->current++ = ch;
}
+/* Calculate the result size of expanded char array in %ms, %mS,
+ %m[ or %lm[. */
+static __always_inline size_t
+grow_to_fit (size_t oldsize, int need)
+{
+ if (need < 0 || oldsize < need)
+ return oldsize * 2;
+ /* oldsize >= need: grow requested capacity and 1 byte for `\0' */
+ return oldsize + need + 1;
+}
+
/* Read formatted input from S according to the format string
FORMAT, using the argument list in ARG.
Return the number of assignments made, or -1 for an input error. */
@@ -804,7 +815,8 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& *strptr + strsize - str <= MB_LEN_MAX)
{
/* We have to enlarge the buffer if the `m' flag
- was given. */
+ was given. And we may not expand str by width
+ as the wcrtomb may return various bytes */
size_t strleng = str - *strptr;
char *newstr;
@@ -1098,7 +1110,8 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& *strptr + strsize - str <= MB_LEN_MAX)
{
/* We have to enlarge the buffer if the `a' or `m'
- flag was given. */
+ flag was given. And we may not expand str by
+ width as the wcrtomb may return various bytes */
size_t strleng = str - *strptr;
char *newstr;
@@ -1156,7 +1169,9 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& (char *) str == *strptr + strsize)
{
/* Enlarge the buffer. */
- str = (char *) realloc (*strptr, 2 * strsize);
+ size_t newsize = grow_to_fit (strsize, width);
+
+ str = (char *) realloc (*strptr, newsize);
if (str == NULL)
{
/* Can't allocate that much. Last-ditch
@@ -1188,7 +1203,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
{
*strptr = (char *) str;
str += strsize;
- strsize *= 2;
+ strsize = newsize;
}
}
}
@@ -1286,9 +1301,10 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
/* Enlarge the buffer. */
- wstr = (wchar_t *) realloc (*strptr,
- (2 * strsize)
- * sizeof (wchar_t));
+ size_t newsize = grow_to_fit (strsize, width);
+
+ wstr = (wchar_t *) realloc (
+ *strptr, newsize * sizeof (wchar_t));
if (wstr == NULL)
{
/* Can't allocate that much. Last-ditch
@@ -1322,7 +1338,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
{
*strptr = (char *) wstr;
wstr += strsize;
- strsize *= 2;
+ strsize = newsize;
}
}
}
@@ -1362,9 +1378,10 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
/* Enlarge the buffer. */
+ size_t newsize = grow_to_fit (strsize, width);
+
wstr = (wchar_t *) realloc (*strptr,
- (2 * strsize
- * sizeof (wchar_t)));
+ newsize * sizeof (wchar_t));
if (wstr == NULL)
{
/* Can't allocate that much. Last-ditch effort. */
@@ -1397,7 +1414,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
{
*strptr = (char *) wstr;
wstr += strsize;
- strsize *= 2;
+ strsize = newsize;
}
}
}
@@ -2754,9 +2771,10 @@ digits_extended_fail:
&& wstr == (wchar_t *) *strptr + strsize)
{
/* Enlarge the buffer. */
- wstr = (wchar_t *) realloc (*strptr,
- (2 * strsize)
- * sizeof (wchar_t));
+ size_t newsize = grow_to_fit (strsize, width);
+
+ wstr = (wchar_t *) realloc (
+ *strptr, newsize * sizeof (wchar_t));
if (wstr == NULL)
{
/* Can't allocate that much. Last-ditch
@@ -2790,7 +2808,7 @@ digits_extended_fail:
{
*strptr = (char *) wstr;
wstr += strsize;
- strsize *= 2;
+ strsize = newsize;
}
}
}
@@ -2839,9 +2857,10 @@ digits_extended_fail:
&& wstr == (wchar_t *) *strptr + strsize)
{
/* Enlarge the buffer. */
- wstr = (wchar_t *) realloc (*strptr,
- (2 * strsize
- * sizeof (wchar_t)));
+ size_t newsize = grow_to_fit (strsize, width);
+
+ wstr = (wchar_t *) realloc (
+ *strptr, newsize * sizeof (wchar_t));
if (wstr == NULL)
{
/* Can't allocate that much. Last-ditch
@@ -2875,7 +2894,7 @@ digits_extended_fail:
{
*strptr = (char *) wstr;
wstr += strsize;
- strsize *= 2;
+ strsize = newsize;
}
}
}
@@ -2983,7 +3002,9 @@ digits_extended_fail:
if ((flags & MALLOC)
&& *strptr + strsize - str <= MB_LEN_MAX)
{
- /* Enlarge the buffer. */
+ /* Enlarge the buffer. And we may not
+ expand str by width as the wcrtomb may
+ return various bytes */
size_t strleng = str - *strptr;
char *newstr;
@@ -3051,7 +3072,7 @@ digits_extended_fail:
&& (char *) str == *strptr + strsize)
{
/* Enlarge the buffer. */
- size_t newsize = 2 * strsize;
+ size_t newsize = grow_to_fit (strsize, width);
allocagain:
str = (char *) realloc (*strptr, newsize);
--
2.53.0
More information about the Libc-alpha
mailing list