From 044df5b2bba1bf1e34a27576bce587f469f84da0 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 18 Mar 2025 13:10:02 +0100 Subject: [PATCH] glib/gnulib/printf.c: Sync with gnulib Sync _g_gnulib_vsprintf() with lib/vszprintf.c and _g_gnulib_vsnprintf() with lib/vsnzprintf.c from gnulib, plus adjust the final guards to handle differing return signatures. Highlights: - Avoid a memory allocation if the result fits into the provided buffer. https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commit;h=f5200a50fa42fdaed40ecc67b27f41be328a6a01 - Don't assume vasnprintf returns EOVERFLOW if the size exceeds INT_MAX; do the check ourselves. https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commit;h=7e421d1cd6a8752aa527895c759a72a47203959a --- glib/gnulib/printf.c | 96 +++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/glib/gnulib/printf.c b/glib/gnulib/printf.c index c290b1542..cb47b8f93 100644 --- a/glib/gnulib/printf.c +++ b/glib/gnulib/printf.c @@ -23,12 +23,18 @@ */ #include -#include -#include + +#include +#include /* for INT_MAX */ +#include /* for uintptr_t, SIZE_MAX */ #include +#include +#include + +#include "printf.h" + #include "g-gnulib.h" #include "vasnprintf.h" -#include "printf.h" int _g_gnulib_printf (char const *format, ...) { @@ -98,39 +104,71 @@ int _g_gnulib_vfprintf (FILE *file, char const *format, va_list args) return rlength; } -int _g_gnulib_vsprintf (char *string, char const *format, va_list args) +int _g_gnulib_vsprintf (char *str, char const *format, va_list args) { - char *result; - size_t length; + char *output; + size_t len; + size_t lenbuf; - result = vasnprintf (NULL, &length, format, args); - if (result == NULL) + /* Set lenbuf = min (SIZE_MAX, - (uintptr_t) str - 1). */ + lenbuf = SIZE_MAX; + if (lenbuf >= ~ (uintptr_t) str) + lenbuf = ~ (uintptr_t) str; + + output = vasnprintf (str, &lenbuf, format, args); + len = lenbuf; + + if (!output) return -1; - memcpy (string, result, length + 1); - free (result); - - return length; -} - -int _g_gnulib_vsnprintf (char *string, size_t n, char const *format, va_list args) -{ - char *result; - size_t length; - - result = vasnprintf (NULL, &length, format, args); - if (result == NULL) - return -1; - - if (n > 0) + if (output != str) { - memcpy (string, result, MIN(length + 1, n)); - string[n - 1] = 0; + /* len is near SIZE_MAX. */ + free (output); + errno = ENOMEM; + return -1; } - free (result); - - return length; + if (len > INT_MAX) + { + errno = EOVERFLOW; + return -1; + } + + return len; +} + +int _g_gnulib_vsnprintf (char *str, size_t size, char const *format, va_list args) +{ + char *output; + size_t len; + size_t lenbuf = size; + + output = vasnprintf (str, &lenbuf, format, args); + len = lenbuf; + + if (!output) + return -1; + + if (output != str) + { + if (size) + { + size_t pruned_len = (len < size ? len : size - 1); + memcpy (str, output, pruned_len); + str[pruned_len] = '\0'; + } + + free (output); + } + + if (len > INT_MAX) + { + errno = EOVERFLOW; + return -1; + } + + return len; } int _g_gnulib_vasprintf (char **result, char const *format, va_list args)