This series of patches introduces an 'obstack-zprintf' module, that fixes the
INT_MAX limitation (and also the unpredictable errno value in case of failure)
of the 'obstack-printf' module.
I originally planned this set of module dependencies:
obstack-printf -> obstack-zprintf
obstack-zprintf -> vasnprintf
but what I did is:
obstack-printf -> vasnprintf
obstack-zprintf -> vasnprintf
because it's simpler. (In order to implement obstack-printf on top of
obstack-zprintf, one needs to be able to undo a previous obstack_grow
invocation. That sounds inefficient.) It means that obstack_printf.o
and obstack_zprintf.o will contain essentially the same binary code.
But since a package will usually only use of them, not both, it's not
a problem.
2024-06-22 Bruno Haible <[email protected]>
obstack-zprintf: Add more tests.
* tests/test-obstack-zprintf-big.c: New file, based on
tests/test-vasnprintf-big.c.
* modules/obstack-zprintf-extra-tests: New file.
* modules/obstack-zprintf-tests (Depends-on): Add it.
obstack-zprintf: Add tests.
* tests/test-obstack-printf.h: New file, based on
tests/test-obstack-printf.c.
* tests/test-obstack-printf.c: Include test-obstack-printf.h.
(obstack_chunk_alloc, obstack_chunk_free, test_function): Moved to
tests/test-obstack-printf.h.
(test_obstack_vprintf, test_obstack_printf): Remove functions.
(main): Inline them here.
* tests/test-obstack-zprintf.c: New file, based on
tests/test-obstack-printf.c.
* modules/obstack-printf-tests (Files): Add tests/test-obstack-printf.h.
* modules/obstack-zprintf-tests: New file.
obstack-zprintf: New module.
* lib/stdio.in.h (obstack_zprintf, obstack_vzprintf): New declarations.
(obstack_printf, obstack_vprintf): Tweak comment.
* lib/obstack_printf.c: Parameterize.
(RESULT_TYPE, OBSTACK_PRINTF, OBSTACK_VPRINTF): New macros.
* lib/obstack_zprintf.c: New file.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_OBSTACK_ZPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_OBSTACK_ZPRINTF.
* modules/obstack-zprintf: New file.
2024-06-22 Bruno Haible <[email protected]>
physmem: Fix typo.
* lib/physmem.h (physmem_claimable): Fix typo in comment.
>From aa910f1628d4adcfa967d4ef09bc2e82e6bbba89 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 13:05:11 +0200
Subject: [PATCH 1/4] physmem: Fix typo.
* lib/physmem.h (physmem_claimable): Fix typo in comment.
---
ChangeLog | 5 +++++
lib/physmem.h | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index f81ae03de7..8d28459959 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ physmem: Fix typo.
+ * lib/physmem.h (physmem_claimable): Fix typo in comment.
+
2024-06-22 Bruno Haible <[email protected]>
c-xvasprintf: Guarantee a non-NULL result.
diff --git a/lib/physmem.h b/lib/physmem.h
index 542dbf214c..9c5438d016 100644
--- a/lib/physmem.h
+++ b/lib/physmem.h
@@ -39,7 +39,7 @@ double physmem_available (void);
aggressivity.
For AGGRESSIVITY == 0.0, the result is like physmem_available (): the amount
of memory the application can use without hindering any other process.
- For AGGRESSIVITY == 1,0, the result is the amount of memory the application
+ For AGGRESSIVITY == 1.0, the result is the amount of memory the application
can use, while causing memory shortage to other processes, but without
bringing the machine into an out-of-memory state.
Values in between, for example AGGRESSIVITY == 0.5, are a reasonable middle
--
2.34.1
>From b216546a9d3e3fd6097d9a8ab3dd1e67a8a68434 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 21:31:46 +0200
Subject: [PATCH 2/4] obstack-zprintf: New module.
* lib/stdio.in.h (obstack_zprintf, obstack_vzprintf): New declarations.
(obstack_printf, obstack_vprintf): Tweak comment.
* lib/obstack_printf.c: Parameterize.
(RESULT_TYPE, OBSTACK_PRINTF, OBSTACK_VPRINTF): New macros.
* lib/obstack_zprintf.c: New file.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_OBSTACK_ZPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_OBSTACK_ZPRINTF.
* modules/obstack-zprintf: New file.
---
ChangeLog | 13 +++++++++++++
lib/obstack_printf.c | 18 ++++++++++++------
lib/obstack_zprintf.c | 20 ++++++++++++++++++++
lib/stdio.in.h | 34 ++++++++++++++++++++++++++++++----
m4/stdio_h.m4 | 3 ++-
modules/obstack-zprintf | 26 ++++++++++++++++++++++++++
modules/stdio | 1 +
7 files changed, 104 insertions(+), 11 deletions(-)
create mode 100644 lib/obstack_zprintf.c
create mode 100644 modules/obstack-zprintf
diff --git a/ChangeLog b/ChangeLog
index 8d28459959..156dd40138 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-06-22 Bruno Haible <[email protected]>
+
+ obstack-zprintf: New module.
+ * lib/stdio.in.h (obstack_zprintf, obstack_vzprintf): New declarations.
+ (obstack_printf, obstack_vprintf): Tweak comment.
+ * lib/obstack_printf.c: Parameterize.
+ (RESULT_TYPE, OBSTACK_PRINTF, OBSTACK_VPRINTF): New macros.
+ * lib/obstack_zprintf.c: New file.
+ * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_OBSTACK_ZPRINTF.
+ * modules/stdio (Makefile.am): Substitute GNULIB_OBSTACK_ZPRINTF.
+ * modules/obstack-zprintf: New file.
+
2024-06-22 Bruno Haible <[email protected]>
physmem: Fix typo.
diff --git a/lib/obstack_printf.c b/lib/obstack_printf.c
index 57979e3509..ed996dd180 100644
--- a/lib/obstack_printf.c
+++ b/lib/obstack_printf.c
@@ -26,20 +26,26 @@
#include <stdarg.h>
#include <stdlib.h>
+#ifndef RESULT_TYPE
+# define RESULT_TYPE int
+# define OBSTACK_PRINTF obstack_printf
+# define OBSTACK_VPRINTF obstack_vprintf
+#endif
+
/* Grow an obstack with formatted output. Return the number of bytes
added to OBS. No trailing nul byte is added, and the object should
be closed with obstack_finish before use.
Upon memory allocation error, call obstack_alloc_failed_handler.
Upon other error, return -1. */
-int
-obstack_printf (struct obstack *obs, const char *format, ...)
+RESULT_TYPE
+OBSTACK_PRINTF (struct obstack *obs, const char *format, ...)
{
va_list args;
- int result;
+ RESULT_TYPE result;
va_start (args, format);
- result = obstack_vprintf (obs, format, args);
+ result = OBSTACK_VPRINTF (obs, format, args);
va_end (args);
return result;
}
@@ -50,8 +56,8 @@ obstack_printf (struct obstack *obs, const char *format, ...)
Upon memory allocation error, call obstack_alloc_failed_handler.
Upon other error, return -1. */
-int
-obstack_vprintf (struct obstack *obs, const char *format, va_list args)
+RESULT_TYPE
+OBSTACK_VPRINTF (struct obstack *obs, const char *format, va_list args)
{
/* If we are close to the end of the current obstack chunk, use a
stack-allocated buffer and copy, to reduce the likelihood of a
diff --git a/lib/obstack_zprintf.c b/lib/obstack_zprintf.c
new file mode 100644
index 0000000000..b802f4dc26
--- /dev/null
+++ b/lib/obstack_zprintf.c
@@ -0,0 +1,20 @@
+/* Formatted output to obstacks.
+ Copyright (C) 2008-2024 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#define RESULT_TYPE ptrdiff_t
+#define OBSTACK_PRINTF obstack_zprintf
+#define OBSTACK_VPRINTF obstack_vzprintf
+#include "obstack_printf.c"
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 4844ea1ebf..cf2d8c999b 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1075,13 +1075,39 @@ _GL_CXXALIASWARN (getw);
# endif
#endif
+#if @GNULIB_OBSTACK_ZPRINTF@
+struct obstack;
+/* Grows an obstack with formatted output. Returns the number of
+ bytes added to OBS. No trailing nul byte is added, and the
+ object should be closed with obstack_finish before use.
+ Upon memory allocation error, calls obstack_alloc_failed_handler.
+ Upon other error, 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 through
+ obstack_alloc_failed_handler. */
+_GL_FUNCDECL_SYS (obstack_zprintf, ptrdiff_t,
+ (struct obstack *obs, const char *format, ...)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (obstack_zprintf, ptrdiff_t,
+ (struct obstack *obs, const char *format, ...));
+_GL_FUNCDECL_SYS (obstack_vzprintf, ptrdiff_t,
+ (struct obstack *obs, const char *format, va_list args)
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (obstack_vzprintf, ptrdiff_t,
+ (struct obstack *obs, const char *format, va_list args));
+#endif
+
#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
struct obstack;
-/* Grow an obstack with formatted output. Return the number of
+/* Grows an obstack with formatted output. Returns the number of
bytes added to OBS. No trailing nul byte is added, and the
- object should be closed with obstack_finish before use. Upon
- memory allocation error, call obstack_alloc_failed_handler. Upon
- other error, return -1. */
+ object should be closed with obstack_finish before use.
+ Upon memory allocation error, calls obstack_alloc_failed_handler.
+ Upon other error, returns -1. */
# if @REPLACE_OBSTACK_PRINTF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# define obstack_printf rpl_obstack_printf
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index aa06d77027..10e1fbb8aa 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
# stdio_h.m4
-# serial 68
+# serial 69
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,
@@ -159,6 +159,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLINE])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF_POSIX])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_ZPRINTF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PCLOSE])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PERROR])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POPEN])
diff --git a/modules/obstack-zprintf b/modules/obstack-zprintf
new file mode 100644
index 0000000000..d78196f4d5
--- /dev/null
+++ b/modules/obstack-zprintf
@@ -0,0 +1,26 @@
+Description:
+Formatted printing into an obstack (without INT_MAX limitation).
+
+Files:
+lib/obstack_zprintf.c
+lib/obstack_printf.c
+
+Depends-on:
+obstack
+stdio
+vasnprintf
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([obstack-zprintf])
+
+Makefile.am:
+lib_SOURCES += obstack_zprintf.c
+
+Include:
+<stdio.h>
+
+License:
+GPL
+
+Maintainer:
+all
diff --git a/modules/stdio b/modules/stdio
index b0cf4ea207..64fdc5fb60 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -94,6 +94,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
-e 's/@''GNULIB_GETLINE''@/$(GNULIB_GETLINE)/g' \
-e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GNULIB_OBSTACK_PRINTF)/g' \
-e 's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GNULIB_OBSTACK_PRINTF_POSIX)/g' \
+ -e 's/@''GNULIB_OBSTACK_ZPRINTF''@/$(GNULIB_OBSTACK_ZPRINTF)/g' \
-e 's/@''GNULIB_PCLOSE''@/$(GNULIB_PCLOSE)/g' \
-e 's/@''GNULIB_PERROR''@/$(GNULIB_PERROR)/g' \
-e 's/@''GNULIB_POPEN''@/$(GNULIB_POPEN)/g' \
--
2.34.1
>From 94c5a52ccbef8fbc3d1af56d12e120e51b4ca75f Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 21:59:50 +0200
Subject: [PATCH 3/4] obstack-zprintf: Add tests.
* tests/test-obstack-printf.h: New file, based on
tests/test-obstack-printf.c.
* tests/test-obstack-printf.c: Include test-obstack-printf.h.
(obstack_chunk_alloc, obstack_chunk_free, test_function): Moved to
tests/test-obstack-printf.h.
(test_obstack_vprintf, test_obstack_printf): Remove functions.
(main): Inline them here.
* tests/test-obstack-zprintf.c: New file, based on
tests/test-obstack-printf.c.
* modules/obstack-printf-tests (Files): Add tests/test-obstack-printf.h.
* modules/obstack-zprintf-tests: New file.
---
ChangeLog | 13 +++++
modules/obstack-printf-tests | 1 +
modules/obstack-zprintf-tests | 15 ++++++
tests/test-obstack-printf.c | 90 +++--------------------------------
tests/test-obstack-printf.h | 85 +++++++++++++++++++++++++++++++++
tests/test-obstack-zprintf.c | 58 ++++++++++++++++++++++
6 files changed, 179 insertions(+), 83 deletions(-)
create mode 100644 modules/obstack-zprintf-tests
create mode 100644 tests/test-obstack-printf.h
create mode 100644 tests/test-obstack-zprintf.c
diff --git a/ChangeLog b/ChangeLog
index 156dd40138..96f1e397da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2024-06-22 Bruno Haible <[email protected]>
+ obstack-zprintf: Add tests.
+ * tests/test-obstack-printf.h: New file, based on
+ tests/test-obstack-printf.c.
+ * tests/test-obstack-printf.c: Include test-obstack-printf.h.
+ (obstack_chunk_alloc, obstack_chunk_free, test_function): Moved to
+ tests/test-obstack-printf.h.
+ (test_obstack_vprintf, test_obstack_printf): Remove functions.
+ (main): Inline them here.
+ * tests/test-obstack-zprintf.c: New file, based on
+ tests/test-obstack-printf.c.
+ * modules/obstack-printf-tests (Files): Add tests/test-obstack-printf.h.
+ * modules/obstack-zprintf-tests: New file.
+
obstack-zprintf: New module.
* lib/stdio.in.h (obstack_zprintf, obstack_vzprintf): New declarations.
(obstack_printf, obstack_vprintf): Tweak comment.
diff --git a/modules/obstack-printf-tests b/modules/obstack-printf-tests
index 2790e6942b..d319a79d20 100644
--- a/modules/obstack-printf-tests
+++ b/modules/obstack-printf-tests
@@ -1,5 +1,6 @@
Files:
tests/test-obstack-printf.c
+tests/test-obstack-printf.h
tests/signature.h
tests/macros.h
diff --git a/modules/obstack-zprintf-tests b/modules/obstack-zprintf-tests
new file mode 100644
index 0000000000..8ee697934f
--- /dev/null
+++ b/modules/obstack-zprintf-tests
@@ -0,0 +1,15 @@
+Files:
+tests/test-obstack-zprintf.c
+tests/test-obstack-printf.h
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+xalloc
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-obstack-zprintf
+check_PROGRAMS += test-obstack-zprintf
+test_obstack_zprintf_LDADD = $(LDADD) @LIBINTL@
diff --git a/tests/test-obstack-printf.c b/tests/test-obstack-printf.c
index 2c7694320b..c2048c5cee 100644
--- a/tests/test-obstack-printf.c
+++ b/tests/test-obstack-printf.c
@@ -18,12 +18,13 @@
#include <config.h>
+/* Specification. */
#include <stdio.h>
#include "signature.h"
SIGNATURE_CHECK (obstack_printf, int, (struct obstack *, char const *, ...));
-SIGNATURE_CHECK (obstack_vprintf, int, (struct obstack *, char const *,
- va_list));
+SIGNATURE_CHECK (obstack_vprintf, int,
+ (struct obstack *, char const *, va_list));
#include "obstack.h"
#include "xalloc.h"
@@ -34,73 +35,8 @@ SIGNATURE_CHECK (obstack_vprintf, int, (struct obstack *, char const *,
#include "macros.h"
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
-static void
-test_function (int (*my_obstack_printf) (struct obstack *, const char *, ...))
-{
- struct obstack obs;
- obstack_init (&obs);
- /* In general, be careful that arguments to obstack_* don't have
- side effects, as not all compilers evaluate macro arguments only
- once. */
-
- /* Grow the obstack to near its boundary, then check that short
- output longer than the obstack free space grows the obstack. */
- {
- char *base = obstack_base (&obs);
- char *new_base;
- int result;
- int room = obstack_room (&obs) - 4;
-
- obstack_blank_fast (&obs, room);
- result = my_obstack_printf (&obs, "%d %s", 123, "456");
- ASSERT (result == 7);
- ASSERT (result + room == obstack_object_size (&obs));
- obstack_1grow (&obs, 0);
- new_base = obstack_finish (&obs);
- ASSERT (base != new_base);
- ASSERT (strcmp (new_base + room, "123 456") == 0);
- }
-
- /* Check that strings shorter than the obstack free space don't
- cause a reshuffling of the obstack. */
- {
- char *base = obstack_base (&obs);
- char *new_base;
- int result;
- int room = obstack_room (&obs);
-
- ASSERT (8 < room);
- result = my_obstack_printf (&obs, "%d %s", 123, "456");
- ASSERT (result == 7);
- ASSERT (result == obstack_object_size (&obs));
- new_base = obstack_base (&obs);
- ASSERT (base == new_base);
- ASSERT (strncmp (base, "123 456", result) == 0);
- obstack_finish (&obs);
- }
-
- /* Check for generating much more output than a chunk size. */
- {
- char *base = obstack_base (&obs);
- char *new_base;
- int result;
- int i;
-
- ASSERT (obstack_chunk_size (&obs) < 10000);
- result = my_obstack_printf (&obs, "%010000d", 0);
- ASSERT (result == 10000);
- ASSERT (result == obstack_object_size (&obs));
- new_base = obstack_base (&obs);
- ASSERT (base != new_base);
- for (i = 0; i < 10000; i++)
- ASSERT (new_base[i] == '0');
- }
-
- obstack_free (&obs, NULL);
-}
+#define RETTYPE int
+#include "test-obstack-printf.h"
static int
my_obstack_printf (struct obstack *obs, const char *format, ...)
@@ -114,22 +50,10 @@ my_obstack_printf (struct obstack *obs, const char *format, ...)
return ret;
}
-static void
-test_obstack_vprintf ()
-{
- test_function (my_obstack_printf);
-}
-
-static void
-test_obstack_printf ()
-{
- test_function (obstack_printf);
-}
-
int
main (int argc, char *argv[])
{
- test_obstack_vprintf ();
- test_obstack_printf ();
+ test_function (my_obstack_printf);
+ test_function (obstack_printf);
return test_exit_status;
}
diff --git a/tests/test-obstack-printf.h b/tests/test-obstack-printf.h
new file mode 100644
index 0000000000..560decf2ee
--- /dev/null
+++ b/tests/test-obstack-printf.h
@@ -0,0 +1,85 @@
+/* Test of obstack_[v][z]printf() functions.
+ Copyright (C) 2008-2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Eric Blake <[email protected]>, 2008. */
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+static void
+test_function (RETTYPE (*my_obstack_printf) (struct obstack *, const char *, ...))
+{
+ struct obstack obs;
+ obstack_init (&obs);
+ /* In general, be careful that arguments to obstack_* don't have
+ side effects, as not all compilers evaluate macro arguments only
+ once. */
+
+ /* Grow the obstack to near its boundary, then check that short
+ output longer than the obstack free space grows the obstack. */
+ {
+ char *base = obstack_base (&obs);
+ char *new_base;
+ RETTYPE result;
+ int room = obstack_room (&obs) - 4;
+
+ obstack_blank_fast (&obs, room);
+ result = my_obstack_printf (&obs, "%d %s", 123, "456");
+ ASSERT (result == 7);
+ ASSERT (result + room == obstack_object_size (&obs));
+ obstack_1grow (&obs, 0);
+ new_base = obstack_finish (&obs);
+ ASSERT (base != new_base);
+ ASSERT (strcmp (new_base + room, "123 456") == 0);
+ }
+
+ /* Check that strings shorter than the obstack free space don't
+ cause a reshuffling of the obstack. */
+ {
+ char *base = obstack_base (&obs);
+ char *new_base;
+ RETTYPE result;
+ int room = obstack_room (&obs);
+
+ ASSERT (8 < room);
+ result = my_obstack_printf (&obs, "%d %s", 123, "456");
+ ASSERT (result == 7);
+ ASSERT (result == obstack_object_size (&obs));
+ new_base = obstack_base (&obs);
+ ASSERT (base == new_base);
+ ASSERT (strncmp (base, "123 456", result) == 0);
+ obstack_finish (&obs);
+ }
+
+ /* Check for generating much more output than a chunk size. */
+ {
+ char *base = obstack_base (&obs);
+ char *new_base;
+ RETTYPE result;
+ int i;
+
+ ASSERT (obstack_chunk_size (&obs) < 10000);
+ result = my_obstack_printf (&obs, "%010000d", 0);
+ ASSERT (result == 10000);
+ ASSERT (result == obstack_object_size (&obs));
+ new_base = obstack_base (&obs);
+ ASSERT (base != new_base);
+ for (i = 0; i < 10000; i++)
+ ASSERT (new_base[i] == '0');
+ }
+
+ obstack_free (&obs, NULL);
+}
diff --git a/tests/test-obstack-zprintf.c b/tests/test-obstack-zprintf.c
new file mode 100644
index 0000000000..143424604e
--- /dev/null
+++ b/tests/test-obstack-zprintf.c
@@ -0,0 +1,58 @@
+/* Test of obstack_zprintf() and obstack_vzprintf() functions.
+ Copyright (C) 2008-2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <stdio.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (obstack_zprintf, ptrdiff_t,
+ (struct obstack *, char const *, ...));
+SIGNATURE_CHECK (obstack_vzprintf, ptrdiff_t,
+ (struct obstack *, char const *, va_list));
+
+#include "obstack.h"
+#include "xalloc.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macros.h"
+
+#define RETTYPE ptrdiff_t
+#include "test-obstack-printf.h"
+
+static ptrdiff_t
+my_obstack_zprintf (struct obstack *obs, const char *format, ...)
+{
+ va_list args;
+ ptrdiff_t ret;
+
+ va_start (args, format);
+ ret = obstack_vzprintf (obs, format, args);
+ va_end (args);
+ return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+ test_function (my_obstack_zprintf);
+ test_function (obstack_zprintf);
+ return test_exit_status;
+}
--
2.34.1
>From 32871f4b576c5f50fbee8d7e6d5125037e428eed Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 22 Jun 2024 22:02:53 +0200
Subject: [PATCH 4/4] obstack-zprintf: Add more tests.
* tests/test-obstack-zprintf-big.c: New file, based on
tests/test-vasnprintf-big.c.
* modules/obstack-zprintf-extra-tests: New file.
* modules/obstack-zprintf-tests (Depends-on): Add it.
---
ChangeLog | 6 +
modules/obstack-zprintf-extra-tests | 17 +++
modules/obstack-zprintf-tests | 1 +
tests/test-obstack-zprintf-big.c | 210 ++++++++++++++++++++++++++++
4 files changed, 234 insertions(+)
create mode 100644 modules/obstack-zprintf-extra-tests
create mode 100644 tests/test-obstack-zprintf-big.c
diff --git a/ChangeLog b/ChangeLog
index 96f1e397da..bf82a188fc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2024-06-22 Bruno Haible <[email protected]>
+ obstack-zprintf: Add more tests.
+ * tests/test-obstack-zprintf-big.c: New file, based on
+ tests/test-vasnprintf-big.c.
+ * modules/obstack-zprintf-extra-tests: New file.
+ * modules/obstack-zprintf-tests (Depends-on): Add it.
+
obstack-zprintf: Add tests.
* tests/test-obstack-printf.h: New file, based on
tests/test-obstack-printf.c.
diff --git a/modules/obstack-zprintf-extra-tests b/modules/obstack-zprintf-extra-tests
new file mode 100644
index 0000000000..65f7b7096e
--- /dev/null
+++ b/modules/obstack-zprintf-extra-tests
@@ -0,0 +1,17 @@
+Status:
+longrunning-test
+
+Files:
+tests/test-obstack-zprintf-big.c
+tests/macros.h
+
+Depends-on:
+physmem
+
+configure.ac:
+AC_CHECK_FUNCS_ONCE([setrlimit])
+
+Makefile.am:
+TESTS += test-obstack-zprintf-big
+check_PROGRAMS += test-obstack-zprintf-big
+test_obstack_zprintf_big_LDADD = $(LDADD) @LIBINTL@
diff --git a/modules/obstack-zprintf-tests b/modules/obstack-zprintf-tests
index 8ee697934f..99187eb87c 100644
--- a/modules/obstack-zprintf-tests
+++ b/modules/obstack-zprintf-tests
@@ -6,6 +6,7 @@ tests/macros.h
Depends-on:
xalloc
+obstack-zprintf-extra-tests
configure.ac:
diff --git a/tests/test-obstack-zprintf-big.c b/tests/test-obstack-zprintf-big.c
new file mode 100644
index 0000000000..7e66aac9cd
--- /dev/null
+++ b/tests/test-obstack-zprintf-big.c
@@ -0,0 +1,210 @@
+/* Test of obstack_[v]zprintf() with big results.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <[email protected]>, 2024. */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "obstack.h"
+#include "physmem.h"
+
+/* Get INT_MAX. */
+#include <limits.h>
+
+/* Get PTRDIFF_MAX. */
+#include <stdint.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if HAVE_SETRLIMIT
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif
+
+#include "macros.h"
+
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+int
+main ()
+{
+#if PTRDIFF_MAX == INT_MAX
+ fputs ("Skipping test: ptrdiff_t is not 64-bits wide\n", stderr);
+ return 77;
+#else
+ bool skipped = false;
+ /* Disable core files that would be huge. */
+# if HAVE_SETRLIMIT && defined RLIMIT_CORE
+ struct rlimit rl;
+ rl.rlim_cur = rl.rlim_max = 0;
+ setrlimit (RLIMIT_CORE, &rl);
+# endif
+ /* The test below needs about 15 GiB of memory:
+ $ time /usr/bin/time -f "Max RSS: %M KiB" ./test-obstack-zprintf-big
+ Max RSS: 15730184 KiB
+ real 0m38,356s
+ user 0m29,715s
+ sys 0m8,640s
+ 5 GiB for the inputs and up to 10 GiB for temporary output buffers. */
+ double needed = 15.0 * 1024 * 1024 * 1024;
+ double avail = physmem_claimable (1.0);
+ printf ("memory needed = %g MiB, available = %g MiB\n",
+ needed / 1024 / 1024, avail / 1024 / 1024);
+ if (avail >= needed)
+ {
+ /* Note: The malloc() calls can fail, due to ulimit of RLIMIT_DATA.
+ For example, on OpenBSD 7.5, the soft limit is 1.0 GiB or 1.5 GiB,
+ and you need "ulimit -d 16777216". */
+
+ struct obstack obs;
+ obstack_init (&obs);
+
+ /* Verify that obstack_zprintf() can return a string of size > 4 GiB. */
+ {
+ size_t n1 = 3 * (INT_MAX / 4) + 10;
+ size_t n2 = 3 * (INT_MAX / 4) + 20;
+ char *s1;
+ char *s2;
+
+ s1 = (char *) malloc (n1 + 1);
+ if (s1 != NULL)
+ {
+ memset (s1, 'a', n1);
+ s1[n1] = '\0';
+
+ s2 = (char *) malloc (n2 + 1);
+ if (s2 != NULL)
+ {
+ memset (s2, 'b', n2);
+ s1[n1] = '\0';
+
+ ptrdiff_t len = obstack_zprintf (&obs, "x%sy%sz", s1, s2);
+ if (len < 0)
+ {
+ ASSERT (errno == ENOMEM);
+ skipped = true;
+ }
+ else
+ {
+ char *s = obstack_finish (&obs);
+ ASSERT (len == n1 + n2 + 3);
+ size_t i;
+ for (i = 0; i < len; i++)
+ s[i] = (i == 0 ? 'x' :
+ i <= n1 ? 'a' :
+ i == n1 + 1 ? 'y' :
+ i <= n1 + n2 + 1 ? 'b' :
+ i == n1 + n2 + 2 ? 'z' :
+ '\0');
+ obstack_free (&obs, s);
+ }
+ free (s2);
+ }
+ free (s1);
+ }
+ }
+
+ /* Verify that obstack_zprintf() can take a string of size
+ > 2 GiB, < 4 GiB as argument. */
+ {
+ size_t n1 = 3 * (size_t) (INT_MAX / 2) + 10;
+ char *s1;
+
+ s1 = (char *) malloc (n1 + 1);
+ if (s1 != NULL)
+ {
+ memset (s1, 'a', n1);
+ s1[n1] = '\0';
+
+ ptrdiff_t len = obstack_zprintf (&obs, "x%sy", s1);
+ if (len < 0)
+ {
+ ASSERT (errno == ENOMEM);
+ skipped = true;
+ }
+ else
+ {
+ char *s = obstack_finish (&obs);
+ ASSERT (len == n1 + 2);
+ size_t i;
+ for (i = 0; i < len; i++)
+ s[i] = (i == 0 ? 'x' :
+ i <= n1 ? 'a' :
+ i == n1 + 1 ? 'y' :
+ '\0');
+ obstack_free (&obs, s);
+ }
+ free (s1);
+ }
+ }
+
+ /* Verify that obstack_zprintf() can take a string of size > 4 GiB
+ as argument. */
+ {
+ size_t n1 = 5 * (size_t) (INT_MAX / 2) + 10;
+ if (n1 > (size_t) INT_MAX)
+ {
+ char *s1;
+
+ s1 = (char *) malloc (n1 + 1);
+ if (s1 != NULL)
+ {
+ memset (s1, 'a', n1);
+ s1[n1] = '\0';
+
+ ptrdiff_t len = obstack_zprintf (&obs, "x%sy", s1);
+ if (len < 0)
+ {
+ ASSERT (errno == ENOMEM);
+ skipped = true;
+ }
+ else
+ {
+ char *s = obstack_finish (&obs);
+ ASSERT (len == n1 + 2);
+ size_t i;
+ for (i = 0; i < len; i++)
+ s[i] = (i == 0 ? 'x' :
+ i <= n1 ? 'a' :
+ i == n1 + 1 ? 'y' :
+ '\0');
+ obstack_free (&obs, s);
+ }
+ free (s1);
+ }
+ }
+ }
+
+ obstack_free (&obs, NULL);
+ }
+ else
+ skipped = true;
+
+ if (test_exit_status != EXIT_SUCCESS)
+ return test_exit_status;
+ if (skipped)
+ {
+ fputs ("Skipping test: not enough memory available\n", stderr);
+ return 77;
+ }
+ return 0;
+#endif
+}
--
2.34.1