As discussed in the thread starting at
<https://lists.gnu.org/archive/html/bug-gnulib/2024-04/msg00352.html>,
I'm adding *zs*printf modules, that are like the existing variants
without 'z', except that
- they support returning results of length > INT_MAX,
- thus the length type is changed to 'ptrdiff_t' from 'int',
- an attempt to return a result > PTRDIFF_MAX produces an error
ENOMEM (consistently with malloc, calloc) instead of EOVERFLOW.
For file stream and file descriptor based function, a similar thing
will be done, with 'off64_t' (instead of ptrdiff_t) replacing 'int'.
Here comes the first part of the string functions.
snprintf -> vzsnprintf
zsnprintf -> vasnprintf
sprintf -> vzsprintf
zsprintf -> vasnprintf
vasprintf -> vazsprintf
vazsprintf -> vasnprintf
vsnprintf -> vzsnprintf
vzsnprintf -> vasnprintf
vsprintf -> vzsprintf
vzsprintf -> vasnprintf
xvasprintf -> vazsprintf
Note that the last patch, in xvasprintf, also fixes a long-standing bug:
The code was examining errno after vasprintf failed, but vasprintf is
not documented to set errno upon failure.
2024-06-22 Bruno Haible <[email protected]>
xvasprintf: Guarantee a non-NULL result.
* lib/xvasprintf.h: Clarify the programmer's responsibilities.
(xasprintf, xvasprintf): Declare as returning non-NULL.
* lib/xvasprintf.c: Include <stdlib.h>.
(xstrcat): Allow results longer than INT_MAX characters. Upon size
overflow, invoke xalloc_die.
(xvasprintf): Call vazsprintf instead of vasprintf. When some other
error occurs, emit an error message and abort.
* m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
from gl_FUNC_STRERRORNAME_NP.
(gl_FUNC_STRERRORNAME_NP): Invoke it.
(gl_OPTIONAL_STRERRORNAME_NP): New macro.
* m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
* modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
(Depends-on): Add extensions, vazsprintf. Remove vasprintf.
* NEWS: Mention the change.
2024-06-22 Bruno Haible <[email protected]>
vasprintf: Make return convention consistent with other modules.
* lib/vasprintf.c: Include <stdint.h>.
(vasprintf): If the length is > PTRDIFF_MAX, fail with ENOMEM, not
EOVERFLOW.
* modules/vasprintf (Depends-on): Add stdint.
vazsprintf: New module.
* lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
* lib/vazsprintf.c: New file, based on lib/vasprintf.c.
* lib/azsprintf.c: New file, based on lib/asprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VAZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VAZSPRINTF.
* modules/vazsprintf: New file.
2024-06-22 Bruno Haible <[email protected]>
sprintf-posix: Use vzsprintf.
* lib/stdio.in.h (sprintf): Move specification to here.
* lib/sprintf.c: Don't include <stdlib.h>, vasnprintf.h. Include
<stdint.h>.
(sprintf): Implement based on vzsprintf.
* modules/sprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
zsprintf: New module.
* lib/stdio.in.h (zsprintf): New declaration, based on
lib/sprintf.c.
* lib/zsprintf.c: New file, based on lib/sprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_ZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_ZSPRINTF.
* modules/zsprintf: New file.
2024-06-22 Bruno Haible <[email protected]>
vsprintf-posix: Use vzsprintf.
* lib/stdio.in.h (vsprintf): Move specification to here.
* lib/vsprintf.c: Don't include <stdlib.h>, vasnprintf.h.
(SIZE_MAX): Remove macro.
(vsprintf): Implement based on vzsprintf.
* modules/vsprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
vzsprintf: New module.
* lib/stdio.in.h (vzsprintf): New declaration, based on
lib/vsprintf.c.
* lib/vzsprintf.c: New file, based on lib/vsprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VZSPRINTF.
* modules/vzsprintf: New file.
2024-06-22 Bruno Haible <[email protected]>
snprintf: Use vzsnprintf.
* lib/stdio.in.h (snprintf): Move specification to here.
* lib/snprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
Include <stdint.h>.
(snprintf): Implement based on vzsnprintf.
* modules/snprintf (Depends-on): Add stdint, vzsnprintf. Remove
vasnprintf.
zsnprintf: New module.
* lib/stdio.in.h (zsnprintf): New declaration, based on
lib/snprintf.c.
* lib/zsnprintf.c: New file, based on lib/snprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_ZSNPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_ZSNPRINTF.
* modules/zsnprintf: New file.
2024-06-22 Bruno Haible <[email protected]>
vsnprintf: Use vzsnprintf.
* lib/stdio.in.h (vsnprintf): Move specification to here.
* lib/vsnprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
Include <stdint.h>.
(vsnprintf): Implement based on vzsnprintf.
* modules/vsnprintf (Depends-on): Add stdint, vzsnprintf. Remove
vasnprintf.
vzsnprintf: New module.
* lib/stdio.in.h (vzsnprintf): New declaration, based on
lib/vsnprintf.c.
* lib/vzsnprintf.c: New file, based on lib/vsnprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VZSNPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VZSNPRINTF.
* modules/vzsnprintf: New file.
>From 599f3ed9963c52be0122b6a5f01b33a13cdcbdda Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:14:41 +0200
Subject: [PATCH 01/11] vzsnprintf: New module.
* lib/stdio.in.h (vzsnprintf): New declaration, based on
lib/vsnprintf.c.
* lib/vzsnprintf.c: New file, based on lib/vsnprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VZSNPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VZSNPRINTF.
* modules/vzsnprintf: New file.
---
ChangeLog | 11 ++++++++
lib/stdio.in.h | 19 ++++++++++++++
lib/vzsnprintf.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
m4/stdio_h.m4 | 3 ++-
modules/stdio | 1 +
modules/vzsnprintf | 27 +++++++++++++++++++
6 files changed, 125 insertions(+), 1 deletion(-)
create mode 100644 lib/vzsnprintf.c
create mode 100644 modules/vzsnprintf
diff --git a/ChangeLog b/ChangeLog
index 8e82912063..60ed445021 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ vzsnprintf: New module.
+ * lib/stdio.in.h (vzsnprintf): New declaration, based on
+ lib/vsnprintf.c.
+ * lib/vzsnprintf.c: New file, based on lib/vsnprintf.c.
+ * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_VZSNPRINTF.
+ * modules/stdio (Makefile.am): Substitute GNULIB_VZSNPRINTF.
+ * modules/vzsnprintf: New file.
+
2024-06-20 Bruno Haible <[email protected]>
test-framework-sh: Fix side effect on dfa tests (regression 2024-06-11).
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 1c0c9661bf..d8d27a56c5 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1769,6 +1769,25 @@ _GL_CXXALIASWARN (vscanf);
# endif
#endif
+#if @GNULIB_VZSNPRINTF@
+/* Prints formatted output to string STR. Similar to sprintf, but the
+ additional parameter SIZE limits how much is written into STR.
+ STR may be NULL, in which case nothing will be written.
+ Returns the string length of the formatted string (which may be larger
+ than SIZE). Upon failure, returns -1 with errno set.
+ Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+ Therefore, if the format string is valid and does not use %ls/%lc
+ directives nor widths, the only possible failure code is ENOMEM. */
+_GL_FUNCDECL_SYS (vzsnprintf, ptrdiff_t,
+ (char *restrict str, size_t size,
+ const char *restrict format, va_list args)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)
+ _GL_ARG_NONNULL ((3)));
+_GL_CXXALIAS_SYS (vzsnprintf, ptrdiff_t,
+ (char *restrict str, size_t size,
+ const char *restrict format, va_list args));
+#endif
+
#if @GNULIB_VSNPRINTF@
# if @REPLACE_VSNPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/vzsnprintf.c b/lib/vzsnprintf.c
new file mode 100644
index 0000000000..96e240bdb7
--- /dev/null
+++ b/lib/vzsnprintf.c
@@ -0,0 +1,65 @@
+/* Formatted output to strings.
+ Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
+ Written by Simon Josefsson and Yoann Vandoorselaere <[email protected]>.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+vzsnprintf (char *str, size_t size, const char *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 > PTRDIFF_MAX)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 8eb5816ad7..9c631f172f 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
# stdio_h.m4
-# serial 63
+# serial 64
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -186,6 +186,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
dnl Support Microsoft deprecated alias function names by default.
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/modules/stdio b/modules/stdio
index 45ae9824ed..63ea9a908e 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -121,6 +121,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
-e 's/@''GNULIB_VPRINTF_POSIX''@/$(GNULIB_VPRINTF_POSIX)/g' \
-e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
-e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
+ -e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
-e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
-e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
-e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
diff --git a/modules/vzsnprintf b/modules/vzsnprintf
new file mode 100644
index 0000000000..853d88210d
--- /dev/null
+++ b/modules/vzsnprintf
@@ -0,0 +1,27 @@
+Description:
+vzsnprintf() function: print formatted output from an stdarg argument list
+to a fixed length string (without INT_MAX limitation)
+
+Files:
+lib/vzsnprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([vzsnprintf])
+
+Makefile.am:
+lib_SOURCES += vzsnprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--
2.34.1
>From 7a34ce4ce5652715bd9dc9d2b3a82a2ea97ed4bc Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:14:52 +0200
Subject: [PATCH 02/11] vsnprintf: Use vzsnprintf.
* lib/stdio.in.h (vsnprintf): Move specification to here.
* lib/vsnprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
Include <stdint.h>.
(vsnprintf): Implement based on vzsnprintf.
* modules/vsnprintf (Depends-on): Add stdint, vzsnprintf. Remove
vasnprintf.
---
ChangeLog | 8 ++++++++
lib/stdio.in.h | 5 +++++
lib/vsnprintf.c | 39 ++++++---------------------------------
modules/vsnprintf | 5 +++--
4 files changed, 22 insertions(+), 35 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 60ed445021..28833003fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2024-06-22 Bruno Haible <[email protected]>
+ vsnprintf: Use vzsnprintf.
+ * lib/stdio.in.h (vsnprintf): Move specification to here.
+ * lib/vsnprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
+ Include <stdint.h>.
+ (vsnprintf): Implement based on vzsnprintf.
+ * modules/vsnprintf (Depends-on): Add stdint, vzsnprintf. Remove
+ vasnprintf.
+
vzsnprintf: New module.
* lib/stdio.in.h (vzsnprintf): New declaration, based on
lib/vsnprintf.c.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index d8d27a56c5..8d6cd21fd5 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1789,6 +1789,11 @@ _GL_CXXALIAS_SYS (vzsnprintf, ptrdiff_t,
#endif
#if @GNULIB_VSNPRINTF@
+/* Prints formatted output to string STR. Similar to vsprintf, but the
+ additional parameter SIZE limits how much is written into STR.
+ STR may be NULL, in which case nothing will be written.
+ Returns the string length of the formatted string (which may be larger
+ than SIZE). Upon failure, returns a negative value. */
# if @REPLACE_VSNPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# define vsnprintf rpl_vsnprintf
diff --git a/lib/vsnprintf.c b/lib/vsnprintf.c
index e6676a1ffa..1954dcea26 100644
--- a/lib/vsnprintf.c
+++ b/lib/vsnprintf.c
@@ -1,6 +1,5 @@
/* Formatted output to strings.
Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
- Written by Simon Josefsson and Yoann Vandoorselaere <[email protected]>.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -25,46 +24,20 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <stdint.h>
-#include "vasnprintf.h"
-
-/* Print formatted output to string STR. Similar to vsprintf, but
- additional length SIZE limit how much is written into STR. Returns
- string length of formatted string (which may be larger than SIZE).
- STR may be NULL, in which case nothing will be written. On error,
- return a negative value. */
int
vsnprintf (char *str, size_t size, const char *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);
- }
+ ptrdiff_t ret = vzsnprintf (str, size, format, args);
- if (len > INT_MAX)
+#if PTRDIFF_MAX > INT_MAX
+ if (ret > INT_MAX)
{
errno = EOVERFLOW;
return -1;
}
+#endif
- return len;
+ return ret;
}
diff --git a/modules/vsnprintf b/modules/vsnprintf
index 053b10c32a..de2a86e285 100644
--- a/modules/vsnprintf
+++ b/modules/vsnprintf
@@ -9,8 +9,9 @@ m4/printf.m4
Depends-on:
stdio
-vasnprintf [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
errno [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
+stdint [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
+vzsnprintf [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
configure.ac:
gl_FUNC_VSNPRINTF
@@ -25,4 +26,4 @@ License:
LGPLv2+
Maintainer:
-Yoann Vandoorselaere
+all
--
2.34.1
>From c85fa7f8a128437cca30f396df8392af1c1b7632 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:15:32 +0200
Subject: [PATCH 03/11] zsnprintf: New module.
* lib/stdio.in.h (zsnprintf): New declaration, based on
lib/snprintf.c.
* lib/zsnprintf.c: New file, based on lib/snprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_ZSNPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_ZSNPRINTF.
* modules/zsnprintf: New file.
---
ChangeLog | 11 ++++++++
lib/stdio.in.h | 19 ++++++++++++++
lib/zsnprintf.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
m4/stdio_h.m4 | 3 ++-
modules/stdio | 1 +
modules/zsnprintf | 27 +++++++++++++++++++
6 files changed, 126 insertions(+), 1 deletion(-)
create mode 100644 lib/zsnprintf.c
create mode 100644 modules/zsnprintf
diff --git a/ChangeLog b/ChangeLog
index 28833003fb..458561b9fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ zsnprintf: New module.
+ * lib/stdio.in.h (zsnprintf): New declaration, based on
+ lib/snprintf.c.
+ * lib/zsnprintf.c: New file, based on lib/snprintf.c.
+ * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_ZSNPRINTF.
+ * modules/stdio (Makefile.am): Substitute GNULIB_ZSNPRINTF.
+ * modules/zsnprintf: New file.
+
2024-06-22 Bruno Haible <[email protected]>
vsnprintf: Use vzsnprintf.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 8d6cd21fd5..4a942a92ed 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1433,6 +1433,25 @@ _GL_CXXALIASWARN (scanf);
# endif
#endif
+#if @GNULIB_ZSNPRINTF@
+/* Prints formatted output to string STR. Similar to sprintf, but the
+ additional parameter SIZE limits how much is written into STR.
+ STR may be NULL, in which case nothing will be written.
+ Returns the string length of the formatted string (which may be larger
+ than SIZE). Upon failure, returns -1 with errno set.
+ Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+ Therefore, if the format string is valid and does not use %ls/%lc
+ directives nor widths, the only possible failure code is ENOMEM. */
+_GL_FUNCDECL_SYS (zsnprintf, ptrdiff_t,
+ (char *restrict str, size_t size,
+ const char *restrict format, ...)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)
+ _GL_ARG_NONNULL ((3)));
+_GL_CXXALIAS_SYS (zsnprintf, ptrdiff_t,
+ (char *restrict str, size_t size,
+ const char *restrict format, ...));
+#endif
+
#if @GNULIB_SNPRINTF@
# if @REPLACE_SNPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/zsnprintf.c b/lib/zsnprintf.c
new file mode 100644
index 0000000000..894631d16a
--- /dev/null
+++ b/lib/zsnprintf.c
@@ -0,0 +1,66 @@
+/* Formatted output to strings.
+ Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
+ Written by Simon Josefsson and Paul Eggert.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+zsnprintf (char *str, size_t size, const char *format, ...)
+{
+ char *output;
+ size_t len;
+ size_t lenbuf = size;
+ va_list args;
+
+ va_start (args, format);
+ output = vasnprintf (str, &lenbuf, format, args);
+ len = lenbuf;
+ va_end (args);
+
+ 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 > PTRDIFF_MAX)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 9c631f172f..28d1c96c74 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
# stdio_h.m4
-# serial 64
+# serial 65
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -187,6 +187,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF])
dnl Support Microsoft deprecated alias function names by default.
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/modules/stdio b/modules/stdio
index 63ea9a908e..9e676681dd 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -122,6 +122,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
-e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
-e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
-e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
+ -e 's/@''GNULIB_ZSNPRINTF''@/$(GNULIB_ZSNPRINTF)/g' \
-e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
-e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
-e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
diff --git a/modules/zsnprintf b/modules/zsnprintf
new file mode 100644
index 0000000000..40fd329e0e
--- /dev/null
+++ b/modules/zsnprintf
@@ -0,0 +1,27 @@
+Description:
+zsnprintf() function: print formatted output to a fixed length string
+(without INT_MAX limitation)
+
+Files:
+lib/zsnprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([zsnprintf])
+
+Makefile.am:
+lib_SOURCES += zsnprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--
2.34.1
>From fdcddac143b28818efadd52f2f3c840778eda0bb Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:15:38 +0200
Subject: [PATCH 04/11] snprintf: Use vzsnprintf.
* lib/stdio.in.h (snprintf): Move specification to here.
* lib/snprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
Include <stdint.h>.
(snprintf): Implement based on vzsnprintf.
* modules/snprintf (Depends-on): Add stdint, vzsnprintf. Remove
vasnprintf.
---
ChangeLog | 8 ++++++++
lib/snprintf.c | 39 +++++++--------------------------------
lib/stdio.in.h | 5 +++++
modules/snprintf | 5 +++--
4 files changed, 23 insertions(+), 34 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 458561b9fe..68677a44ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2024-06-22 Bruno Haible <[email protected]>
+ snprintf: Use vzsnprintf.
+ * lib/stdio.in.h (snprintf): Move specification to here.
+ * lib/snprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
+ Include <stdint.h>.
+ (snprintf): Implement based on vzsnprintf.
+ * modules/snprintf (Depends-on): Add stdint, vzsnprintf. Remove
+ vasnprintf.
+
zsnprintf: New module.
* lib/stdio.in.h (zsnprintf): New declaration, based on
lib/snprintf.c.
diff --git a/lib/snprintf.c b/lib/snprintf.c
index c1b93562ec..80f69225ac 100644
--- a/lib/snprintf.c
+++ b/lib/snprintf.c
@@ -1,6 +1,5 @@
/* Formatted output to strings.
Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
- Written by Simon Josefsson and Paul Eggert.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -23,49 +22,25 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <stdint.h>
-#include "vasnprintf.h"
-
-/* Print formatted output to string STR. Similar to sprintf, but
- additional length SIZE limit how much is written into STR. Returns
- string length of formatted string (which may be larger than SIZE).
- STR may be NULL, in which case nothing will be written. On error,
- return a negative value. */
int
snprintf (char *str, size_t size, const char *format, ...)
{
- char *output;
- size_t len;
- size_t lenbuf = size;
va_list args;
+ ptrdiff_t ret;
va_start (args, format);
- output = vasnprintf (str, &lenbuf, format, args);
- len = lenbuf;
+ ret = vzsnprintf (str, size, format, args);
va_end (args);
- 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 (INT_MAX < len)
+#if PTRDIFF_MAX > INT_MAX
+ if (ret > INT_MAX)
{
errno = EOVERFLOW;
return -1;
}
+#endif
- return len;
+ return ret;
}
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 4a942a92ed..d0479c10ae 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1453,6 +1453,11 @@ _GL_CXXALIAS_SYS (zsnprintf, ptrdiff_t,
#endif
#if @GNULIB_SNPRINTF@
+/* Prints formatted output to string STR. Similar to sprintf, but the
+ additional parameter SIZE limits how much is written into STR.
+ STR may be NULL, in which case nothing will be written.
+ Returns the string length of the formatted string (which may be larger
+ than SIZE). Upon failure, returns a negative value. */
# if @REPLACE_SNPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# define snprintf rpl_snprintf
diff --git a/modules/snprintf b/modules/snprintf
index 102d629706..cd4eb6b2c4 100644
--- a/modules/snprintf
+++ b/modules/snprintf
@@ -8,8 +8,9 @@ m4/printf.m4
Depends-on:
stdio
-vasnprintf [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
errno [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
+stdint [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
+vzsnprintf [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
configure.ac:
gl_FUNC_SNPRINTF
@@ -25,4 +26,4 @@ License:
LGPLv2+
Maintainer:
-Simon Josefsson, Paul Eggert
+all
--
2.34.1
>From 058db602ad919d2c4c46264a988b94ed6c1c2b05 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:16:00 +0200
Subject: [PATCH 05/11] vzsprintf: New module.
* lib/stdio.in.h (vzsprintf): New declaration, based on
lib/vsprintf.c.
* lib/vzsprintf.c: New file, based on lib/vsprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VZSPRINTF.
* modules/vzsprintf: New file.
---
ChangeLog | 11 ++++++++
lib/stdio.in.h | 17 +++++++++++++
lib/vzsprintf.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++
m4/stdio_h.m4 | 3 ++-
modules/stdio | 1 +
modules/vzsprintf | 27 ++++++++++++++++++++
6 files changed, 122 insertions(+), 1 deletion(-)
create mode 100644 lib/vzsprintf.c
create mode 100644 modules/vzsprintf
diff --git a/ChangeLog b/ChangeLog
index 68677a44ad..470192143c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ vzsprintf: New module.
+ * lib/stdio.in.h (vzsprintf): New declaration, based on
+ lib/vsprintf.c.
+ * lib/vzsprintf.c: New file, based on lib/vsprintf.c.
+ * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_VZSPRINTF.
+ * modules/stdio (Makefile.am): Substitute GNULIB_VZSPRINTF.
+ * modules/vzsprintf: New file.
+
2024-06-22 Bruno Haible <[email protected]>
snprintf: Use vzsnprintf.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index d0479c10ae..2d7e20e3d1 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1854,6 +1854,23 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - "
# endif
#endif
+#if @GNULIB_VZSPRINTF@
+/* Prints formatted output to string STR.
+ Returns the string length of the formatted string. Upon failure,
+ returns -1 with errno set.
+ Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+ Therefore, if the format string is valid and does not use %ls/%lc
+ directives nor widths, the only possible failure code is ENOMEM. */
+_GL_FUNCDECL_SYS (vzsprintf, ptrdiff_t,
+ (char *restrict str,
+ const char *restrict format, va_list args)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (vzsprintf, ptrdiff_t,
+ (char *restrict str,
+ const char *restrict format, va_list args));
+#endif
+
#if @GNULIB_VSPRINTF_POSIX@
# if @REPLACE_VSPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/vzsprintf.c b/lib/vzsprintf.c
new file mode 100644
index 0000000000..549543070c
--- /dev/null
+++ b/lib/vzsprintf.c
@@ -0,0 +1,64 @@
+/* Formatted output to strings.
+ Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+vzsprintf (char *str, const char *format, va_list args)
+{
+ char *output;
+ size_t len;
+ size_t lenbuf;
+
+ /* 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;
+
+ if (output != str)
+ {
+ /* len is near SIZE_MAX. */
+ free (output);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (len > PTRDIFF_MAX)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 28d1c96c74..f549ca4810 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
# stdio_h.m4
-# serial 65
+# serial 66
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -187,6 +187,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF])
dnl Support Microsoft deprecated alias function names by default.
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
diff --git a/modules/stdio b/modules/stdio
index 9e676681dd..4e41ae13e8 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -122,6 +122,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
-e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
-e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
-e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
+ -e 's/@''GNULIB_VZSPRINTF''@/$(GNULIB_VZSPRINTF)/g' \
-e 's/@''GNULIB_ZSNPRINTF''@/$(GNULIB_ZSNPRINTF)/g' \
-e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
-e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
diff --git a/modules/vzsprintf b/modules/vzsprintf
new file mode 100644
index 0000000000..6564c020f1
--- /dev/null
+++ b/modules/vzsprintf
@@ -0,0 +1,27 @@
+Description:
+vzsprintf() function: print formatted output from an stdarg argument list
+to a string (without INT_MAX limitation)
+
+Files:
+lib/vzsprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([vzsprintf])
+
+Makefile.am:
+lib_SOURCES += vzsprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPL
+
+Maintainer:
+all
--
2.34.1
>From 587920f982d6c3e777ee1f98ce36b403ee85c565 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:16:06 +0200
Subject: [PATCH 06/11] vsprintf-posix: Use vzsprintf.
* lib/stdio.in.h (vsprintf): Move specification to here.
* lib/vsprintf.c: Don't include <stdlib.h>, vasnprintf.h.
(SIZE_MAX): Remove macro.
(vsprintf): Implement based on vzsprintf.
* modules/vsprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
---
ChangeLog | 7 +++++++
lib/stdio.in.h | 3 +++
lib/vsprintf.c | 44 +++++-------------------------------------
modules/vsprintf-posix | 2 +-
4 files changed, 16 insertions(+), 40 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 470192143c..c823d86fbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2024-06-22 Bruno Haible <[email protected]>
+ vsprintf-posix: Use vzsprintf.
+ * lib/stdio.in.h (vsprintf): Move specification to here.
+ * lib/vsprintf.c: Don't include <stdlib.h>, vasnprintf.h.
+ (SIZE_MAX): Remove macro.
+ (vsprintf): Implement based on vzsprintf.
+ * modules/vsprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
+
vzsprintf: New module.
* lib/stdio.in.h (vzsprintf): New declaration, based on
lib/vsprintf.c.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 2d7e20e3d1..858ab47736 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1872,6 +1872,9 @@ _GL_CXXALIAS_SYS (vzsprintf, ptrdiff_t,
#endif
#if @GNULIB_VSPRINTF_POSIX@
+/* Prints formatted output to string STR.
+ Returns the string length of the formatted string. Upon failure,
+ returns a negative value. */
# if @REPLACE_VSPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# define vsprintf rpl_vsprintf
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 181bc9814f..065ed74222 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -25,53 +25,19 @@
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
-#include <stdlib.h>
-#include "vasnprintf.h"
-
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-
-/* Print formatted output to string STR.
- Return string length of formatted string. On error, return a negative
- value. */
int
vsprintf (char *str, const char *format, va_list args)
{
- char *output;
- size_t len;
- size_t lenbuf;
-
- /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
- than INT_MAX (if that fits into a 'size_t' at all).
- Also note that glibc's iconv fails with E2BIG when we pass a length that
- is so large that str + lenbuf wraps around, i.e.
- (uintptr_t) (str + lenbuf) < (uintptr_t) str.
- Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1). */
- lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
- if (lenbuf > ~ (uintptr_t) str)
- lenbuf = ~ (uintptr_t) str;
-
- output = vasnprintf (str, &lenbuf, format, args);
- len = lenbuf;
-
- if (!output)
- return -1;
+ ptrdiff_t ret = vzsprintf (str, format, args);
- if (output != str)
- {
- /* len is near SIZE_MAX. */
- free (output);
- errno = EOVERFLOW;
- return -1;
- }
-
- if (len > INT_MAX)
+#if PTRDIFF_MAX > INT_MAX
+ if (ret > INT_MAX)
{
errno = EOVERFLOW;
return -1;
}
+#endif
- return len;
+ return ret;
}
diff --git a/modules/vsprintf-posix b/modules/vsprintf-posix
index a3ef9998ed..2bbb36055b 100644
--- a/modules/vsprintf-posix
+++ b/modules/vsprintf-posix
@@ -18,7 +18,7 @@ stdio
nocrash
printf-safe
multiarch
-vasnprintf [test $REPLACE_VSPRINTF = 1]
+vzsprintf [test $REPLACE_VSPRINTF = 1]
isnand-nolibm [test $REPLACE_VSPRINTF = 1]
isnanl-nolibm [test $REPLACE_VSPRINTF = 1]
frexp-nolibm [test $REPLACE_VSPRINTF = 1]
--
2.34.1
>From f89f459b49563a6dfb82b5deac70d87086a390f3 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:16:24 +0200
Subject: [PATCH 07/11] zsprintf: New module.
* lib/stdio.in.h (zsprintf): New declaration, based on
lib/sprintf.c.
* lib/zsprintf.c: New file, based on lib/sprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_ZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_ZSPRINTF.
* modules/zsprintf: New file.
---
ChangeLog | 11 ++++++++
lib/stdio.in.h | 17 ++++++++++++
lib/zsprintf.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
m4/stdio_h.m4 | 3 ++-
modules/stdio | 1 +
modules/zsprintf | 27 +++++++++++++++++++
6 files changed, 125 insertions(+), 1 deletion(-)
create mode 100644 lib/zsprintf.c
create mode 100644 modules/zsprintf
diff --git a/ChangeLog b/ChangeLog
index c823d86fbc..96dc1dff2c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ zsprintf: New module.
+ * lib/stdio.in.h (zsprintf): New declaration, based on
+ lib/sprintf.c.
+ * lib/zsprintf.c: New file, based on lib/sprintf.c.
+ * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_ZSPRINTF.
+ * modules/stdio (Makefile.am): Substitute GNULIB_ZSPRINTF.
+ * modules/zsprintf: New file.
+
2024-06-22 Bruno Haible <[email protected]>
vsprintf-posix: Use vzsprintf.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 858ab47736..17c662f45a 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1494,6 +1494,23 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - "
# endif
#endif
+#if @GNULIB_ZSPRINTF@
+/* Prints formatted output to string STR.
+ Returns the string length of the formatted string. Upon failure,
+ returns -1 with errno set.
+ Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+ Therefore, if the format string is valid and does not use %ls/%lc
+ directives nor widths, the only possible failure code is ENOMEM. */
+_GL_FUNCDECL_SYS (zsprintf, ptrdiff_t,
+ (char *restrict str,
+ const char *restrict format, ...)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (zsprintf, ptrdiff_t,
+ (char *restrict str,
+ const char *restrict format, ...));
+#endif
+
/* Some people would argue that all sprintf uses should be warned about
(for example, OpenBSD issues a link warning for it),
since it can cause security holes due to buffer overruns.
diff --git a/lib/zsprintf.c b/lib/zsprintf.c
new file mode 100644
index 0000000000..f004ed7238
--- /dev/null
+++ b/lib/zsprintf.c
@@ -0,0 +1,67 @@
+/* Formatted output to strings.
+ Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+zsprintf (char *str, const char *format, ...)
+{
+ char *output;
+ size_t len;
+ size_t lenbuf;
+ va_list args;
+
+ /* Set lenbuf = min (SIZE_MAX, - (uintptr_t) str - 1). */
+ lenbuf = SIZE_MAX;
+ if (lenbuf >= ~ (uintptr_t) str)
+ lenbuf = ~ (uintptr_t) str;
+
+ va_start (args, format);
+ output = vasnprintf (str, &lenbuf, format, args);
+ len = lenbuf;
+ va_end (args);
+
+ if (!output)
+ return -1;
+
+ if (output != str)
+ {
+ /* len is near SIZE_MAX. */
+ free (output);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (len > PTRDIFF_MAX)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index f549ca4810..69d4b88b4b 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
# stdio_h.m4
-# serial 66
+# serial 67
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -189,6 +189,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSPRINTF])
dnl Support Microsoft deprecated alias function names by default.
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/modules/stdio b/modules/stdio
index 4e41ae13e8..29ed8e0bfa 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -124,6 +124,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
-e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
-e 's/@''GNULIB_VZSPRINTF''@/$(GNULIB_VZSPRINTF)/g' \
-e 's/@''GNULIB_ZSNPRINTF''@/$(GNULIB_ZSNPRINTF)/g' \
+ -e 's/@''GNULIB_ZSPRINTF''@/$(GNULIB_ZSPRINTF)/g' \
-e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
-e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
-e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
diff --git a/modules/zsprintf b/modules/zsprintf
new file mode 100644
index 0000000000..7da8687ea4
--- /dev/null
+++ b/modules/zsprintf
@@ -0,0 +1,27 @@
+Description:
+zsprintf() function: print formatted output to a string (without INT_MAX
+limitation)
+
+Files:
+lib/zsprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([zsprintf])
+
+Makefile.am:
+lib_SOURCES += zsprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPL
+
+Maintainer:
+all
--
2.34.1
>From 8a31e0648af657347c4ef3b8d823c464eced4b5a Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:16:30 +0200
Subject: [PATCH 08/11] sprintf-posix: Use vzsprintf.
* lib/stdio.in.h (sprintf): Move specification to here.
* lib/sprintf.c: Don't include <stdlib.h>, vasnprintf.h. Include
<stdint.h>.
(sprintf): Implement based on vzsprintf.
* modules/sprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
---
ChangeLog | 7 +++++++
lib/sprintf.c | 44 ++++++-------------------------------------
lib/stdio.in.h | 3 +++
modules/sprintf-posix | 2 +-
4 files changed, 17 insertions(+), 39 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 96dc1dff2c..76c8dc4dce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2024-06-22 Bruno Haible <[email protected]>
+ sprintf-posix: Use vzsprintf.
+ * lib/stdio.in.h (sprintf): Move specification to here.
+ * lib/sprintf.c: Don't include <stdlib.h>, vasnprintf.h. Include
+ <stdint.h>.
+ (sprintf): Implement based on vzsprintf.
+ * modules/sprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
+
zsprintf: New module.
* lib/stdio.in.h (zsprintf): New declaration, based on
lib/sprintf.c.
diff --git a/lib/sprintf.c b/lib/sprintf.c
index ba0108d08c..d781b8c7b5 100644
--- a/lib/sprintf.c
+++ b/lib/sprintf.c
@@ -25,56 +25,24 @@
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
-#include <stdlib.h>
-#include "vasnprintf.h"
-
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-
-/* Print formatted output to string STR.
- Return string length of formatted string. On error, return a negative
- value. */
int
sprintf (char *str, const char *format, ...)
{
- char *output;
- size_t len;
- size_t lenbuf;
va_list args;
-
- /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
- than INT_MAX (if that fits into a 'size_t' at all).
- Also note that glibc's iconv fails with E2BIG when we pass a length that
- is so large that str + lenbuf wraps around, i.e.
- (uintptr_t) (str + lenbuf) < (uintptr_t) str.
- Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1). */
- lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
- if (lenbuf > ~ (uintptr_t) str)
- lenbuf = ~ (uintptr_t) str;
+ ptrdiff_t ret;
va_start (args, format);
- output = vasnprintf (str, &lenbuf, format, args);
- len = lenbuf;
+ ret = vzsprintf (str, format, args);
va_end (args);
- if (!output)
- return -1;
-
- if (output != str)
- {
- /* len is near SIZE_MAX. */
- free (output);
- errno = EOVERFLOW;
- return -1;
- }
-
- if (len > INT_MAX)
+#if PTRDIFF_MAX > INT_MAX
+ if (ret > INT_MAX)
{
errno = EOVERFLOW;
return -1;
}
+#endif
- return len;
+ return ret;
}
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 17c662f45a..5a70aa20ba 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1521,6 +1521,9 @@ _GL_CXXALIAS_SYS (zsprintf, ptrdiff_t,
GNULIB_POSIXCHECK is defined. */
#if @GNULIB_SPRINTF_POSIX@
+/* Prints formatted output to string STR.
+ Returns the string length of the formatted string. Upon failure,
+ returns a negative value. */
# if @REPLACE_SPRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# define sprintf rpl_sprintf
diff --git a/modules/sprintf-posix b/modules/sprintf-posix
index 589ad104ce..a1eb6127ad 100644
--- a/modules/sprintf-posix
+++ b/modules/sprintf-posix
@@ -18,7 +18,7 @@ stdio
nocrash
printf-safe
multiarch
-vasnprintf [test $REPLACE_SPRINTF = 1]
+vzsprintf [test $REPLACE_SPRINTF = 1]
isnand-nolibm [test $REPLACE_SPRINTF = 1]
isnanl-nolibm [test $REPLACE_SPRINTF = 1]
frexp-nolibm [test $REPLACE_SPRINTF = 1]
--
2.34.1
>From cf5774e94a80589b8fd92fd7166dea82c925cfcc Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:17:02 +0200
Subject: [PATCH 09/11] vazsprintf: New module.
* lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
* lib/vazsprintf.c: New file, based on lib/vasprintf.c.
* lib/azsprintf.c: New file, based on lib/asprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VAZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VAZSPRINTF.
* modules/vazsprintf: New file.
---
ChangeLog | 11 +++++++++++
lib/azsprintf.c | 34 ++++++++++++++++++++++++++++++++++
lib/stdio.in.h | 23 +++++++++++++++++++++++
lib/vazsprintf.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
m4/stdio_h.m4 | 3 ++-
modules/stdio | 1 +
modules/vazsprintf | 30 ++++++++++++++++++++++++++++++
7 files changed, 147 insertions(+), 1 deletion(-)
create mode 100644 lib/azsprintf.c
create mode 100644 lib/vazsprintf.c
create mode 100644 modules/vazsprintf
diff --git a/ChangeLog b/ChangeLog
index 76c8dc4dce..b38ebee8a3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ vazsprintf: New module.
+ * lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
+ * lib/vazsprintf.c: New file, based on lib/vasprintf.c.
+ * lib/azsprintf.c: New file, based on lib/asprintf.c.
+ * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_VAZSPRINTF.
+ * modules/stdio (Makefile.am): Substitute GNULIB_VAZSPRINTF.
+ * modules/vazsprintf: New file.
+
2024-06-22 Bruno Haible <[email protected]>
sprintf-posix: Use vzsprintf.
diff --git a/lib/azsprintf.c b/lib/azsprintf.c
new file mode 100644
index 0000000000..9489854cb9
--- /dev/null
+++ b/lib/azsprintf.c
@@ -0,0 +1,34 @@
+/* Formatted output to strings.
+ Copyright (C) 1999-2024 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <stdio.h>
+
+#include <stdarg.h>
+
+ptrdiff_t
+azsprintf (char **resultp, const char *format, ...)
+{
+ va_list args;
+ ptrdiff_t result;
+
+ va_start (args, format);
+ result = vazsprintf (resultp, format, args);
+ va_end (args);
+ return result;
+}
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 5a70aa20ba..4844ea1ebf 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1603,6 +1603,29 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - "
# endif
#endif
+#if @GNULIB_VAZSPRINTF@
+/* Prints formatted output to a string dynamically allocated with malloc().
+ If the memory allocation succeeds, it stores the address of the string in
+ *RESULT and returns the number of resulting bytes, excluding the trailing
+ NUL. Upon memory allocation error, or some other error, it returns -1
+ with errno set.
+ Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+ Therefore, if the format string is valid and does not use %ls/%lc
+ directives nor widths, the only possible failure code is ENOMEM. */
+_GL_FUNCDECL_SYS (azsprintf, ptrdiff_t,
+ (char **result, const char *format, ...)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (azsprintf, ptrdiff_t,
+ (char **result, const char *format, ...));
+_GL_FUNCDECL_SYS (vazsprintf, ptrdiff_t,
+ (char **result, const char *format, va_list args)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (vazsprintf, ptrdiff_t,
+ (char **result, const char *format, va_list args));
+#endif
+
#if @GNULIB_VASPRINTF@
/* Write formatted output to a string dynamically allocated with malloc().
If the memory allocation succeeds, store the address of the string in
diff --git a/lib/vazsprintf.c b/lib/vazsprintf.c
new file mode 100644
index 0000000000..73002a17d5
--- /dev/null
+++ b/lib/vazsprintf.c
@@ -0,0 +1,46 @@
+/* Formatted output to strings.
+ Copyright (C) 1999-2024 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+vazsprintf (char **resultp, const char *format, va_list args)
+{
+ size_t length;
+ char *result = vasnprintf (NULL, &length, format, args);
+ if (result == NULL)
+ return -1;
+
+ if (length > PTRDIFF_MAX)
+ {
+ free (result);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ *resultp = result;
+ /* Return the number of resulting bytes, excluding the trailing NUL. */
+ return length;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 69d4b88b4b..aa06d77027 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
# stdio_h.m4
-# serial 67
+# serial 68
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -177,6 +177,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VAZSPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF])
diff --git a/modules/stdio b/modules/stdio
index 29ed8e0bfa..b0cf4ea207 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -112,6 +112,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
-e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GNULIB_STDIO_H_SIGPIPE)/g' \
-e 's/@''GNULIB_TMPFILE''@/$(GNULIB_TMPFILE)/g' \
-e 's/@''GNULIB_VASPRINTF''@/$(GNULIB_VASPRINTF)/g' \
+ -e 's/@''GNULIB_VAZSPRINTF''@/$(GNULIB_VAZSPRINTF)/g' \
-e 's/@''GNULIB_VDPRINTF''@/$(GNULIB_VDPRINTF)/g' \
-e 's/@''GNULIB_VFPRINTF''@/$(GNULIB_VFPRINTF)/g' \
-e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GNULIB_VFPRINTF_POSIX)/g' \
diff --git a/modules/vazsprintf b/modules/vazsprintf
new file mode 100644
index 0000000000..787825aa71
--- /dev/null
+++ b/modules/vazsprintf
@@ -0,0 +1,30 @@
+Description:
+vsprintf (without INT_MAX limitation) with automatic memory allocation
+
+Files:
+lib/vazsprintf.c
+lib/azsprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([vazsprintf])
+m4_ifdef([AM_XGETTEXT_OPTION],
+ [AM_][XGETTEXT_OPTION([--flag=azsprintf:2:c-format])
+ AM_][XGETTEXT_OPTION([--flag=vazsprintf:2:c-format])])
+
+Makefile.am:
+lib_SOURCES += vazsprintf.c azsprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--
2.34.1
>From 134cfb88c06b0a427f3b4c60acb664c9cc5ec2d9 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:17:10 +0200
Subject: [PATCH 10/11] vasprintf: Make return convention consistent with other
modules.
* lib/vasprintf.c: Include <stdint.h>.
(vasprintf): If the length is > PTRDIFF_MAX, fail with ENOMEM, not
EOVERFLOW.
* modules/vasprintf (Depends-on): Add stdint.
---
ChangeLog | 6 ++++++
lib/vasprintf.c | 12 +++++++++++-
modules/vasprintf | 1 +
3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index b38ebee8a3..7c720ba885 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2024-06-22 Bruno Haible <[email protected]>
+ vasprintf: Make return convention consistent with other modules.
+ * lib/vasprintf.c: Include <stdint.h>.
+ (vasprintf): If the length is > PTRDIFF_MAX, fail with ENOMEM, not
+ EOVERFLOW.
+ * modules/vasprintf (Depends-on): Add stdint.
+
vazsprintf: New module.
* lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
* lib/vazsprintf.c: New file, based on lib/vasprintf.c.
diff --git a/lib/vasprintf.c b/lib/vasprintf.c
index e52aaca586..757d1c740a 100644
--- a/lib/vasprintf.c
+++ b/lib/vasprintf.c
@@ -25,6 +25,7 @@
#include <errno.h>
#include <limits.h>
+#include <stdint.h>
#include <stdlib.h>
#include "vasnprintf.h"
@@ -37,12 +38,21 @@ vasprintf (char **resultp, const char *format, va_list args)
if (result == NULL)
return -1;
+#if PTRDIFF_MAX > INT_MAX
if (length > INT_MAX)
{
free (result);
- errno = EOVERFLOW;
+ errno = (length > PTRDIFF_MAX ? ENOMEM : EOVERFLOW);
return -1;
}
+#else
+ if (length > PTRDIFF_MAX)
+ {
+ free (result);
+ errno = ENOMEM;
+ return -1;
+ }
+#endif
*resultp = result;
/* Return the number of resulting bytes, excluding the trailing NUL. */
diff --git a/modules/vasprintf b/modules/vasprintf
index 91d082bd27..46bfcc51ba 100644
--- a/modules/vasprintf
+++ b/modules/vasprintf
@@ -11,6 +11,7 @@ stdio
extensions
vasnprintf [test $HAVE_VASPRINTF = 0 || test $REPLACE_VASPRINTF = 1]
errno [test $HAVE_VASPRINTF = 0 || test $REPLACE_VASPRINTF = 1]
+stdint [test $HAVE_VASPRINTF = 0 || test $REPLACE_VASPRINTF = 1]
configure.ac:
gl_FUNC_VASPRINTF
--
2.34.1
>From 53549b9b9198f1309f9559cf377e344cf5ea784c Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 12:17:51 +0200
Subject: [PATCH 11/11] xvasprintf: Guarantee a non-NULL result.
* lib/xvasprintf.h: Clarify the programmer's responsibilities.
(xasprintf, xvasprintf): Declare as returning non-NULL.
* lib/xvasprintf.c: Include <stdlib.h>.
(xstrcat): Allow results longer than INT_MAX characters. Upon size
overflow, invoke xalloc_die.
(xvasprintf): Call vazsprintf instead of vasprintf. When some other
error occurs, emit an error message and abort.
* m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
from gl_FUNC_STRERRORNAME_NP.
(gl_FUNC_STRERRORNAME_NP): Invoke it.
(gl_OPTIONAL_STRERRORNAME_NP): New macro.
* m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
* modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
(Depends-on): Add extensions, vazsprintf. Remove vasprintf.
* NEWS: Mention the change.
---
ChangeLog | 19 ++++++++++++++++++
NEWS | 4 ++++
lib/xvasprintf.c | 46 ++++++++++++++++++++++++++++++++-----------
lib/xvasprintf.h | 25 +++++++++++++++--------
m4/strerrorname_np.m4 | 33 ++++++++++++++++++++++++++-----
m4/xvasprintf.m4 | 6 ++++--
modules/xvasprintf | 4 +++-
7 files changed, 110 insertions(+), 27 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 7c720ba885..ef21dcc222 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ xvasprintf: Guarantee a non-NULL result.
+ * lib/xvasprintf.h: Clarify the programmer's responsibilities.
+ (xasprintf, xvasprintf): Declare as returning non-NULL.
+ * lib/xvasprintf.c: Include <stdlib.h>.
+ (xstrcat): Allow results longer than INT_MAX characters. Upon size
+ overflow, invoke xalloc_die.
+ (xvasprintf): Call vazsprintf instead of vasprintf. When some other
+ error occurs, emit an error message and abort.
+ * m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
+ from gl_FUNC_STRERRORNAME_NP.
+ (gl_FUNC_STRERRORNAME_NP): Invoke it.
+ (gl_OPTIONAL_STRERRORNAME_NP): New macro.
+ * m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
+ * modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
+ (Depends-on): Add extensions, vazsprintf. Remove vasprintf.
+ * NEWS: Mention the change.
+
2024-06-22 Bruno Haible <[email protected]>
vasprintf: Make return convention consistent with other modules.
diff --git a/NEWS b/NEWS
index 57540c8375..36ffbb64f8 100644
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,10 @@ User visible incompatible changes
Date Modules Changes
+2024-06-22 xvasprintf It is now the programmer's responsibility to pass
+ a valid format string without %ls, %lc directives
+ and that all widths are >= -INT_MAX and <= INT_MAX.
+
2024-05-16 putenv This module is renamed to 'putenv-gnu'.
2024-02-21 *printf-posix These modules no longer support the 'n' directive
diff --git a/lib/xvasprintf.c b/lib/xvasprintf.c
index 6cf6d36a58..97f24eb297 100644
--- a/lib/xvasprintf.c
+++ b/lib/xvasprintf.c
@@ -21,8 +21,9 @@
#include <errno.h>
#include <limits.h>
-#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "xalloc.h"
@@ -48,14 +49,10 @@ xstrcat (size_t argcount, va_list args)
}
va_end (ap);
- /* Test for overflow in the summing pass above or in (totalsize + 1) below.
- Also, don't return a string longer than INT_MAX, for consistency with
- vasprintf(). */
- if (totalsize == SIZE_MAX || totalsize > INT_MAX)
- {
- errno = EOVERFLOW;
- return NULL;
- }
+ /* Test for overflow in the summing pass above or in (totalsize + 1)
+ below. */
+ if (totalsize == SIZE_MAX)
+ xalloc_die ();
/* Allocate and fill the result string. */
result = XNMALLOC (totalsize + 1, char);
@@ -99,11 +96,38 @@ xvasprintf (const char *format, va_list args)
}
}
- if (vasprintf (&result, format, args) < 0)
+ if (vazsprintf (&result, format, args) < 0)
{
if (errno == ENOMEM)
xalloc_die ();
- return NULL;
+ else
+ {
+ /* The programmer ought to have ensured that none of the other errors
+ can occur. */
+ int err = errno;
+ char errbuf[20];
+ const char *errname;
+#if HAVE_WORKING_STRERRORNAME_NP
+ errname = strerrorname_np (err);
+ if (errname == NULL)
+#else
+ if (err == EINVAL)
+ errname = "EINVAL";
+ else if (err == EILSEQ)
+ errname = "EILSEQ";
+ else if (err == EOVERFLOW)
+ errname = "EOVERFLOW";
+ else
+#endif
+ {
+ sprintf (errbuf, "%d", err);
+ errname = errbuf;
+ }
+ fprintf (stderr, "vasprintf failed! format=\"%s\", errno=%s\n",
+ format, errname);
+ fflush (stderr);
+ abort ();
+ }
}
return result;
diff --git a/lib/xvasprintf.h b/lib/xvasprintf.h
index 937f97ba4b..fac633c549 100644
--- a/lib/xvasprintf.h
+++ b/lib/xvasprintf.h
@@ -17,7 +17,8 @@
#ifndef _XVASPRINTF_H
#define _XVASPRINTF_H
-/* This file uses _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MALLOC. */
+/* This file uses _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MALLOC,
+ _GL_ATTRIBUTE_RETURNS_NONNULL. */
#if !_GL_CONFIG_H_INCLUDED
#error "Please include config.h first."
#endif
@@ -35,19 +36,27 @@
extern "C" {
#endif
-/* Write formatted output to a string dynamically allocated with malloc(),
- and return it. Upon [ENOMEM] memory allocation error, call xalloc_die.
- On some other error
- - [EOVERFLOW] resulting string length is > INT_MAX,
+/* Prints formatted output to a string dynamically allocated with malloc(),
+ and returns it. Upon [ENOMEM] memory allocation error, it calls xalloc_die.
+
+ It is the responsibility of the programmer to ensure that
+ - the format string is valid,
+ - the format string does not use %ls or %lc directives, and
+ - all widths in the format string and passed as arguments are >= -INT_MAX
+ and <= INT_MAX,
+ so that other errors
- [EINVAL] invalid format string,
- [EILSEQ] error during conversion between wide and multibyte characters,
- return NULL. */
+ - [EOVERFLOW] some specified width is > INT_MAX,
+ cannot occur. */
extern char *xasprintf (const char *format, ...)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
- _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2));
+ _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2))
+ _GL_ATTRIBUTE_RETURNS_NONNULL;
extern char *xvasprintf (const char *format, va_list args)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
- _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0));
+ _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0))
+ _GL_ATTRIBUTE_RETURNS_NONNULL;
#ifdef __cplusplus
}
diff --git a/m4/strerrorname_np.m4 b/m4/strerrorname_np.m4
index 9725155bae..ac0211715a 100644
--- a/m4/strerrorname_np.m4
+++ b/m4/strerrorname_np.m4
@@ -1,5 +1,5 @@
# strerrorname_np.m4
-# serial 5
+# serial 6
dnl Copyright (C) 2020-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -9,6 +9,21 @@ AC_DEFUN([gl_FUNC_STRERRORNAME_NP]
[
AC_REQUIRE([gl_STRING_H_DEFAULTS])
+ AC_REQUIRE([gl_CHECK_STRERRORNAME_NP])
+ if test $ac_cv_func_strerrorname_np = yes; then
+ case "$gl_cv_func_strerrorname_np_works" in
+ *yes) ;;
+ *) REPLACE_STRERRORNAME_NP=1 ;;
+ esac
+ else
+ HAVE_STRERRORNAME_NP=0
+ fi
+])
+
+# Check for a working strerrorname_np function.
+# Sets ac_cv_func_strerrorname_np, gl_cv_func_strerrorname_np_works.
+AC_DEFUN([gl_CHECK_STRERRORNAME_NP],
+[
dnl Persuade glibc <string.h> to declare strerrorname_np().
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
@@ -54,11 +69,19 @@ AC_DEFUN([gl_FUNC_STRERRORNAME_NP]
esac
])
])
+ fi
+])
+
+# Prerequisite for using strerrorname_np when available.
+AC_DEFUN_ONCE([gl_OPTIONAL_STRERRORNAME_NP],
+[
+ AC_REQUIRE([gl_CHECK_STRERRORNAME_NP])
+ if test $ac_cv_func_strerrorname_np = yes; then
case "$gl_cv_func_strerrorname_np_works" in
- *yes) ;;
- *) REPLACE_STRERRORNAME_NP=1 ;;
+ *yes)
+ AC_DEFINE([HAVE_WORKING_STRERRORNAME_NP], [1],
+ [Define to 1 if the function strerrorname_np exists and works.])
+ ;;
esac
- else
- HAVE_STRERRORNAME_NP=0
fi
])
diff --git a/m4/xvasprintf.m4 b/m4/xvasprintf.m4
index f492e990cb..a3c15966d9 100644
--- a/m4/xvasprintf.m4
+++ b/m4/xvasprintf.m4
@@ -1,9 +1,11 @@
# xvasprintf.m4
-# serial 2
+# serial 3
dnl Copyright (C) 2006, 2009-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl Prerequisites of lib/xvasprintf.c.
-AC_DEFUN([gl_XVASPRINTF], [:])
+AC_DEFUN([gl_XVASPRINTF], [
+ gl_OPTIONAL_STRERRORNAME_NP
+])
diff --git a/modules/xvasprintf b/modules/xvasprintf
index b322890876..bb537ce3ee 100644
--- a/modules/xvasprintf
+++ b/modules/xvasprintf
@@ -7,10 +7,12 @@ lib/xvasprintf.c
lib/xasprintf.c
lib/xalloc.h
m4/xvasprintf.m4
+m4/strerrorname_np.m4
Depends-on:
+extensions
stdio
-vasprintf
+vazsprintf
xalloc
xalloc-die
extern-inline
--
2.34.1