import UBI glibc-2.34-168.el9_6.14

This commit is contained in:
eabdullin 2025-05-13 15:10:28 +00:00
parent 38871a8ad9
commit 39a4f1a064
230 changed files with 161332 additions and 538 deletions

View File

@ -0,0 +1,337 @@
commit f58a8c1c15d8b5d8a08e8553f82867202b88a5cc
Author: Paul Pluzhnikov <ppluzhnikov@google.com>
Date: Sat May 27 06:48:33 2023 +0000
Fix misspellings in iconv/ and iconvdata/ -- BZ 25337
All the changes are in comments or '#error' messages.
Applying this commit results in bit-identical rebuild of iconvdata/*.so
Reviewed-by: Florian Weimer <fw@deneb.enyo.de>
diff --git a/iconv/gconv_charset.c b/iconv/gconv_charset.c
index 5696058298..0cf3226be6 100644
--- a/iconv/gconv_charset.c
+++ b/iconv/gconv_charset.c
@@ -181,10 +181,10 @@ __gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
implementation has always handled them. Only suffixes in the tocode are
processed and handled. The reality is that invalid input in the input
character set should only be ignored if the fromcode specifies IGNORE.
- The current implementation ignores invalid intput in the input character
+ The current implementation ignores invalid input in the input character
set if the tocode contains IGNORE. We preserve this behavior for
backwards compatibility. In the future we may split the handling of
- IGNORE to allow a finer grained specification of ignorning invalid input
+ IGNORE to allow a finer grained specification of ignoring invalid input
and/or ignoring invalid output. */
conv_spec->translit = ptc.translit;
conv_spec->ignore = ptc.ignore;
diff --git a/iconv/gconv_charset.h b/iconv/gconv_charset.h
index 00744aad56..07815b0eee 100644
--- a/iconv/gconv_charset.h
+++ b/iconv/gconv_charset.h
@@ -48,7 +48,7 @@
/* This function copies in-order, characters from the source 's' that are
- either alpha-numeric or one in one of these: "_-.,:/" - into the destination
+ either alphanumeric or one in one of these: "_-.,:/" - into the destination
'wp' while dropping all other characters. In the process, it converts all
alphabetical characters to upper case. It then appends up to two '/'
characters so that the total number of '/'es in the destination is 2. */
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index c76011d6bc..ee9e97e1bd 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -153,7 +153,7 @@ static void
add_alias (char *rp)
{
/* We now expect two more string. The strings are normalized
- (converted to UPPER case) and strored in the alias database. */
+ (converted to UPPER case) and stored in the alias database. */
char *from, *to, *wp;
while (__isspace_l (*rp, _nl_C_locobj_ptr))
diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h
index 4b247a815f..19d042faff 100644
--- a/iconv/gconv_int.h
+++ b/iconv/gconv_int.h
@@ -172,7 +172,7 @@ __libc_lock_define (extern, __gconv_lock attribute_hidden)
})
-/* Return in *HANDLE, a decriptor for the transformation. The function expects
+/* Return in *HANDLE, a descriptor for the transformation. The function expects
the specification of the transformation in the structure pointed to by
CONV_SPEC. It only reads *CONV_SPEC and does not take ownership of it. */
extern int __gconv_open (struct gconv_spec *conv_spec,
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
index c60cffad4c..e936e171d7 100644
--- a/iconv/gconv_simple.c
+++ b/iconv/gconv_simple.c
@@ -56,7 +56,7 @@ __gconv_btwoc_ascii (struct __gconv_step *step, unsigned char c)
/* Transform from the internal, UCS4-like format, to UCS4. The
difference between the internal ucs4 format and the real UCS4
- format is, if any, the endianess. The Unicode/ISO 10646 says that
+ format is, if any, the endianness. The Unicode/ISO 10646 says that
unless some higher protocol specifies it differently, the byte
order is big endian.*/
#define DEFINE_INIT 0
@@ -100,7 +100,7 @@ internal_ucs4_loop (struct __gconv_step *step,
*inptrp = inptr + n_convert * 4;
*outptrp = __mempcpy (outptr, inptr, n_convert * 4);
#else
-# error "This endianess is not supported."
+# error "This endianness is not supported."
#endif
/* Determine the status. */
@@ -153,7 +153,7 @@ internal_ucs4_loop_single (struct __gconv_step *step,
(*outptrp)[2] = state->__value.__wchb[2];
(*outptrp)[3] = state->__value.__wchb[3];
#else
-# error "This endianess is not supported."
+# error "This endianness is not supported."
#endif
*outptrp += 4;
@@ -347,7 +347,7 @@ internal_ucs4le_loop (struct __gconv_step *step,
*inptrp = inptr + n_convert * 4;
*outptrp = __mempcpy (outptr, inptr, n_convert * 4);
#else
-# error "This endianess is not supported."
+# error "This endianness is not supported."
#endif
/* Determine the status. */
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index 1d90938d71..bee898c63c 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -537,7 +537,7 @@ incomplete character or shift sequence at end of buffer"));
static int
process_fd (iconv_t cd, int fd, FILE **output, const char *output_file)
{
- /* we have a problem with reading from a desriptor since we must not
+ /* we have a problem with reading from a descriptor since we must not
provide the iconv() function an incomplete character or shift
sequence at the end of the buffer. Since we have to deal with
arbitrary encodings we must read the whole text in a buffer and
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index a319e2f762..f3f4baa4e7 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -445,7 +445,7 @@ static void
add_alias (char *rp)
{
/* We now expect two more string. The strings are normalized
- (converted to UPPER case) and strored in the alias database. */
+ (converted to UPPER case) and stored in the alias database. */
char *from;
char *to;
char *wp;
diff --git a/iconvdata/bug-iconv8.c b/iconvdata/bug-iconv8.c
index e32d891b5c..1ebb674c91 100644
--- a/iconvdata/bug-iconv8.c
+++ b/iconvdata/bug-iconv8.c
@@ -29,7 +29,7 @@ do_test (void)
/*
* result: -1 84 0 0 (84=EILSEQ)
*
- * Error is returnd but inbuf is consumed.
+ * Error is returned but inbuf is consumed.
*
* \x83\xd9 is valid shift-jis sequence but no character is assigned
* to it.
diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
index 4d6ec71139..5203f30e79 100644
--- a/iconvdata/ibm1364.c
+++ b/iconvdata/ibm1364.c
@@ -91,7 +91,7 @@
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_curcs = *curcsp; \
diff --git a/iconvdata/ibm930.c b/iconvdata/ibm930.c
index 2939d4d29e..fe2fe1f15b 100644
--- a/iconvdata/ibm930.c
+++ b/iconvdata/ibm930.c
@@ -80,7 +80,7 @@
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_curcs = *curcsp; \
diff --git a/iconvdata/ibm933.c b/iconvdata/ibm933.c
index 95935b8b36..4db0699a68 100644
--- a/iconvdata/ibm933.c
+++ b/iconvdata/ibm933.c
@@ -79,7 +79,7 @@
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_curcs = *curcsp; \
diff --git a/iconvdata/ibm935.c b/iconvdata/ibm935.c
index 1d8240a758..3c3d697a24 100644
--- a/iconvdata/ibm935.c
+++ b/iconvdata/ibm935.c
@@ -80,7 +80,7 @@
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_curcs = *curcsp; \
diff --git a/iconvdata/ibm937.c b/iconvdata/ibm937.c
index 9e02aba122..1586036c1e 100644
--- a/iconvdata/ibm937.c
+++ b/iconvdata/ibm937.c
@@ -80,7 +80,7 @@
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_curcs = *curcsp; \
diff --git a/iconvdata/ibm939.c b/iconvdata/ibm939.c
index ce719cb29f..9b053c696e 100644
--- a/iconvdata/ibm939.c
+++ b/iconvdata/ibm939.c
@@ -80,7 +80,7 @@
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_curcs = *curcsp; \
diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c
index d0c3ca4f03..36727f0865 100644
--- a/iconvdata/iso-2022-cn-ext.c
+++ b/iconvdata/iso-2022-cn-ext.c
@@ -154,7 +154,7 @@ enum
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_set = *setp; \
diff --git a/iconvdata/iso-2022-cn.c b/iconvdata/iso-2022-cn.c
index 73eb5e77c6..5660ead668 100644
--- a/iconvdata/iso-2022-cn.c
+++ b/iconvdata/iso-2022-cn.c
@@ -102,7 +102,7 @@ enum
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_set = *setp; \
diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
index d341a14f51..c722bdbfc3 100644
--- a/iconvdata/iso-2022-jp-3.c
+++ b/iconvdata/iso-2022-jp-3.c
@@ -156,7 +156,7 @@ enum
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
saved_state = *statep; \
diff --git a/iconvdata/iso-2022-jp.c b/iconvdata/iso-2022-jp.c
index f31dfb92e6..b023d3cf8e 100644
--- a/iconvdata/iso-2022-jp.c
+++ b/iconvdata/iso-2022-jp.c
@@ -249,7 +249,7 @@ gconv_end (struct __gconv_step *data)
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_set = *setp; \
@@ -679,7 +679,7 @@ static const cvlist_t conversion_lists[4] =
the character is unknown. \
The CJK character sets partially overlap when seen as subsets \
of ISO 10646; therefore there is no single correct result. \
- We use a preferrence order which depends on the language tag. */ \
+ We use a preference order which depends on the language tag. */ \
\
if (ch <= 0x7f) \
{ \
diff --git a/iconvdata/iso-2022-kr.c b/iconvdata/iso-2022-kr.c
index e71198aee9..fd785fd8f9 100644
--- a/iconvdata/iso-2022-kr.c
+++ b/iconvdata/iso-2022-kr.c
@@ -100,7 +100,7 @@ enum
/* Since we might have to reset input pointer we must be able to save
- and retore the state. */
+ and restore the state. */
#define SAVE_RESET_STATE(Save) \
if (Save) \
save_set = *setp; \
diff --git a/iconvdata/iso646.c b/iconvdata/iso646.c
index f7111a3759..1800dc8fdb 100644
--- a/iconvdata/iso646.c
+++ b/iconvdata/iso646.c
@@ -21,7 +21,7 @@
zillions of ISO 646 derivates and supporting them all in a separate
module is overkill since these coded character sets are hardly ever
used anymore (except ANSI_X3.4-1968 == ASCII, which is compatible
- with ISO 8859-1). The European variants are superceded by the
+ with ISO 8859-1). The European variants are superseded by the
various ISO 8859-? standards and the Asian variants are embedded in
larger character sets. Therefore this implementation is simply
here to make it possible to do the conversion if it is necessary.
diff --git a/iconvdata/sjis.c b/iconvdata/sjis.c
index 93c28db13e..5ab821bbff 100644
--- a/iconvdata/sjis.c
+++ b/iconvdata/sjis.c
@@ -2001,7 +2001,7 @@ static const char from_ucs4_greek[193][2] =
/* The mapping of the Kanji is horrible. The glyphs covered by Shift JIS
- are spreaded all around the Unicode CJK area. We use one big table
+ are spread all around the Unicode CJK area. We use one big table
since using the gaps will not buy us much.
The following table can be generated using
diff --git a/iconvdata/tst-table.sh b/iconvdata/tst-table.sh
index d5b1f3c87d..bc6f542b24 100755
--- a/iconvdata/tst-table.sh
+++ b/iconvdata/tst-table.sh
@@ -44,7 +44,7 @@ if test ${charset} = GB18030; then
mv ${objpfx}tst-${charset}.truncated.table ${objpfx}tst-${charset}.charmap.table
fi
-# Precomputed expexted differences between the charmap and iconv forward.
+# Precomputed expected differences between the charmap and iconv forward.
precomposed=${charset}.precomposed
# Precompute expected differences between the charmap and iconv backward.

View File

@ -0,0 +1,218 @@
commit 422ed8ede312f786369e4850e47b8d32beaae4e4
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Sep 20 13:10:54 2024 +0200
iconv: Base tests for buffer management
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts:
iconv/Makefile - tests-special list differences
diff --git a/iconv/Makefile b/iconv/Makefile
index 65b4a44ab8..b0fa550141 100644
--- a/iconv/Makefile 2024-11-18 12:41:42.539981355 -0500
+++ b/iconv/Makefile 2024-11-18 12:40:54.861651890 -0500
@@ -72,7 +72,10 @@ include $(patsubst %,$(..)libof-iterator
ifeq ($(run-built-tests),yes)
xtests-special += $(objpfx)test-iconvconfig.out
-tests-special += $(objpfx)tst-iconv_prog.out
+tests-special += \
+ $(objpfx)tst-iconv_prog-buffer.out \
+ $(objpfx)tst-iconv_prog.out \
+ # tests-special
endif
# Make a copy of the file because gconv module names are constructed
@@ -125,3 +128,8 @@ $(objpfx)tst-iconv_prog.out: tst-iconv_p
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
'$(run-program-env)' > $@; \
$(evaluate-test)
+
+$(objpfx)tst-iconv_prog-buffer.out: \
+ tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
+ $(BASH) $< $(common-objdir) '$(test-program-prefix)' > $@; \
+ $(evaluate-test)
diff --git a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
new file mode 100644
index 0000000000..a27107f02b
--- /dev/null
+++ b/iconv/tst-iconv_prog-buffer.sh
@@ -0,0 +1,177 @@
+#!/bin/bash
+# Test for iconv (the program) buffer management.
+# Copyright (C) 2024 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# 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.
+
+# The GNU C Library 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 the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+exec 2>&1
+set -e
+
+exec {logfd}>&1
+
+codir=$1
+test_program_prefix="$2"
+
+# Use internal converters to avoid issues with module loading.
+iconv_args="-f ASCII -t UTF-8"
+
+failure=false
+
+tmp=`mktemp -d`
+trap 'rm -rf "$tmp"' 0
+echo ABC > "$tmp/abc"
+echo DEF > "$tmp/def"
+echo GGG > "$tmp/ggg"
+echo HH > "$tmp/hh"
+echo XY > "$tmp/xy"
+echo ZT > "$tmp/zt"
+echo OUT > "$tmp/out-template"
+printf '\xff' > "$tmp/0xff"
+cat "$tmp/xy" "$tmp/0xff" "$tmp/zt" > "$tmp/0xff-wrapped"
+
+run_iconv () {
+ local c=0
+ if test "${FUNCNAME[2]}" = main; then
+ c=1
+ fi
+ echo "${BASH_SOURCE[$c]}:${BASH_LINENO[$c]}: iconv $iconv_args $@" >&$logfd
+ $test_program_prefix $codir/iconv/iconv_prog $iconv_args "$@"
+}
+
+check_out_expected () {
+ if ! cmp -s "$tmp/out" "$tmp/expected" ; then
+ echo "error: iconv output difference" >&$logfd
+ echo "*** expected ***" >&$logfd
+ cat "$tmp/expected" >&$logfd
+ echo "*** actual ***" >&$logfd
+ cat "$tmp/out" >&$logfd
+ failure=true
+ fi
+}
+
+expect_files () {
+ local f
+ ! test -z "$1"
+ cp "$tmp/$1" "$tmp/expected"
+ shift
+ for f in "$@" ; do
+ cat "$tmp/$f" >> "$tmp/expected"
+ done
+ check_out_expected
+}
+
+check_out () {
+ cat > "$tmp/expected"
+ check_out_expected
+}
+
+expect_exit () {
+ local expected=$1
+ shift
+ # Prevent failure for stopping the script.
+ if "$@" ; then
+ actual=$?
+ else
+ actual=$?
+ fi
+ if test "$actual" -ne "$expected"; then
+ echo "error: expected exit status $expected, not $actual" >&$logfd
+ exit 1
+ fi
+}
+
+ignore_failure () {
+ set +e
+ "$@"
+ status=$?
+ set -e
+}
+
+# Concatentation test.
+run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/def"
+expect_files abc def
+
+# Single-file in-place conversion.
+run_iconv -o "$tmp/out" "$tmp/out"
+expect_files abc def
+
+# Multiple input files with in-place conversion.
+
+run_iconv -o "$tmp/out" "$tmp/out" "$tmp/abc"
+expect_files abc def abc
+
+# But not if we are writing to standard output.
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv </dev/null >>"$tmp/out"
+expect_files out-template
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv - </dev/null >>"$tmp/out"
+expect_files out-template
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv /dev/null >>"$tmp/out"
+expect_files out-template
+
+# Conversion errors should avoid clobbering an existing file if
+# it is also an input file.
+
+cp "$tmp/0xff" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/out"
+expect_files 0xff
+
+cp "$tmp/0xff" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" < "$tmp/out"
+expect_files 0xff
+
+cp "$tmp/0xff" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" - < "$tmp/out"
+expect_files 0xff
+
+# If errors are ignored, the file should be overwritten.
+
+cp "$tmp/out-template" "$tmp/out"
+expect_exit 1 \
+ run_iconv -c -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def" 2>"$tmp/err"
+! test -s "$tmp/err"
+expect_files abc def
+
+# FIXME: This is not correct, -c should not change the exit status.
+cp "$tmp/out-template" "$tmp/out"
+run_iconv -c -o "$tmp/out" \
+ "$tmp/abc" "$tmp/0xff-wrapped" "$tmp/def" 2>"$tmp/err"
+! test -s "$tmp/err"
+expect_files abc xy zt def
+
+# If the file does not exist yet, it should not be created on error.
+
+rm "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/0xff"
+! test -e "$tmp/out"
+
+expect_exit 1 run_iconv -o "$tmp/out" < "$tmp/0xff"
+! test -e "$tmp/out"
+
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def"
+! test -e "$tmp/out"
+
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/0xff" "$tmp/def"
+! test -e "$tmp/out"
+
+if $failure ; then
+ exit 1
+fi

View File

@ -0,0 +1,91 @@
commit 0cb64617a6f691b611406427c8e24b7f04c4983f
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Sep 20 13:10:54 2024 +0200
iconv: Do not use mmap in iconv (the program) (bug 17703)
On current systems, very large files are needed before
mmap becomes beneficial. Simplify the implementation.
This exposed that inptr was not initialized correctly in
process_fd. Handling multiple input files resulted in
EFAULT in read because a null pointer was passed. This
could be observed previously if an input file was not
mappable and was reported as bug 17703.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index a765b1af21..88a928557e 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -31,9 +31,6 @@
#include <string.h>
#include <unistd.h>
#include <libintl.h>
-#ifdef _POSIX_MAPPED_FILES
-# include <sys/mman.h>
-#endif
#include <charmap.h>
#include <gconv_int.h>
#include "iconv_prog.h"
@@ -253,10 +250,6 @@ conversions from `%s' and to `%s' are not supported"),
else
do
{
-#ifdef _POSIX_MAPPED_FILES
- struct stat64 st;
- char *addr;
-#endif
int fd, ret;
if (verbose)
@@ -276,39 +269,6 @@ conversions from `%s' and to `%s' are not supported"),
}
}
-#ifdef _POSIX_MAPPED_FILES
- /* We have possibilities for reading the input file. First try
- to mmap() it since this will provide the fastest solution. */
- if (fstat64 (fd, &st) == 0
- && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
- fd, 0)) != MAP_FAILED))
- {
- /* Yes, we can use mmap(). The descriptor is not needed
- anymore. */
- if (close (fd) != 0)
- error (EXIT_FAILURE, errno,
- _("error while closing input `%s'"),
- argv[remaining]);
-
- ret = process_block (cd, addr, st.st_size, &output,
- output_file);
-
- /* We don't need the input data anymore. */
- munmap ((void *) addr, st.st_size);
-
- if (ret != 0)
- {
- status = EXIT_FAILURE;
-
- if (ret < 0)
- /* We cannot go on with producing output since it might
- lead to problem because the last output might leave
- the output stream in an undefined state. */
- break;
- }
- }
- else
-#endif /* _POSIX_MAPPED_FILES */
{
/* Read the file in pieces. */
ret = process_fd (cd, fd, &output, output_file);
@@ -544,7 +504,7 @@ process_fd (iconv_t cd, int fd, FILE **output, const char *output_file)
process it in one step. */
static char *inbuf = NULL;
static size_t maxlen = 0;
- char *inptr = NULL;
+ char *inptr = inbuf;
size_t actlen = 0;
while (actlen < maxlen)

View File

@ -0,0 +1,62 @@
commit 00ba299787c2ea9e5c4986301e2f4965dffbfded
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Sep 20 13:10:54 2024 +0200
manual: __is_last is no longer part of iconv internals
The __is_last field was replaced with a bitmask in
commit 85830c4c4688b30d3d76111aa9a26745c7b141d6 in 2000,
and multiple bits are in use today.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/manual/charset.texi b/manual/charset.texi
index 427db3bc80..3aaa62d088 100644
--- a/manual/charset.texi
+++ b/manual/charset.texi
@@ -2422,11 +2422,11 @@ written into the buffer to signal how much output is available. If this
conversion step is not the last one, the element must not be modified.
The @code{__outbufend} element must not be modified.
-@item int __is_last
-This element is nonzero if this conversion step is the last one. This
-information is necessary for the recursion. See the description of the
-conversion function internals below. This element must never be
-modified.
+@item int __flags
+This field is a set of flags. The @code{__GCONV_IS_LAST} bit is set if
+this conversion step is the last one. This information is necessary for
+the recursion. See the description of the conversion function internals
+below. This element must never be modified.
@item int __invocation_counter
The conversion function can use this element to see how many calls of
@@ -2731,8 +2731,8 @@ Otherwise the function has to emit a byte sequence to bring the state
object into the initial state. Once this all happened the other
conversion modules in the chain of conversions have to get the same
chance. Whether another step follows can be determined from the
-@code{__is_last} element of the step data structure to which the first
-parameter points.
+@code{__GCONV_IS_LAST} flag in the @code{__flags} field of the step
+data structure to which the first parameter points.
The more interesting mode is when actual text has to be converted. The
first step in this case is to convert as much text as possible from the
@@ -2866,7 +2866,7 @@ gconv (struct __gconv_step *step, struct __gconv_step_data *data,
/* @r{Call the steps down the chain if there are any but only}
@r{if we successfully emitted the escape sequence.} */
- if (status == __GCONV_OK && ! data->__is_last)
+ if (status == __GCONV_OK && ! (data->__flags & __GCONV_IS_LAST))
status = fct (next_step, next_data, NULL, NULL,
written, 1);
@}
@@ -2892,7 +2892,7 @@ gconv (struct __gconv_step *step, struct __gconv_step_data *data,
/* @r{If this is the last step, leave the loop. There is}
@r{nothing we can do.} */
- if (data->__is_last)
+ if (data->__flags & __GCONV_IS_LAST)
@{
/* @r{Store information about how many bytes are}
@r{available.} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,715 @@
commit 8ef3cff9d1ceafe369f982d980678d749fb93bd2
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Sep 20 13:10:54 2024 +0200
iconv: Support in-place conversions (bug 10460, bug 32033)
Check if any of the input files overlaps with the output file, and use
a temporary file in this case, so that the input is no clobbered
before it is read. This fixes bug 10460. It allows to use iconv
more easily as a functional replacement for GNU recode.
The updated output buffer management truncates the output file
if there is no input, fixing bug 32033.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts:
NEWS - Dropped
iconv/Makefile - tests-special list diffs
iconv/iconv_prog.c - Manual merge
diff -Nrup a/iconv/Makefile b/iconv/Makefile
--- a/iconv/Makefile 2024-11-21 11:08:26.166051531 -0500
+++ b/iconv/Makefile 2024-11-21 11:08:51.325219751 -0500
@@ -77,6 +77,8 @@ include $(patsubst %,$(..)libof-iterator
ifeq ($(run-built-tests),yes)
xtests-special += $(objpfx)test-iconvconfig.out
tests-special += \
+ $(objpfx)tst-iconv_prog-buffer-large.out \
+ $(objpfx)tst-iconv_prog-buffer-tiny.out \
$(objpfx)tst-iconv_prog-buffer.out \
$(objpfx)tst-iconv_prog.out \
# tests-special
@@ -137,3 +139,12 @@ $(objpfx)tst-iconv_prog-buffer.out: \
tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
$(BASH) $< $(common-objdir) '$(test-program-prefix)' > $@; \
$(evaluate-test)
+$(objpfx)tst-iconv_prog-buffer-tiny.out: \
+ tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
+ $(BASH) $< $(common-objdir) '$(test-program-prefix)' \
+ '--buffer-size=1' > $@; \
+ $(evaluate-test)
+$(objpfx)tst-iconv_prog-buffer-large.out: \
+ tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
+ $(BASH) $< $(common-objdir) '$(test-program-prefix)' '' '22' > $@; \
+ $(evaluate-test)
diff -Nrup a/iconv/iconv_prog.c b/iconv/iconv_prog.c
--- a/iconv/iconv_prog.c 2024-11-21 11:08:26.167051537 -0500
+++ b/iconv/iconv_prog.c 2024-11-21 11:10:10.028745981 -0500
@@ -48,7 +48,11 @@
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
-#define OPT_VERBOSE 1000
+enum
+ {
+ OPT_VERBOSE = 1000,
+ OPT_BUFFER_SIZE,
+ };
#define OPT_LIST 'l'
/* Definitions of arguments for argp functions. */
@@ -64,6 +68,10 @@ static const struct argp_option options[
{ "output", 'o', N_("FILE"), 0, N_("output file") },
{ "silent", 's', NULL, 0, N_("suppress warnings") },
{ "verbose", OPT_VERBOSE, NULL, 0, N_("print progress information") },
+ /* This is an internal option intended for testing only. Very small
+ buffers do not work with all character sets. */
+ { "buffer-size", OPT_BUFFER_SIZE, N_("BYTE-COUNT"), OPTION_HIDDEN,
+ N_("size of in-memory scratch buffer") },
{ NULL, 0, NULL, 0, NULL }
};
@@ -101,13 +109,20 @@ static int list;
/* If nonzero omit invalid character from output. */
int omit_invalid;
+/* Current index in argv (after command line processing) with the
+ input file name. */
+static int current_input_file_index;
+
+/* Size of the temporary, in-memory buffer. Exceeding it needs
+ spooling to disk in a temporary file. Controlled by --buffer_size. */
+static size_t output_buffer_size = 1024 * 1024;
+
/* Prototypes for the functions doing the actual work. */
-static int process_block (iconv_t cd, char *addr, size_t len, FILE **output,
- const char *output_file);
-static int process_fd (iconv_t cd, int fd, FILE **output,
- const char *output_file);
-static int process_file (iconv_t cd, FILE *input, FILE **output,
- const char *output_file);
+static void prepare_output_file (char **argv);
+static void close_output_file (int status);
+static int process_block (iconv_t cd, char *addr, size_t len);
+static int process_fd (iconv_t cd, int fd);
+static int process_file (iconv_t cd, FILE *input);
static void print_known_names (void);
@@ -115,7 +130,6 @@ int
main (int argc, char *argv[])
{
int status = EXIT_SUCCESS;
- int remaining;
__gconv_t cd;
struct charmap_t *from_charmap = NULL;
struct charmap_t *to_charmap = NULL;
@@ -127,7 +141,7 @@ main (int argc, char *argv[])
textdomain (_libc_intl_domainname);
/* Parse and process arguments. */
- argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+ argp_parse (&argp, argc, argv, 0, &current_input_file_index, NULL);
/* List all coded character sets if wanted. */
if (list)
@@ -162,7 +176,8 @@ main (int argc, char *argv[])
if (from_charmap != NULL || to_charmap != NULL)
/* Construct the conversion table and do the conversion. */
status = charmap_conversion (from_code, from_charmap, to_code, to_charmap,
- argc, remaining, argv, output_file);
+ argc, current_input_file_index, argv,
+ output_file);
else
{
struct gconv_spec conv_spec;
@@ -236,16 +251,14 @@ conversions from `%s' and to `%s' are no
_("failed to start conversion processing"));
}
- /* The output file. Will be opened when we are ready to produce
- output. */
- FILE *output = NULL;
+ prepare_output_file (argv);
/* Now process the remaining files. Write them to stdout or the file
specified with the `-o' parameter. If we have no file given as
the parameter process all from stdin. */
- if (remaining == argc)
+ if (current_input_file_index == argc)
{
- if (process_file (cd, stdin, &output, output_file) != 0)
+ if (process_file (cd, stdin) != 0)
status = EXIT_FAILURE;
}
else
@@ -254,17 +267,17 @@ conversions from `%s' and to `%s' are no
int fd, ret;
if (verbose)
- fprintf (stderr, "%s:\n", argv[remaining]);
- if (strcmp (argv[remaining], "-") == 0)
- fd = 0;
+ fprintf (stderr, "%s:\n", argv[current_input_file_index]);
+ if (strcmp (argv[current_input_file_index], "-") == 0)
+ fd = STDIN_FILENO;
else
{
- fd = open (argv[remaining], O_RDONLY);
+ fd = open (argv[current_input_file_index], O_RDONLY);
if (fd == -1)
{
error (0, errno, _("cannot open input file `%s'"),
- argv[remaining]);
+ argv[current_input_file_index]);
status = EXIT_FAILURE;
continue;
}
@@ -272,7 +285,7 @@ conversions from `%s' and to `%s' are no
{
/* Read the file in pieces. */
- ret = process_fd (cd, fd, &output, output_file);
+ ret = process_fd (cd, fd);
/* Now close the file. */
close (fd);
@@ -290,7 +303,7 @@ conversions from `%s' and to `%s' are no
}
}
}
- while (++remaining < argc);
+ while (++current_input_file_index < argc);
/* Ensure that iconv -c still exits with failure if iconv (the
function) has failed with E2BIG instead of EILSEQ. */
@@ -298,8 +311,7 @@ conversions from `%s' and to `%s' are no
status = EXIT_FAILURE;
/* Close the output file now. */
- if (output != NULL && fclose (output))
- error (EXIT_FAILURE, errno, _("error while closing output file"));
+ close_output_file (status);
}
return status;
@@ -329,6 +341,14 @@ parse_opt (int key, char *arg, struct ar
/* Omit invalid characters from output. */
omit_invalid = 1;
break;
+ case OPT_BUFFER_SIZE:
+ {
+ int i = atoi (arg);
+ if (i <= 0)
+ error (EXIT_FAILURE, 0, _("invalid buffer size: %s"), arg);
+ output_buffer_size = i;
+ }
+ break;
case OPT_VERBOSE:
verbose = 1;
break;
@@ -375,59 +395,247 @@ warranty; not even for MERCHANTABILITY o
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
+/* Command line index of the last input file that overlaps with the
+ output file. Zero means no temporary file is ever required. */
+static int last_overlapping_file_index;
-static int
-write_output (const char *outbuf, const char *outptr, FILE **output,
- const char *output_file)
+/* This is set to true if the output is written to a temporary file. */
+static bool output_using_temporary_file;
+
+/* This is the file descriptor that will be used by write_output. */
+static int output_fd = -1;
+
+/* Pointers at the start and end of the fixed-size output buffer. */
+static char *output_buffer_start;
+
+/* Current write position in the output buffer. */
+static char *output_buffer_current;
+
+/* Remaining bytes after output_buffer_current in the output buffer. */
+static size_t output_buffer_remaining;
+
+
+/* Reduce the buffer size when writing directly to the output file, to
+ reduce cache utilization. */
+static size_t copy_buffer_size = BUFSIZ;
+
+static void
+output_error (void)
+{
+ error (EXIT_FAILURE, errno, _("cannot open output file"));
+}
+
+static void
+input_error (const char *path)
{
- /* We have something to write out. */
- int errno_save = errno;
+ error (0, errno, _("cannot open input file `%s'"), path);
+}
- if (*output == NULL)
+/* Opens output_file for writing, truncating it. */
+static void
+open_output_direct (void)
+{
+ output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if (output_fd < 0)
+ output_error ();
+}
+
+static void
+prepare_output_file (char **argv)
+{
+ if (copy_buffer_size > output_buffer_size)
+ copy_buffer_size = output_buffer_size;
+
+ if (output_file == NULL || strcmp (output_file, "-") == 0)
+ {
+ /* No buffering is required when writing to standard output
+ because input overlap is expected to be solved externally. */
+ output_fd = STDOUT_FILENO;
+ output_buffer_size = copy_buffer_size;
+ }
+ else
{
- /* Determine output file. */
- if (output_file != NULL && strcmp (output_file, "-") != 0)
+ /* If iconv creates the output file, no overlap is possible. */
+ output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0777);
+ if (output_fd >= 0)
+ output_buffer_size = copy_buffer_size;
+ else
{
- *output = fopen (output_file, "w");
- if (*output == NULL)
- error (EXIT_FAILURE, errno, _("cannot open output file"));
+ /* Otherwise, check if any of the input files overlap with the
+ output file. */
+ struct statx st;
+ if (statx (AT_FDCWD, output_file, 0, STATX_INO | STATX_MODE, &st)
+ != 0)
+ output_error ();
+ uint32_t out_dev_minor = st.stx_dev_minor;
+ uint32_t out_dev_major = st.stx_dev_major;
+ uint64_t out_ino = st.stx_ino;
+
+ int idx = current_input_file_index;
+ while (true)
+ {
+ /* Special case: no input files means standard input. */
+ if (argv[idx] == NULL && idx != current_input_file_index)
+ break;
+
+ int ret;
+ if (argv[idx] == NULL || strcmp (argv[idx], "-") == 0)
+ ret = statx (STDIN_FILENO, "", AT_EMPTY_PATH, STATX_INO, &st);
+ else
+ ret = statx (AT_FDCWD, argv[idx], 0, STATX_INO, &st);
+ if (ret != 0)
+ {
+ input_error (argv[idx]);
+ exit (EXIT_FAILURE);
+ }
+ if (out_dev_minor == st.stx_dev_minor
+ && out_dev_major == st.stx_dev_major
+ && out_ino == st.stx_ino)
+ {
+ if (argv[idx] == NULL)
+ /* Corner case: index of NULL would be larger than
+ idx while converting, triggering a switch away
+ from the temporary file. */
+ last_overlapping_file_index = INT_MAX;
+ else
+ last_overlapping_file_index = idx;
+ }
+
+ if (argv[idx] == NULL)
+ break;
+ ++idx;
+ }
+
+ /* If there is no overlap, avoid using a temporary file. */
+ if (last_overlapping_file_index == 0)
+ {
+ open_output_direct ();
+ output_buffer_size = copy_buffer_size;
+ }
}
- else
- *output = stdout;
}
- if (fwrite (outbuf, 1, outptr - outbuf, *output) < (size_t) (outptr - outbuf)
- || ferror (*output))
+ output_buffer_start = malloc (output_buffer_size);
+ if (output_buffer_start == NULL)
+ output_error ();
+ output_buffer_current = output_buffer_start;
+ output_buffer_remaining = output_buffer_size;
+}
+
+/* Write out the range [first, last), terminating the process on write
+ error. */
+static void
+write_fully (int fd, const char *first, const char *last)
+{
+ while (first < last)
{
- /* Error occurred while printing the result. */
- error (0, 0, _("\
+ ssize_t ret = write (fd, first, last - first);
+ if (ret == 0)
+ {
+ errno = ENOSPC;
+ output_error ();
+ }
+ if (ret < 0)
+ error (EXIT_FAILURE, errno, _("\
conversion stopped due to problem in writing the output"));
- return -1;
+ first += ret;
}
+}
- errno = errno_save;
+static void
+flush_output (void)
+{
+ bool temporary_file_not_needed
+ = current_input_file_index > last_overlapping_file_index;
+ if (output_fd < 0)
+ {
+ if (temporary_file_not_needed)
+ open_output_direct ();
+ else
+ {
+ /* Create an anonymous temporary file. */
+ FILE *fp = tmpfile ();
+ if (fp == NULL)
+ output_error ();
+ output_fd = dup (fileno (fp));
+ if (output_fd < 0)
+ output_error ();
+ fclose (fp);
+ output_using_temporary_file = true;
+ }
+ /* Either way, no longer use a memory-only staging buffer. */
+ output_buffer_size = copy_buffer_size;
+ }
+ else if (output_using_temporary_file && temporary_file_not_needed)
+ {
+ /* The temporary file is no longer needed. Switch to direct
+ output, replacing output_fd. */
+ int temp_fd = output_fd;
+ open_output_direct ();
+
+ /* Copy over the data spooled to the temporary file. */
+ if (lseek (temp_fd, 0, SEEK_SET) < 0)
+ output_error ();
+ while (true)
+ {
+ char buf[BUFSIZ];
+ ssize_t ret = read (temp_fd, buf, sizeof (buf));
+ if (ret < 0)
+ output_error ();
+ if (ret == 0)
+ break;
+ write_fully (output_fd, buf, buf + ret);
+ }
+ close (temp_fd);
- return 0;
+ /* No longer using a temporary file from now on. */
+ output_using_temporary_file = false;
+ output_buffer_size = copy_buffer_size;
+ }
+
+ write_fully (output_fd, output_buffer_start, output_buffer_current);
+ output_buffer_current = output_buffer_start;
+ output_buffer_remaining = output_buffer_size;
}
+static void
+close_output_file (int status)
+{
+ /* Do not perform a flush if a temporary file or the in-memory
+ buffer is in use and there was an error. It would clobber the
+ overlapping input file. */
+ if (status != EXIT_SUCCESS && !omit_invalid &&
+ (output_using_temporary_file || output_fd < 0))
+ return;
+
+ /* The current_input_file_index variable is now larger than
+ last_overlapping_file_index, so the flush_output call switches
+ away from the temporary file. */
+ flush_output ();
+
+ if (output_fd == STDOUT_FILENO)
+ {
+ /* Close standard output in safe manner, to report certain
+ ENOSPC errors. */
+ output_fd = dup (output_fd);
+ if (output_fd < 0)
+ output_error ();
+ }
+ if (close (output_fd) < 0)
+ output_error ();
+}
static int
-process_block (iconv_t cd, char *addr, size_t len, FILE **output,
- const char *output_file)
+process_block (iconv_t cd, char *addr, size_t len)
{
-#define OUTBUF_SIZE 32768
const char *start = addr;
- char outbuf[OUTBUF_SIZE];
- char *outptr;
- size_t outlen;
size_t n;
int ret = 0;
while (len > 0)
{
- outptr = outbuf;
- outlen = OUTBUF_SIZE;
- n = iconv (cd, &addr, &len, &outptr, &outlen);
+ n = iconv (cd, &addr, &len,
+ &output_buffer_current, &output_buffer_remaining);
if (n == (size_t) -1 && omit_invalid && errno == EILSEQ)
{
@@ -438,39 +646,34 @@ process_block (iconv_t cd, char *addr, s
errno = E2BIG;
}
- if (outptr != outbuf)
- {
- ret = write_output (outbuf, outptr, output, output_file);
- if (ret != 0)
- break;
- }
-
if (n != (size_t) -1)
{
/* All the input test is processed. For state-dependent
character sets we have to flush the state now. */
- outptr = outbuf;
- outlen = OUTBUF_SIZE;
- n = iconv (cd, NULL, NULL, &outptr, &outlen);
-
- if (outptr != outbuf)
+ n = iconv (cd, NULL, NULL,
+ &output_buffer_current, &output_buffer_remaining);
+ if (n == (size_t) -1 && errno == E2BIG)
{
- ret = write_output (outbuf, outptr, output, output_file);
- if (ret != 0)
- break;
+ /* Try again if the state flush exceeded the buffer space. */
+ flush_output ();
+ n = iconv (cd, NULL, NULL,
+ &output_buffer_current, &output_buffer_remaining);
}
+ bool errno_is_EILSEQ = errno == EILSEQ;
if (n != (size_t) -1)
break;
- if (omit_invalid && errno == EILSEQ)
+ if (omit_invalid && errno_is_EILSEQ)
{
ret = 1;
break;
}
}
- if (errno != E2BIG)
+ if (errno == E2BIG)
+ flush_output ();
+ else
{
/* iconv() ran into a problem. */
switch (errno)
@@ -501,7 +704,7 @@ incomplete character or shift sequence a
static int
-process_fd (iconv_t cd, int fd, FILE **output, const char *output_file)
+process_fd (iconv_t cd, int fd)
{
/* we have a problem with reading from a descriptor since we must not
provide the iconv() function an incomplete character or shift
@@ -575,16 +778,16 @@ process_fd (iconv_t cd, int fd, FILE **o
}
/* Now we have all the input in the buffer. Process it in one run. */
- return process_block (cd, inbuf, actlen, output, output_file);
+ return process_block (cd, inbuf, actlen);
}
static int
-process_file (iconv_t cd, FILE *input, FILE **output, const char *output_file)
+process_file (iconv_t cd, FILE *input)
{
/* This should be safe since we use this function only for `stdin' and
we haven't read anything so far. */
- return process_fd (cd, fileno (input), output, output_file);
+ return process_fd (cd, fileno (input));
}
diff -Nrup a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
--- a/iconv/tst-iconv_prog-buffer.sh 2024-11-21 11:08:26.168051544 -0500
+++ b/iconv/tst-iconv_prog-buffer.sh 2024-11-21 11:08:51.326219757 -0500
@@ -17,6 +17,12 @@
# License along with the GNU C Library; if not, see
# <https://www.gnu.org/licenses/>.
+# Arguments:
+# root of the build tree ($(objpfx-common))
+# test command wrapper (for running on the board/with new ld.so)
+# extra flags to pass to iconv
+# number of times to double the input files in size (default: 0)
+
exec 2>&1
set -e
@@ -26,7 +32,9 @@ codir=$1
test_program_prefix="$2"
# Use internal converters to avoid issues with module loading.
-iconv_args="-f ASCII -t UTF-8"
+iconv_args="-f ASCII -t UTF-8 $3"
+
+file_size_doublings=${4-0}
failure=false
@@ -39,7 +47,19 @@ echo HH > "$tmp/hh"
echo XY > "$tmp/xy"
echo ZT > "$tmp/zt"
echo OUT > "$tmp/out-template"
+: > "$tmp/empty"
printf '\xff' > "$tmp/0xff"
+
+# Double all files to produce larger buffers.
+for p in "$tmp"/* ; do
+ i=0
+ while test $i -lt $file_size_doublings; do
+ cat "$p" "$p" > "$tmp/scratch"
+ mv "$tmp/scratch" "$p"
+ i=$(($i + 1))
+ done
+done
+
cat "$tmp/xy" "$tmp/0xff" "$tmp/zt" > "$tmp/0xff-wrapped"
run_iconv () {
@@ -113,6 +133,38 @@ expect_files abc def
run_iconv -o "$tmp/out" "$tmp/out" "$tmp/abc"
expect_files abc def abc
+run_iconv -o "$tmp/out" "$tmp/ggg" "$tmp/out"
+expect_files ggg abc def abc
+
+run_iconv -o "$tmp/out" "$tmp/hh" "$tmp/out" "$tmp/hh"
+expect_files hh ggg abc def abc hh
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv -o "$tmp/out" "$tmp/ggg" "$tmp/out" "$tmp/out" "$tmp/ggg"
+expect_files ggg out-template out-template ggg
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv -o "$tmp/out" "$tmp/ggg" "$tmp/out" "$tmp/hh" "$tmp/out" "$tmp/ggg"
+expect_files ggg out-template hh out-template ggg
+
+# Empty output should truncate the output file if exists.
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv -o "$tmp/out" </dev/null
+expect_files empty
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv -o "$tmp/out" - </dev/null
+expect_files empty
+
+cp "$tmp/out-template" "$tmp/out"
+run_iconv -o "$tmp/out" /dev/null
+expect_files empty
+
+cp "$tmp/out-template" "$tmp/out"
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/0xff"
+expect_files empty
+
# But not if we are writing to standard output.
cp "$tmp/out-template" "$tmp/out"
@@ -142,8 +194,36 @@ cp "$tmp/0xff" "$tmp/out"
expect_exit 1 run_iconv -o "$tmp/out" - < "$tmp/out"
expect_files 0xff
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/out"
+expect_files 0xff-wrapped
+
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" < "$tmp/out"
+expect_files 0xff-wrapped
+
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" - < "$tmp/out"
+expect_files 0xff-wrapped
+
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/out"
+expect_files 0xff-wrapped
+
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/out"
+expect_files 0xff-wrapped
+
# If errors are ignored, the file should be overwritten.
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/out"
+expect_files xy zt
+
+cp "$tmp/0xff" "$tmp/out"
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/abc" "$tmp/out" "$tmp/def"
+expect_files abc def
+
cp "$tmp/out-template" "$tmp/out"
expect_exit 1 \
run_iconv -c -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def" 2>"$tmp/err"
@@ -156,6 +236,20 @@ expect_exit 1 run_iconv -c -o "$tmp/out"
! test -s "$tmp/err"
expect_files abc xy zt def
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/out" "$tmp/abc" "$tmp/out" "$tmp/def"
+expect_files xy zt abc xy zt def
+
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -o "$tmp/out" \
+ "$tmp/out" "$tmp/abc" "$tmp/out" "$tmp/def"
+expect_files 0xff-wrapped
+
+cp "$tmp/0xff-wrapped" "$tmp/out"
+expect_exit 1 run_iconv -c -o "$tmp/out" \
+ "$tmp/abc" "$tmp/out" "$tmp/def" "$tmp/out"
+expect_files abc xy zt def xy zt
+
# If the file does not exist yet, it should not be created on error.
rm "$tmp/out"

View File

@ -0,0 +1,41 @@
commit 75819cdd29a193cc2db980878bec305905b22bbc
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Sep 20 13:10:54 2024 +0200
iconv: Multiple - on command line should not fail (bug 32050)
Usually, the second and subsequent - return EOF immediately
and do not contribute to the output, but this is not an error.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index 3e02db7319..dd4bc3a59a 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -287,7 +287,8 @@ conversions from `%s' and to `%s' are not supported"),
ret = process_fd (cd, fd);
/* Now close the file. */
- close (fd);
+ if (fd != STDIN_FILENO)
+ close (fd);
if (ret != 0)
{
diff --git a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
index 54ff871d32..a9c3729d94 100644
--- a/iconv/tst-iconv_prog-buffer.sh
+++ b/iconv/tst-iconv_prog-buffer.sh
@@ -265,6 +265,11 @@ expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def"
expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/0xff" "$tmp/def"
! test -e "$tmp/out"
+# Listing standard input multiple times should not fail (bug 32050).
+
+run_iconv -o "$tmp/out" "$tmp/xy" - - "$tmp/zt" < "$tmp/abc"
+expect_files xy abc zt
+
if $failure ; then
exit 1
fi

View File

@ -0,0 +1,323 @@
commit fa1b0d5e9f6e0353e16339430770a7a8824c0468
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Sep 20 13:10:54 2024 +0200
iconv: Input buffering for the iconv program (bug 6050)
Do not read the entire input file into memory.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index dd4bc3a59a..a2f1d34e45 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -118,8 +118,9 @@ static size_t output_buffer_size = 1024 * 1024;
/* Prototypes for the functions doing the actual work. */
static void prepare_output_file (char **argv);
-static void close_output_file (int status);
-static int process_block (iconv_t cd, char *addr, size_t len);
+static void close_output_file (__gconv_t cd, int status);
+static int process_block (iconv_t cd, char **addr, size_t *len,
+ off64_t file_offset, bool *incomplete);
static int process_fd (iconv_t cd, int fd);
static int process_file (iconv_t cd, FILE *input);
static void print_known_names (void);
@@ -311,7 +312,7 @@ conversions from `%s' and to `%s' are not supported"),
status = EXIT_FAILURE;
/* Close the output file now. */
- close_output_file (status);
+ close_output_file (cd, status);
}
return status;
@@ -599,7 +600,7 @@ flush_output (void)
}
static void
-close_output_file (int status)
+close_output_file (__gconv_t cd, int status)
{
/* Do not perform a flush if a temporary file or the in-memory
buffer is in use and there was an error. It would clobber the
@@ -608,10 +609,28 @@ close_output_file (int status)
(output_using_temporary_file || output_fd < 0))
return;
- /* The current_input_file_index variable is now larger than
- last_overlapping_file_index, so the flush_output call switches
+ /* All the input text is processed. For state-dependent character
+ sets we have to flush the state now.
+
+ The current_input_file_index variable is now larger than
+ last_overlapping_file_index, so the flush_output calls switch
away from the temporary file. */
+ size_t n = iconv (cd, NULL, NULL,
+ &output_buffer_current, &output_buffer_remaining);
+ if (n == (size_t) -1 && errno == E2BIG)
+ {
+ /* Try again if the state flush exceeded the buffer space. */
+ flush_output ();
+ n = iconv (cd, NULL, NULL,
+ &output_buffer_current, &output_buffer_remaining);
+ }
+ int saved_errno = errno;
flush_output ();
+ if (n == (size_t) -1 && !omit_invalid)
+ {
+ errno = saved_errno;
+ output_error ();
+ }
if (output_fd == STDOUT_FILENO)
{
@@ -625,51 +644,35 @@ close_output_file (int status)
output_error ();
}
+/* CD is the iconv handle. Input processing starts at *ADDR, and
+ consumes upto *LEN bytes. *ADDR and *LEN are updated. FILE_OFFSET
+ is the file offset of the data initially at ADDR. *INCOMPLETE is
+ set to true if conversion stops due to an incomplete input
+ sequence. */
static int
-process_block (iconv_t cd, char *addr, size_t len)
+process_block (iconv_t cd, char **addr, size_t *len, off64_t file_offset,
+ bool *incomplete)
{
- const char *start = addr;
+ const char *start = *addr;
size_t n;
int ret = 0;
- while (len > 0)
+ while (*len > 0)
{
- n = iconv (cd, &addr, &len,
+ n = iconv (cd, addr, len,
&output_buffer_current, &output_buffer_remaining);
if (n == (size_t) -1 && omit_invalid && errno == EILSEQ)
{
ret = 1;
- if (len == 0)
+ if (*len == 0)
n = 0;
else
errno = E2BIG;
}
if (n != (size_t) -1)
- {
- /* All the input test is processed. For state-dependent
- character sets we have to flush the state now. */
- n = iconv (cd, NULL, NULL,
- &output_buffer_current, &output_buffer_remaining);
- if (n == (size_t) -1 && errno == E2BIG)
- {
- /* Try again if the state flush exceeded the buffer space. */
- flush_output ();
- n = iconv (cd, NULL, NULL,
- &output_buffer_current, &output_buffer_remaining);
- }
- bool errno_is_EILSEQ = errno == EILSEQ;
-
- if (n != (size_t) -1)
- break;
-
- if (omit_invalid && errno_is_EILSEQ)
- {
- ret = 1;
- break;
- }
- }
+ break;
if (errno == E2BIG)
flush_output ();
@@ -680,13 +683,12 @@ process_block (iconv_t cd, char *addr, size_t len)
{
case EILSEQ:
if (! omit_invalid)
- error (0, 0, _("illegal input sequence at position %ld"),
- (long int) (addr - start));
+ error (0, 0, _("illegal input sequence at position %lld"),
+ (long long int) (file_offset + (*addr - start)));
break;
case EINVAL:
- error (0, 0, _("\
-incomplete character or shift sequence at end of buffer"));
- break;
+ *incomplete = true;
+ return ret;
case EBADF:
error (0, 0, _("internal error (illegal descriptor)"));
break;
@@ -706,79 +708,49 @@ incomplete character or shift sequence at end of buffer"));
static int
process_fd (iconv_t cd, int fd)
{
- /* we have a problem with reading from a descriptor since we must not
- provide the iconv() function an incomplete character or shift
- sequence at the end of the buffer. Since we have to deal with
- arbitrary encodings we must read the whole text in a buffer and
- process it in one step. */
- static char *inbuf = NULL;
- static size_t maxlen = 0;
- char *inptr = inbuf;
- size_t actlen = 0;
-
- while (actlen < maxlen)
+ char inbuf[BUFSIZ];
+ char *inbuf_end = inbuf + sizeof (inbuf);
+ size_t inbuf_used = 0;
+ off64_t file_offset = 0;
+ int status = 0;
+ bool incomplete = false;
+
+ while (true)
{
- ssize_t n = read (fd, inptr, maxlen - actlen);
-
- if (n == 0)
- /* No more text to read. */
- break;
-
- if (n == -1)
+ char *p = inbuf + inbuf_used;
+ ssize_t read_ret = read (fd, p, inbuf_end - p);
+ if (read_ret == 0)
+ {
+ /* On EOF, check if the previous iconv invocation saw an
+ incomplete sequence. */
+ if (incomplete)
+ {
+ error (0, 0, _("\
+incomplete character or shift sequence at end of buffer"));
+ return 1;
+ }
+ return 0;
+ }
+ if (read_ret < 0)
{
- /* Error while reading. */
error (0, errno, _("error while reading the input"));
return -1;
}
-
- inptr += n;
- actlen += n;
+ inbuf_used += read_ret;
+ incomplete = false;
+ p = inbuf;
+ int ret = process_block (cd, &p, &inbuf_used, file_offset, &incomplete);
+ if (ret != 0)
+ {
+ status = ret;
+ if (ret < 0)
+ break;
+ }
+ /* The next loop iteration consumes the leftover bytes. */
+ memmove (inbuf, p, inbuf_used);
+ file_offset += read_ret - inbuf_used;
}
-
- if (actlen == maxlen)
- while (1)
- {
- ssize_t n;
- char *new_inbuf;
-
- /* Increase the buffer. */
- new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
- if (new_inbuf == NULL)
- {
- error (0, errno, _("unable to allocate buffer for input"));
- return -1;
- }
- inbuf = new_inbuf;
- maxlen += 32768;
- inptr = inbuf + actlen;
-
- do
- {
- n = read (fd, inptr, maxlen - actlen);
-
- if (n == 0)
- /* No more text to read. */
- break;
-
- if (n == -1)
- {
- /* Error while reading. */
- error (0, errno, _("error while reading the input"));
- return -1;
- }
-
- inptr += n;
- actlen += n;
- }
- while (actlen < maxlen);
-
- if (n == 0)
- /* Break again so we leave both loops. */
- break;
- }
-
- /* Now we have all the input in the buffer. Process it in one run. */
- return process_block (cd, inbuf, actlen);
+ return status;
}
diff --git a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
index a9c3729d94..23098ac56a 100644
--- a/iconv/tst-iconv_prog-buffer.sh
+++ b/iconv/tst-iconv_prog-buffer.sh
@@ -50,6 +50,9 @@ echo OUT > "$tmp/out-template"
: > "$tmp/empty"
printf '\xff' > "$tmp/0xff"
+# Length should be a prime number, to help with buffer alignment testing.
+printf '\xc3\xa4\xe2\x80\x94\xe2\x80\x94\xc3\xa4\n' > "$tmp/utf8-sequence"
+
# Double all files to produce larger buffers.
for p in "$tmp"/* ; do
i=0
@@ -270,6 +273,34 @@ expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/0xff" "$tmp/def"
run_iconv -o "$tmp/out" "$tmp/xy" - - "$tmp/zt" < "$tmp/abc"
expect_files xy abc zt
+# NB: Extra iconv args are ignored after this point. Actual
+# multi-byte conversion does not work with tiny buffers.
+iconv_args="-f UTF-8 -t ASCII"
+
+printf 'x\n\xc3' > "$tmp/incomplete"
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/incomplete"
+check_out <<EOF
+x
+EOF
+
+# Test buffering behavior if the buffer ends with an incomplete
+# multi-byte sequence.
+prefix=""
+prefix_length=0
+while test $prefix_length -lt 12; do
+ echo "info: testing prefix length $prefix_length" 2>&$logfd
+ printf "%s" "$prefix" > "$tmp/prefix"
+ cat "$tmp/prefix" "$tmp/utf8-sequence" > "$tmp/tmp"
+ iconv_args="-f UTF-8 -t UCS-4"
+ run_iconv -o "$tmp/out1" "$tmp/tmp"
+ iconv_args="-f UCS-4 -t UTF-8"
+ run_iconv -o "$tmp/out" "$tmp/out1"
+ expect_files prefix utf8-sequence
+
+ prefix="$prefix@"
+ prefix_length=$(($prefix_length + 1))
+done
+
if $failure ; then
exit 1
fi

View File

@ -0,0 +1,37 @@
commit 079ebf7624e7fd0ad7fe94a7176a2e132c996d86
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Sep 24 10:41:35 2024 +0200
iconv: Use $(run-program-prefix) for running iconv (bug 32197)
With --enable-hardcoded-path-in-tests, $(test-program-prefix)
does not redirect to the built glibc, but we need to run
iconv (the program) against the built glibc even with
--enable-hardcoded-path-in-tests, as it is using the ABI
path for the dynamic linker (as an installed program).
Use $(run-program-prefix) instead.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff --git a/iconv/Makefile b/iconv/Makefile
index c9af0c4d44..de9d964ed3 100644
--- a/iconv/Makefile
+++ b/iconv/Makefile
@@ -153,14 +153,14 @@ $(objpfx)tst-translit-mchar.out: tst-translit-mchar.sh \
$(objpfx)tst-iconv_prog-buffer.out: \
tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
- $(BASH) $< $(common-objdir) '$(test-program-prefix)' > $@; \
+ $(BASH) $< $(common-objdir) '$(run-program-prefix)' > $@; \
$(evaluate-test)
$(objpfx)tst-iconv_prog-buffer-tiny.out: \
tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
- $(BASH) $< $(common-objdir) '$(test-program-prefix)' \
+ $(BASH) $< $(common-objdir) '$(run-program-prefix)' \
'--buffer-size=1' > $@; \
$(evaluate-test)
$(objpfx)tst-iconv_prog-buffer-large.out: \
tst-iconv_prog-buffer.sh $(objpfx)iconv_prog
- $(BASH) $< $(common-objdir) '$(test-program-prefix)' '' '22' > $@; \
+ $(BASH) $< $(common-objdir) '$(run-program-prefix)' '' '22' > $@; \
$(evaluate-test)

View File

@ -0,0 +1,315 @@
commit 3367d8e180848030d1646f088759f02b8dfe0d6f
Author: Amrita H S <amritahs@linux.vnet.ibm.com>
Date: Wed Dec 6 11:43:11 2023 -0500
powerpc: Optimized strcmp for power10
This patch is based on __strcmp_power9 and __strlen_power10.
Improvements from __strcmp_power9:
1. Uses new POWER10 instructions
- This code uses lxvp to decrease contention on load
by loading 32 bytes per instruction.
2. Performance implication
- This version has around 30% better performance on average.
- Performance regression is seen for a specific combination
of sizes and alignments. Some of them is observed without
changes also, while rest may be induced by the patch.
Signed-off-by: Amrita H S <amritahs@linux.vnet.ibm.com>
Reviewed-by: Paul E. Murphy <murphyp@linux.ibm.com>
diff --git a/sysdeps/powerpc/powerpc64/le/power10/strcmp.S b/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
new file mode 100644
index 0000000000000000..a3c1adad539978e0
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
@@ -0,0 +1,204 @@
+/* Optimized strcmp implementation for PowerPC64/POWER10.
+ Copyright (C) 2021-2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+#include <sysdep.h>
+
+#ifndef STRCMP
+# define STRCMP strcmp
+#endif
+
+/* Implements the function
+ int [r3] strcmp (const char *s1 [r3], const char *s2 [r4]). */
+
+/* TODO: Change this to actual instructions when minimum binutils is upgraded
+ to 2.27. Macros are defined below for these newer instructions in order
+ to maintain compatibility. */
+
+#define LXVP(xtp,dq,ra) \
+ .long(((6)<<(32-6)) \
+ | ((((xtp)-32)>>1)<<(32-10)) \
+ | ((1)<<(32-11)) \
+ | ((ra)<<(32-16)) \
+ | dq)
+
+#define COMPARE_16(vreg1,vreg2,offset) \
+ lxv vreg1+32,offset(r3); \
+ lxv vreg2+32,offset(r4); \
+ vcmpnezb. v7,vreg1,vreg2; \
+ bne cr6,L(different); \
+
+#define COMPARE_32(vreg1,vreg2,offset,label1,label2) \
+ LXVP(vreg1+32,offset,r3); \
+ LXVP(vreg2+32,offset,r4); \
+ vcmpnezb. v7,vreg1+1,vreg2+1; \
+ bne cr6,L(label1); \
+ vcmpnezb. v7,vreg1,vreg2; \
+ bne cr6,L(label2); \
+
+#define TAIL(vreg1,vreg2) \
+ vctzlsbb r6,v7; \
+ vextubrx r5,r6,vreg1; \
+ vextubrx r4,r6,vreg2; \
+ subf r3,r4,r5; \
+ blr; \
+
+#define CHECK_N_BYTES(reg1,reg2,len_reg) \
+ sldi r0,len_reg,56; \
+ lxvl 32+v4,reg1,r0; \
+ lxvl 32+v5,reg2,r0; \
+ add reg1,reg1,len_reg; \
+ add reg2,reg2,len_reg; \
+ vcmpnezb. v7,v4,v5; \
+ vctzlsbb r6,v7; \
+ cmpld cr7,r6,len_reg; \
+ blt cr7,L(different); \
+
+ /* TODO: change this to .machine power10 when the minimum required
+ binutils allows it. */
+
+ .machine power9
+ENTRY_TOCLESS (STRCMP, 4)
+ li r11,16
+ /* eq bit of cr1 used as swap status flag to indicate if
+ source pointers were swapped. */
+ crclr 4*cr1+eq
+ vspltisb v19,-1
+ andi. r7,r3,15
+ sub r7,r11,r7 /* r7(nalign1) = 16 - (str1 & 15). */
+ andi. r9,r4,15
+ sub r5,r11,r9 /* r5(nalign2) = 16 - (str2 & 15). */
+ cmpld cr7,r7,r5
+ beq cr7,L(same_aligned)
+ blt cr7,L(nalign1_min)
+ /* Swap r3 and r4, and r7 and r5 such that r3 and r7 hold the
+ pointer which is closer to the next 16B boundary so that only
+ one CHECK_N_BYTES is needed before entering the loop below. */
+ mr r8,r4
+ mr r4,r3
+ mr r3,r8
+ mr r12,r7
+ mr r7,r5
+ mr r5,r12
+ crset 4*cr1+eq /* Set bit on swapping source pointers. */
+
+ .p2align 5
+L(nalign1_min):
+ CHECK_N_BYTES(r3,r4,r7)
+
+ .p2align 5
+L(s1_aligned):
+ /* r9 and r5 is number of bytes to be read after and before
+ page boundary correspondingly. */
+ sub r5,r5,r7
+ subfic r9,r5,16
+ /* Now let r7 hold the count of quadwords which can be
+ checked without crossing a page boundary. quadword offset is
+ (str2>>4)&0xFF. */
+ rlwinm r7,r4,28,0xFF
+ /* Below check is required only for first iteration. For second
+ iteration and beyond, the new loop counter is always 255. */
+ cmpldi r7,255
+ beq L(L3)
+ /* Get the initial loop count by 255-((str2>>4)&0xFF). */
+ subfic r11,r7,255
+
+ .p2align 5
+L(L1):
+ mtctr r11
+
+ .p2align 5
+L(L2):
+ COMPARE_16(v4,v5,0) /* Load 16B blocks using lxv. */
+ addi r3,r3,16
+ addi r4,r4,16
+ bdnz L(L2)
+ /* Cross the page boundary of s2, carefully. */
+
+ .p2align 5
+L(L3):
+ CHECK_N_BYTES(r3,r4,r5)
+ CHECK_N_BYTES(r3,r4,r9)
+ li r11,255 /* Load the new loop counter. */
+ b L(L1)
+
+ .p2align 5
+L(same_aligned):
+ CHECK_N_BYTES(r3,r4,r7)
+ /* Align s1 to 32B and adjust s2 address.
+ Use lxvp only if both s1 and s2 are 32B aligned. */
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ COMPARE_16(v4,v5,32)
+ COMPARE_16(v4,v5,48)
+ addi r3,r3,64
+ addi r4,r4,64
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+
+ clrldi r6,r3,59
+ subfic r5,r6,32
+ add r3,r3,r5
+ add r4,r4,r5
+ andi. r5,r4,0x1F
+ beq cr0,L(32B_aligned_loop)
+
+ .p2align 5
+L(16B_aligned_loop):
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ COMPARE_16(v4,v5,32)
+ COMPARE_16(v4,v5,48)
+ addi r3,r3,64
+ addi r4,r4,64
+ b L(16B_aligned_loop)
+
+ /* Calculate and return the difference. */
+L(different):
+ vctzlsbb r6,v7
+ vextubrx r5,r6,v4
+ vextubrx r4,r6,v5
+ bt 4*cr1+eq,L(swapped)
+ subf r3,r4,r5
+ blr
+
+ /* If src pointers were swapped, then swap the
+ indices and calculate the return value. */
+L(swapped):
+ subf r3,r5,r4
+ blr
+
+ .p2align 5
+L(32B_aligned_loop):
+ COMPARE_32(v14,v16,0,tail1,tail2)
+ COMPARE_32(v18,v20,32,tail3,tail4)
+ COMPARE_32(v22,v24,64,tail5,tail6)
+ COMPARE_32(v26,v28,96,tail7,tail8)
+ addi r3,r3,128
+ addi r4,r4,128
+ b L(32B_aligned_loop)
+
+L(tail1): TAIL(v15,v17)
+L(tail2): TAIL(v14,v16)
+L(tail3): TAIL(v19,v21)
+L(tail4): TAIL(v18,v20)
+L(tail5): TAIL(v23,v25)
+L(tail6): TAIL(v22,v24)
+L(tail7): TAIL(v27,v29)
+L(tail8): TAIL(v26,v28)
+
+END (STRCMP)
+libc_hidden_builtin_def (strcmp)
diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
index 0ee7ce39d6470d80..91ed88a9c716800d 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
+++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
@@ -33,7 +33,8 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
ifneq (,$(filter %le,$(config-machine)))
sysdep_routines += memcmp-power10 memcpy-power10 memmove-power10 memset-power10 \
rawmemchr-power9 rawmemchr-power10 \
- strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \
+ strcmp-power9 strcmp-power10 strncmp-power9 \
+ strcpy-power9 stpcpy-power9 \
strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10
endif
CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
index 2c84d287ee76a7ea..caec2047ab10d209 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
@@ -416,6 +416,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
/* Support sysdeps/powerpc/powerpc64/multiarch/strcmp.c. */
IFUNC_IMPL (i, name, strcmp,
#ifdef __LITTLE_ENDIAN__
+ IFUNC_IMPL_ADD (array, i, strcmp,
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1)
+ && (hwcap & PPC_FEATURE_HAS_VSX),
+ __strcmp_power10)
IFUNC_IMPL_ADD (array, i, strcmp,
hwcap2 & PPC_FEATURE2_ARCH_3_00
&& hwcap & PPC_FEATURE_HAS_ALTIVEC,
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp-power10.S b/sysdeps/powerpc/powerpc64/multiarch/strcmp-power10.S
new file mode 100644
index 0000000000000000..c80067ce3305de81
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp-power10.S
@@ -0,0 +1,26 @@
+/* Optimized strcmp implementation for POWER10/PPC64.
+ Copyright (C) 2021-2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
+#define STRCMP __strcmp_power10
+
+#undef libc_hidden_builtin_def
+#define libc_hidden_builtin_def(name)
+
+#include <sysdeps/powerpc/powerpc64/le/power10/strcmp.S>
+#endif /* __LITTLE_ENDIAN__ && IS_IN (libc) */
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
index 8132682a992edb7a..4e77005117525edb 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
@@ -29,12 +29,16 @@ extern __typeof (strcmp) __strcmp_power7 attribute_hidden;
extern __typeof (strcmp) __strcmp_power8 attribute_hidden;
# ifdef __LITTLE_ENDIAN__
extern __typeof (strcmp) __strcmp_power9 attribute_hidden;
+extern __typeof (strcmp) __strcmp_power10 attribute_hidden;
# endif
# undef strcmp
libc_ifunc_redirected (__redirect_strcmp, strcmp,
# ifdef __LITTLE_ENDIAN__
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1
+ && hwcap & PPC_FEATURE_HAS_VSX)
+ ? __strcmp_power10 :
(hwcap2 & PPC_FEATURE2_ARCH_3_00
&& hwcap & PPC_FEATURE_HAS_ALTIVEC)
? __strcmp_power9 :

View File

@ -0,0 +1,435 @@
commit b9182c793caa05df5d697427c0538936e6396d4b
Author: MAHESH BODAPATI <bmahi496@linux.ibm.com>
Date: Tue Dec 12 08:52:45 2023 -0600
powerpc : Add optimized memchr for POWER10
Optimized memchr for POWER10 based on existing rawmemchr and strlen.
Reordering instructions and loop unrolling helped in getting better performance.
Reviewed-by: Rajalakshmi Srinivasaraghavan <rajis@linux.ibm.com>
diff --git a/sysdeps/powerpc/powerpc64/le/power10/memchr.S b/sysdeps/powerpc/powerpc64/le/power10/memchr.S
new file mode 100644
index 0000000000000000..faf293f3447e6fc6
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/power10/memchr.S
@@ -0,0 +1,315 @@
+/* Optimized memchr implementation for POWER10 LE.
+ Copyright (C) 2021-2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+# ifndef MEMCHR
+# define MEMCHR __memchr
+# endif
+# define M_VREG_ZERO v20
+# define M_OFF_START_LOOP 256
+# define MEMCHR_SUBTRACT_VECTORS \
+ vsububm v4,v4,v18; \
+ vsububm v5,v5,v18; \
+ vsububm v6,v6,v18; \
+ vsububm v7,v7,v18;
+# define M_TAIL(vreg,increment) \
+ vctzlsbb r4,vreg; \
+ cmpld r5,r4; \
+ ble L(null); \
+ addi r4,r4,increment; \
+ add r3,r6,r4; \
+ blr
+
+/* TODO: Replace macros by the actual instructions when minimum binutils becomes
+ >= 2.35. This is used to keep compatibility with older versions. */
+#define M_VEXTRACTBM(rt,vrb) \
+ .long(((4)<<(32-6)) \
+ | ((rt)<<(32-11)) \
+ | ((8)<<(32-16)) \
+ | ((vrb)<<(32-21)) \
+ | 1602)
+
+#define M_LXVP(xtp,dq,ra) \
+ .long(((6)<<(32-6)) \
+ | ((((xtp)-32)>>1)<<(32-10)) \
+ | ((1)<<(32-11)) \
+ | ((ra)<<(32-16)) \
+ | dq)
+
+#define CHECK16B(vreg,offset,addr,label) \
+ lxv vreg+32,offset(addr); \
+ vcmpequb. vreg,vreg,v18; \
+ bne cr6,L(label); \
+ cmpldi r5,16; \
+ ble L(null); \
+ addi r5,r5,-16;
+
+/* Load 4 quadwords, merge into one VR for speed and check for NULLs. r6 has #
+ of bytes already checked. */
+#define CHECK64B(offset,addr,label) \
+ M_LXVP(v4+32,offset,addr); \
+ M_LXVP(v6+32,offset+32,addr); \
+ MEMCHR_SUBTRACT_VECTORS; \
+ vminub v14,v4,v5; \
+ vminub v15,v6,v7; \
+ vminub v16,v14,v15; \
+ vcmpequb. v0,v16,M_VREG_ZERO; \
+ beq cr6,$+12; \
+ li r7,offset; \
+ b L(label); \
+ cmpldi r5,64; \
+ ble L(null); \
+ addi r5,r5,-64
+
+/* Implements the function
+ void *[r3] memchr (const void *s [r3], int c [r4], size_t n [r5]). */
+
+ .machine power9
+
+ENTRY_TOCLESS (MEMCHR)
+ CALL_MCOUNT 3
+
+ cmpldi r5,0
+ beq L(null)
+ mr r0,r5
+ xori r6,r4,0xff
+
+ mtvsrd v18+32,r4 /* matching char in v18 */
+ mtvsrd v19+32,r6 /* non matching char in v19 */
+
+ vspltb v18,v18,7 /* replicate */
+ vspltb v19,v19,7 /* replicate */
+ vspltisb M_VREG_ZERO,0
+
+ /* Next 16B-aligned address. Prepare address for L(aligned). */
+ addi r6,r3,16
+ clrrdi r6,r6,4
+
+ /* Align data and fill bytes not loaded with non matching char. */
+ lvx v0,0,r3
+ lvsr v1,0,r3
+ vperm v0,v19,v0,v1
+
+ vcmpequb. v6,v0,v18
+ bne cr6,L(found)
+ sub r4,r6,r3
+ cmpld r5,r4
+ ble L(null)
+ sub r5,r5,r4
+
+ /* Test up to OFF_START_LOOP-16 bytes in 16B chunks. The main loop is
+ optimized for longer strings, so checking the first bytes in 16B
+ chunks benefits a lot small strings. */
+ .p2align 5
+L(aligned):
+ cmpldi r5,0
+ beq L(null)
+
+ CHECK16B(v0,0,r6,tail1)
+ CHECK16B(v1,16,r6,tail2)
+ CHECK16B(v2,32,r6,tail3)
+ CHECK16B(v3,48,r6,tail4)
+ CHECK16B(v4,64,r6,tail5)
+ CHECK16B(v5,80,r6,tail6)
+ CHECK16B(v6,96,r6,tail7)
+ CHECK16B(v7,112,r6,tail8)
+ CHECK16B(v8,128,r6,tail9)
+ CHECK16B(v9,144,r6,tail10)
+ CHECK16B(v10,160,r6,tail11)
+ CHECK16B(v0,176,r6,tail12)
+ CHECK16B(v1,192,r6,tail13)
+ CHECK16B(v2,208,r6,tail14)
+ CHECK16B(v3,224,r6,tail15)
+
+ cmpdi cr5,r4,0 /* Check if c == 0. This will be useful to
+ choose how we will perform the main loop. */
+
+ /* Prepare address for the loop. */
+ addi r4,r3,M_OFF_START_LOOP
+ clrrdi r4,r4,6
+ sub r6,r4,r3
+ sub r5,r0,r6
+ addi r6,r4,128
+
+ /* If c == 0, use the loop without the vsububm. */
+ beq cr5,L(loop)
+
+ /* This is very similar to the block after L(loop), the difference is
+ that here MEMCHR_SUBTRACT_VECTORS is not empty, and we subtract
+ each byte loaded by the char we are looking for, this way we can keep
+ using vminub to merge the results and checking for nulls. */
+ .p2align 5
+L(memchr_loop):
+ CHECK64B(0,r4,pre_tail_64b)
+ CHECK64B(64,r4,pre_tail_64b)
+ addi r4,r4,256
+
+ CHECK64B(0,r6,tail_64b)
+ CHECK64B(64,r6,tail_64b)
+ addi r6,r6,256
+
+ CHECK64B(0,r4,pre_tail_64b)
+ CHECK64B(64,r4,pre_tail_64b)
+ addi r4,r4,256
+
+ CHECK64B(0,r6,tail_64b)
+ CHECK64B(64,r6,tail_64b)
+ addi r6,r6,256
+
+ b L(memchr_loop)
+ /* Switch to a more aggressive approach checking 64B each time. Use 2
+ pointers 128B apart and unroll the loop once to make the pointer
+ updates and usages separated enough to avoid stalls waiting for
+ address calculation. */
+ .p2align 5
+L(loop):
+#undef MEMCHR_SUBTRACT_VECTORS
+#define MEMCHR_SUBTRACT_VECTORS /* nothing */
+ CHECK64B(0,r4,pre_tail_64b)
+ CHECK64B(64,r4,pre_tail_64b)
+ addi r4,r4,256
+
+ CHECK64B(0,r6,tail_64b)
+ CHECK64B(64,r6,tail_64b)
+ addi r6,r6,256
+
+ CHECK64B(0,r4,pre_tail_64b)
+ CHECK64B(64,r4,pre_tail_64b)
+ addi r4,r4,256
+
+ CHECK64B(0,r6,tail_64b)
+ CHECK64B(64,r6,tail_64b)
+ addi r6,r6,256
+
+ b L(loop)
+
+ .p2align 5
+L(pre_tail_64b):
+ mr r6,r4
+L(tail_64b):
+ /* OK, we found a null byte. Let's look for it in the current 64-byte
+ block and mark it in its corresponding VR. lxvp vx,0(ry) puts the
+ low 16B bytes into vx+1, and the high into vx, so the order here is
+ v5, v4, v7, v6. */
+ vcmpequb v1,v5,M_VREG_ZERO
+ vcmpequb v2,v4,M_VREG_ZERO
+ vcmpequb v3,v7,M_VREG_ZERO
+ vcmpequb v4,v6,M_VREG_ZERO
+
+ /* Take into account the other 64B blocks we had already checked. */
+ add r6,r6,r7
+ /* Extract first bit of each byte. */
+ M_VEXTRACTBM(r8,v1)
+ M_VEXTRACTBM(r9,v2)
+ M_VEXTRACTBM(r10,v3)
+ M_VEXTRACTBM(r11,v4)
+
+ /* Shift each value into their corresponding position. */
+ sldi r9,r9,16
+ sldi r10,r10,32
+ sldi r11,r11,48
+
+ /* Merge the results. */
+ or r8,r8,r9
+ or r9,r10,r11
+ or r11,r9,r8
+
+ cnttzd r0,r11 /* Count trailing zeros before the match. */
+ cmpld r5,r0
+ ble L(null)
+ add r3,r6,r0 /* Compute final address. */
+ blr
+
+ .p2align 5
+L(tail1):
+ M_TAIL(v0,0)
+
+ .p2align 5
+L(tail2):
+ M_TAIL(v1,16)
+
+ .p2align 5
+L(tail3):
+ M_TAIL(v2,32)
+
+ .p2align 5
+L(tail4):
+ M_TAIL(v3,48)
+
+ .p2align 5
+L(tail5):
+ M_TAIL(v4,64)
+
+ .p2align 5
+L(tail6):
+ M_TAIL(v5,80)
+
+ .p2align 5
+L(tail7):
+ M_TAIL(v6,96)
+
+ .p2align 5
+L(tail8):
+ M_TAIL(v7,112)
+
+ .p2align 5
+L(tail9):
+ M_TAIL(v8,128)
+
+ .p2align 5
+L(tail10):
+ M_TAIL(v9,144)
+
+ .p2align 5
+L(tail11):
+ M_TAIL(v10,160)
+
+ .p2align 5
+L(tail12):
+ M_TAIL(v0,176)
+
+ .p2align 5
+L(tail13):
+ M_TAIL(v1,192)
+
+ .p2align 5
+L(tail14):
+ M_TAIL(v2,208)
+
+ .p2align 5
+L(tail15):
+ M_TAIL(v3,224)
+
+ .p2align 5
+L(found):
+ vctzlsbb r7,v6
+ cmpld r5,r7
+ ble L(null)
+ add r3,r3,r7
+ blr
+
+ .p2align 5
+L(null):
+ li r3,0
+ blr
+
+END (MEMCHR)
+
+weak_alias (__memchr, memchr)
+libc_hidden_builtin_def (memchr)
diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
index 91ed88a9c716800d..b4251932de1854c2 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
+++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
@@ -31,10 +31,10 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
strncase-power8
ifneq (,$(filter %le,$(config-machine)))
-sysdep_routines += memcmp-power10 memcpy-power10 memmove-power10 memset-power10 \
- rawmemchr-power9 rawmemchr-power10 \
- strcmp-power9 strcmp-power10 strncmp-power9 \
- strcpy-power9 stpcpy-power9 \
+sysdep_routines += memchr-power10 memcmp-power10 memcpy-power10 \
+ memmove-power10 memset-power10 rawmemchr-power9 \
+ rawmemchr-power10 strcmp-power9 strcmp-power10 \
+ strncmp-power9 strcpy-power9 stpcpy-power9 \
strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10
endif
CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
index caec2047ab10d209..e8a38fd4d5e1357e 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
@@ -265,6 +265,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
/* Support sysdeps/powerpc/powerpc64/multiarch/memchr.c. */
IFUNC_IMPL (i, name, memchr,
+#ifdef __LITTLE_ENDIAN__
+ IFUNC_IMPL_ADD (array, i, memchr,
+ hwcap2 & PPC_FEATURE2_ARCH_3_1
+ && hwcap & PPC_FEATURE_HAS_VSX,
+ __memchr_power10)
+#endif
IFUNC_IMPL_ADD (array, i, memchr,
hwcap2 & PPC_FEATURE2_ARCH_2_07
&& hwcap & PPC_FEATURE_HAS_ALTIVEC,
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memchr-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memchr-power10.S
new file mode 100644
index 0000000000000000..b9ed7926762e2b6f
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/multiarch/memchr-power10.S
@@ -0,0 +1,28 @@
+/* Optimized memchr implementation for POWER10/PPC64.
+ Copyright (C) 2016-2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
+#define MEMCHR __memchr_power10
+
+#undef libc_hidden_builtin_def
+#define libc_hidden_builtin_def(name)
+#undef weak_alias
+#define weak_alias(name,alias)
+
+#include <sysdeps/powerpc/powerpc64/le/power10/memchr.S>
+#endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memchr.c b/sysdeps/powerpc/powerpc64/multiarch/memchr.c
index f40013e06113096f..389d5f18683c2dfc 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memchr.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/memchr.c
@@ -25,15 +25,23 @@ extern __typeof (__memchr) __memchr_ppc attribute_hidden;
extern __typeof (__memchr) __memchr_power7 attribute_hidden;
extern __typeof (__memchr) __memchr_power8 attribute_hidden;
+# ifdef __LITTLE_ENDIAN__
+extern __typeof (__memchr) __memchr_power10 attribute_hidden;
+# endif
/* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
ifunc symbol properly. */
libc_ifunc (__memchr,
- (hwcap2 & PPC_FEATURE2_ARCH_2_07
- && hwcap & PPC_FEATURE_HAS_ALTIVEC)
- ? __memchr_power8 :
- (hwcap & PPC_FEATURE_ARCH_2_06)
- ? __memchr_power7
- : __memchr_ppc);
+# ifdef __LITTLE_ENDIAN__
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1
+ && hwcap & PPC_FEATURE_HAS_VSX)
+ ? __memchr_power10 :
+# endif
+ (hwcap2 & PPC_FEATURE2_ARCH_2_07
+ && hwcap & PPC_FEATURE_HAS_ALTIVEC)
+ ? __memchr_power8 :
+ (hwcap & PPC_FEATURE_ARCH_2_06)
+ ? __memchr_power7
+ : __memchr_ppc);
weak_alias (__memchr, memchr)
libc_hidden_builtin_def (memchr)

View File

@ -0,0 +1,218 @@
commit 90bcc8721ef82b7378d2b080141228660e862d56
Author: Amrita H S <amritahs@linux.vnet.ibm.com>
Date: Fri Dec 15 11:48:17 2023 -0500
powerpc: Fix performance issues of strcmp power10
Current implementation of strcmp for power10 has
performance regression for multiple small sizes
and alignment combination.
Most of these performance issues are fixed by this
patch. The compare loop is unrolled and page crosses
of unrolled loop is handled.
Thanks to Paul E. Murphy for helping in fixing the
performance issues.
Signed-off-by: Amrita H S <amritahs@linux.vnet.ibm.com>
Co-Authored-By: Paul E. Murphy <murphyp@linux.ibm.com>
Reviewed-by: Rajalakshmi Srinivasaraghavan <rajis@linux.ibm.com>
diff --git a/sysdeps/powerpc/powerpc64/le/power10/strcmp.S b/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
index a3c1adad539978e0..3406f4f26a214270 100644
--- a/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
+++ b/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
@@ -62,7 +62,7 @@
lxvl 32+v5,reg2,r0; \
add reg1,reg1,len_reg; \
add reg2,reg2,len_reg; \
- vcmpnezb. v7,v4,v5; \
+ vcmpnezb v7,v4,v5; \
vctzlsbb r6,v7; \
cmpld cr7,r6,len_reg; \
blt cr7,L(different); \
@@ -72,70 +72,110 @@
.machine power9
ENTRY_TOCLESS (STRCMP, 4)
- li r11,16
- /* eq bit of cr1 used as swap status flag to indicate if
- source pointers were swapped. */
- crclr 4*cr1+eq
- vspltisb v19,-1
- andi. r7,r3,15
- sub r7,r11,r7 /* r7(nalign1) = 16 - (str1 & 15). */
- andi. r9,r4,15
- sub r5,r11,r9 /* r5(nalign2) = 16 - (str2 & 15). */
- cmpld cr7,r7,r5
- beq cr7,L(same_aligned)
- blt cr7,L(nalign1_min)
- /* Swap r3 and r4, and r7 and r5 such that r3 and r7 hold the
- pointer which is closer to the next 16B boundary so that only
- one CHECK_N_BYTES is needed before entering the loop below. */
- mr r8,r4
- mr r4,r3
- mr r3,r8
- mr r12,r7
- mr r7,r5
- mr r5,r12
- crset 4*cr1+eq /* Set bit on swapping source pointers. */
+ andi. r7,r3,4095
+ andi. r8,r4,4095
+ cmpldi cr0,r7,4096-16
+ cmpldi cr1,r8,4096-16
+ bgt cr0,L(crosses)
+ bgt cr1,L(crosses)
+ COMPARE_16(v4,v5,0)
- .p2align 5
+L(crosses):
+ andi. r7,r3,15
+ subfic r7,r7,16 /* r7(nalign1) = 16 - (str1 & 15). */
+ andi. r9,r4,15
+ subfic r5,r9,16 /* r5(nalign2) = 16 - (str2 & 15). */
+ cmpld cr7,r7,r5
+ beq cr7,L(same_aligned)
+ blt cr7,L(nalign1_min)
+
+ /* nalign2 is minimum and s2 pointer is aligned. */
+ CHECK_N_BYTES(r3,r4,r5)
+ /* Are we on the 64B hunk which crosses a page? */
+ andi. r10,r3,63 /* Determine offset into 64B hunk. */
+ andi. r8,r3,15 /* The offset into the 16B hunk. */
+ neg r7,r3
+ andi. r9,r7,15 /* Number of bytes after a 16B cross. */
+ rlwinm. r7,r7,26,0x3F /* ((r3-4096))>>6&63. */
+ beq L(compare_64_pagecross)
+ mtctr r7
+ b L(compare_64B_unaligned)
+
+ /* nalign1 is minimum and s1 pointer is aligned. */
L(nalign1_min):
CHECK_N_BYTES(r3,r4,r7)
+ /* Are we on the 64B hunk which crosses a page? */
+ andi. r10,r4,63 /* Determine offset into 64B hunk. */
+ andi. r8,r4,15 /* The offset into the 16B hunk. */
+ neg r7,r4
+ andi. r9,r7,15 /* Number of bytes after a 16B cross. */
+ rlwinm. r7,r7,26,0x3F /* ((r4-4096))>>6&63. */
+ beq L(compare_64_pagecross)
+ mtctr r7
.p2align 5
-L(s1_aligned):
- /* r9 and r5 is number of bytes to be read after and before
- page boundary correspondingly. */
- sub r5,r5,r7
- subfic r9,r5,16
- /* Now let r7 hold the count of quadwords which can be
- checked without crossing a page boundary. quadword offset is
- (str2>>4)&0xFF. */
- rlwinm r7,r4,28,0xFF
- /* Below check is required only for first iteration. For second
- iteration and beyond, the new loop counter is always 255. */
- cmpldi r7,255
- beq L(L3)
- /* Get the initial loop count by 255-((str2>>4)&0xFF). */
- subfic r11,r7,255
+L(compare_64B_unaligned):
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ COMPARE_16(v4,v5,32)
+ COMPARE_16(v4,v5,48)
+ addi r3,r3,64
+ addi r4,r4,64
+ bdnz L(compare_64B_unaligned)
- .p2align 5
-L(L1):
+ /* Cross the page boundary of s2, carefully. Only for first
+ iteration we have to get the count of 64B blocks to be checked.
+ From second iteration and beyond, loop counter is always 63. */
+L(compare_64_pagecross):
+ li r11, 63
mtctr r11
-
- .p2align 5
-L(L2):
- COMPARE_16(v4,v5,0) /* Load 16B blocks using lxv. */
+ cmpldi r10,16
+ ble L(cross_4)
+ cmpldi r10,32
+ ble L(cross_3)
+ cmpldi r10,48
+ ble L(cross_2)
+L(cross_1):
+ CHECK_N_BYTES(r3,r4,r9)
+ CHECK_N_BYTES(r3,r4,r8)
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ COMPARE_16(v4,v5,32)
+ addi r3,r3,48
+ addi r4,r4,48
+ b L(compare_64B_unaligned)
+L(cross_2):
+ COMPARE_16(v4,v5,0)
addi r3,r3,16
addi r4,r4,16
- bdnz L(L2)
- /* Cross the page boundary of s2, carefully. */
-
- .p2align 5
-L(L3):
- CHECK_N_BYTES(r3,r4,r5)
CHECK_N_BYTES(r3,r4,r9)
- li r11,255 /* Load the new loop counter. */
- b L(L1)
+ CHECK_N_BYTES(r3,r4,r8)
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ addi r3,r3,32
+ addi r4,r4,32
+ b L(compare_64B_unaligned)
+L(cross_3):
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ addi r3,r3,32
+ addi r4,r4,32
+ CHECK_N_BYTES(r3,r4,r9)
+ CHECK_N_BYTES(r3,r4,r8)
+ COMPARE_16(v4,v5,0)
+ addi r3,r3,16
+ addi r4,r4,16
+ b L(compare_64B_unaligned)
+L(cross_4):
+ COMPARE_16(v4,v5,0)
+ COMPARE_16(v4,v5,16)
+ COMPARE_16(v4,v5,32)
+ addi r3,r3,48
+ addi r4,r4,48
+ CHECK_N_BYTES(r3,r4,r9)
+ CHECK_N_BYTES(r3,r4,r8)
+ b L(compare_64B_unaligned)
- .p2align 5
L(same_aligned):
CHECK_N_BYTES(r3,r4,r7)
/* Align s1 to 32B and adjust s2 address.
@@ -168,18 +208,7 @@ L(16B_aligned_loop):
/* Calculate and return the difference. */
L(different):
- vctzlsbb r6,v7
- vextubrx r5,r6,v4
- vextubrx r4,r6,v5
- bt 4*cr1+eq,L(swapped)
- subf r3,r4,r5
- blr
-
- /* If src pointers were swapped, then swap the
- indices and calculate the return value. */
-L(swapped):
- subf r3,r5,r4
- blr
+ TAIL(v4,v5)
.p2align 5
L(32B_aligned_loop):

View File

@ -0,0 +1,69 @@
commit f942a732d37a96217ef828116ebe64a644db18d7
Author: Joe Talbott <joetalbott@gmail.com>
Date: Tue May 14 14:39:38 2024 +0000
math: Add GLIBC_TEST_LIBM_VERBOSE environment variable support.
Allow the libm-test-driver based tests to have their verbosity set based
on the GLIBC_TEST_LIBM_VERBOSE environment variable. This allows the entire
testsuite to be run with a non-default verbosity.
While here check the conversion for the verbose option as well.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/math/libm-test-support.c b/math/libm-test-support.c
index 9b4cb2ee7d072578..9e64dcfc99234bc7 100644
--- a/math/libm-test-support.c
+++ b/math/libm-test-support.c
@@ -130,7 +130,7 @@ static int noTests; /* number of tests (without testing exceptions) */
static int noExcTests; /* number of tests for exception flags */
static int noErrnoTests;/* number of tests for errno values */
-static int verbose;
+static unsigned int verbose;
static int output_max_error; /* Should the maximal errors printed? */
static int output_points; /* Should the single function results printed? */
static int ignore_max_ulp; /* Should we ignore max_ulp? */
@@ -1057,7 +1057,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'v':
if (optarg)
- verbose = (unsigned int) strtoul (optarg, NULL, 0);
+ {
+ char *optstr_conv = optarg;
+ unsigned int opt_verbose;
+
+ opt_verbose = (unsigned int) strtoul (optarg, &optstr_conv, 0);
+ if (*optstr_conv == '\0' && optstr_conv != optarg)
+ verbose = opt_verbose;
+ }
else
verbose = 3;
break;
@@ -1139,6 +1146,7 @@ libm_test_init (int argc, char **argv)
int remaining;
char *ulps_file_path;
size_t dir_len = 0;
+ char *envstr_verbose;
verbose = 1;
output_ulps = 0;
@@ -1148,6 +1156,17 @@ libm_test_init (int argc, char **argv)
/* XXX set to 0 for releases. */
ignore_max_ulp = 0;
+ envstr_verbose = getenv("GLIBC_TEST_LIBM_VERBOSE");
+ if (envstr_verbose != NULL)
+ {
+ char *envstr_conv = envstr_verbose;
+ unsigned int env_verbose;
+
+ env_verbose = (unsigned int) strtoul (envstr_verbose, &envstr_conv, 0);
+ if (*envstr_conv == '\0' && envstr_conv != envstr_verbose)
+ verbose = env_verbose;
+ }
+
/* Parse and process arguments. */
argp_parse (&argp, argc, argv, 0, &remaining, NULL);

View File

@ -0,0 +1,529 @@
commit ae18044f95271ed422ed847bd8d8c6d8e84674ce
Author: Joe Simmons-Talbott <josimmon@redhat.com>
Date: Mon May 20 14:09:35 2024 +0000
math: Add more details to the test driver output.
Add start and end indicators that identify the test being run in the
verbose output. Better identify the tests for max errors in the
summary output. Count each exception checked for each test. Remove
double counting of tests for the check_<type> functions other than
check_float_internal. Rename print_max_error and
print_complex_max_error to check_max_error and check_complex_max_error
respectively since they have side effects.
Co-Authored-By: Carlos O'Donell <carlos@redhat.com>
Reviewed-By: Joseph Myers <josmyers@redhat.com>
diff --git a/math/libm-test-driver.c b/math/libm-test-driver.c
index 0a430a86067766e3..5448ea2109a264b7 100644
--- a/math/libm-test-driver.c
+++ b/math/libm-test-driver.c
@@ -1059,9 +1059,9 @@ struct test_Ff_b1_data
= STR_CON3 (FUN, SUFF, TEST_SUFF) TEST_SUFF_STR; \
init_max_error (this_func, EXACT, TEST_COND_any_ibm128)
#define END \
- print_max_error (this_func)
+ check_max_error (this_func)
#define END_COMPLEX \
- print_complex_max_error (this_func)
+ check_complex_max_error (this_func)
/* Run tests for a given function in all rounding modes. */
#define ALL_RM_TEST(FUNC, EXACT, ARRAY, LOOP_MACRO, END_MACRO, ...) \
diff --git a/math/libm-test-support.c b/math/libm-test-support.c
index 9e64dcfc99234bc7..5cf5aa5df2cacb24 100644
--- a/math/libm-test-support.c
+++ b/math/libm-test-support.c
@@ -112,6 +112,7 @@
#include <argp.h>
#include <errno.h>
#include <string.h>
+#include <assert.h>
/* This header defines func_ulps, func_real_ulps and func_imag_ulps
arrays. */
@@ -125,10 +126,13 @@ static FILE *ulps_file; /* File to document difference. */
static int output_ulps; /* Should ulps printed? */
static char *output_dir; /* Directory where generated files will be written. */
-static int noErrors; /* number of errors */
-static int noTests; /* number of tests (without testing exceptions) */
-static int noExcTests; /* number of tests for exception flags */
-static int noErrnoTests;/* number of tests for errno values */
+#define TEST_INPUT 1
+#define TEST_MAXERROR 2
+static int noErrors; /* number of errors */
+static int noTests; /* number of tests (without testing exceptions) */
+static int noMaxErrorTests; /* number of max error tests */
+static int noExcTests; /* number of tests for exception flags */
+static int noErrnoTests; /* number of tests for errno values */
static unsigned int verbose;
static int output_max_error; /* Should the maximal errors printed? */
@@ -299,9 +303,19 @@ print_screen_max_error (int ok)
/* Update statistic counters. */
static void
-update_stats (int ok)
+update_stats (int ok, int testType)
{
- ++noTests;
+ switch (testType)
+ {
+ case TEST_INPUT:
+ ++noTests;
+ break;
+ case TEST_MAXERROR:
+ ++noMaxErrorTests;
+ break;
+ default:
+ abort();
+ }
if (!ok)
++noErrors;
}
@@ -367,11 +381,30 @@ fpstack_test (const char *test_name)
#endif
}
+static void
+print_test_start (int test_num, const char *test_name, int test_type)
+{
+ if (print_screen (1))
+ printf ("--- Start of%s test # %d, named \"%s\" ---\n",
+ test_type == TEST_MAXERROR ? " max error" : "", test_num, test_name);
+}
+static void
+print_test_end (int test_num, const char *test_name, int test_type)
+{
+ if (print_screen (1))
+ printf ("--- End of%s test # %d, named \"%s\" ---\n",
+ test_type == TEST_MAXERROR ? " max error" : "", test_num, test_name);
+}
+
+/* This is a builtin test of overall max error. */
void
-print_max_error (const char *func_name)
+check_max_error (const char *func_name)
{
int ok = 0;
+ int thisTest = noMaxErrorTests;
+
+ print_test_start (thisTest, func_name, TEST_MAXERROR);
if (max_error == 0.0 || (max_error <= prev_max_error && !ignore_max_ulp))
{
@@ -392,14 +425,19 @@ print_max_error (const char *func_name)
printf (" accepted: %s ulp\n", pmestr);
}
- update_stats (ok);
-}
+ update_stats (ok, TEST_MAXERROR);
+ print_test_end (thisTest, func_name, TEST_MAXERROR);
+}
+/* This is a builtin test of overall max error. */
void
-print_complex_max_error (const char *func_name)
+check_complex_max_error (const char *func_name)
{
int real_ok = 0, imag_ok = 0, ok;
+ int thisTest = noMaxErrorTests;
+
+ print_test_start (thisTest, func_name, TEST_MAXERROR);
if (real_max_error == 0
|| (real_max_error <= prev_real_max_error && !ignore_max_ulp))
@@ -436,7 +474,8 @@ print_complex_max_error (const char *func_name)
printf (" accepted: %s ulp\n", pimestr);
}
- update_stats (ok);
+ update_stats (ok, TEST_MAXERROR);
+ print_test_end (thisTest, func_name, TEST_MAXERROR);
}
@@ -477,12 +516,13 @@ test_single_exception (const char *test_name,
else
{
if (print_screen (1))
- printf ("%s: Exception \"%s\" not set\n", test_name,
+ printf ("Pass: %s: Exception \"%s\" not set\n", test_name,
flag_name);
}
}
if (!ok)
++noErrors;
+ ++noExcTests;
}
#endif
@@ -494,23 +534,32 @@ test_exceptions (const char *test_name, int exception)
{
if (flag_test_exceptions && EXCEPTION_TESTS (FLOAT))
{
- ++noExcTests;
+ int ran = 0;
#ifdef FE_DIVBYZERO
if ((exception & DIVIDE_BY_ZERO_EXCEPTION_OK) == 0)
- test_single_exception (test_name, exception,
- DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO,
- "Divide by zero");
+ {
+ test_single_exception (test_name, exception,
+ DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO,
+ "Divide by zero");
+ ran = 1;
+ }
#endif
#ifdef FE_INVALID
if ((exception & INVALID_EXCEPTION_OK) == 0)
- test_single_exception (test_name, exception,
- INVALID_EXCEPTION, FE_INVALID,
- "Invalid operation");
+ {
+ test_single_exception (test_name, exception,
+ INVALID_EXCEPTION, FE_INVALID,
+ "Invalid operation");
+ ran = 1;
+ }
#endif
#ifdef FE_OVERFLOW
if ((exception & OVERFLOW_EXCEPTION_OK) == 0)
- test_single_exception (test_name, exception, OVERFLOW_EXCEPTION,
- FE_OVERFLOW, "Overflow");
+ {
+ test_single_exception (test_name, exception, OVERFLOW_EXCEPTION,
+ FE_OVERFLOW, "Overflow");
+ ran = 1;
+ }
#endif
/* Spurious "underflow" and "inexact" exceptions are always
allowed for IBM long double, in line with the underlying
@@ -519,17 +568,30 @@ test_exceptions (const char *test_name, int exception)
if ((exception & UNDERFLOW_EXCEPTION_OK) == 0
&& !(test_ibm128
&& (exception & UNDERFLOW_EXCEPTION) == 0))
- test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION,
- FE_UNDERFLOW, "Underflow");
+ {
+ test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION,
+ FE_UNDERFLOW, "Underflow");
+ ran = 1;
+ }
+
#endif
#ifdef FE_INEXACT
if ((exception & (INEXACT_EXCEPTION | NO_INEXACT_EXCEPTION)) != 0
&& !(test_ibm128
&& (exception & NO_INEXACT_EXCEPTION) != 0))
- test_single_exception (test_name, exception, INEXACT_EXCEPTION,
- FE_INEXACT, "Inexact");
+ {
+ test_single_exception (test_name, exception, INEXACT_EXCEPTION,
+ FE_INEXACT, "Inexact");
+ ran = 1;
+ }
#endif
+ assert (ran == 1);
}
+ else
+ {
+ if (print_screen (1))
+ printf ("Info: %s: No exceptions tested\n", test_name);
+ }
feclearexcept (FE_ALL_EXCEPT);
}
@@ -552,6 +614,7 @@ test_single_errno (const char *test_name, int errno_value,
printf ("Failure: %s: errno set to %d, expected %d (%s)\n",
test_name, errno_value, expected_value, expected_name);
}
+ ++noErrnoTests;
}
/* Test whether errno (value ERRNO_VALUE) has been for TEST_NAME set
@@ -561,13 +624,39 @@ test_errno (const char *test_name, int errno_value, int exceptions)
{
if (flag_test_errno)
{
- ++noErrnoTests;
+ int ran = 0;
+
+ if ((exceptions & (ERRNO_UNCHANGED|ERRNO_EDOM|ERRNO_ERANGE)) == 0)
+ {
+ if (print_screen (1))
+ printf ("Info: %s: The value of errno was not tested\n",
+ test_name);
+ return;
+ }
+
+
if (exceptions & ERRNO_UNCHANGED)
- test_single_errno (test_name, errno_value, 0, "unchanged");
+ {
+ test_single_errno (test_name, errno_value, 0, "unchanged");
+ ran = 1;
+ }
if (exceptions & ERRNO_EDOM)
- test_single_errno (test_name, errno_value, EDOM, "EDOM");
+ {
+ test_single_errno (test_name, errno_value, EDOM, "EDOM");
+ ran = 1;
+ }
if (exceptions & ERRNO_ERANGE)
- test_single_errno (test_name, errno_value, ERANGE, "ERANGE");
+ {
+ test_single_errno (test_name, errno_value, ERANGE, "ERANGE");
+ ran = 1;
+ }
+
+ assert (ran == 1);
+ }
+ else
+ {
+ if (print_screen (1))
+ printf ("Info: %s: No errno tests\n", test_name);
}
}
@@ -619,6 +708,9 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
FLOAT diff = 0;
FLOAT ulps = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
@@ -716,12 +808,13 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
printf (" max.ulp : %s\n", mustrn);
}
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -776,12 +869,14 @@ check_int (const char *test_name, int computed, int expected,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -795,11 +890,12 @@ check_int (const char *test_name, int computed, int expected,
printf (" should be: %d\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -810,12 +906,14 @@ check_long (const char *test_name, long int computed, long int expected,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -829,11 +927,12 @@ check_long (const char *test_name, long int computed, long int expected,
printf (" should be: %ld\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -844,12 +943,14 @@ check_bool (const char *test_name, int computed, int expected,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if ((computed == 0) == (expected == 0))
ok = 1;
@@ -863,11 +964,12 @@ check_bool (const char *test_name, int computed, int expected,
printf (" should be: %d\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -879,12 +981,14 @@ check_longlong (const char *test_name, long long int computed,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -898,11 +1002,12 @@ check_longlong (const char *test_name, long long int computed,
printf (" should be: %lld\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -913,12 +1018,14 @@ check_intmax_t (const char *test_name, intmax_t computed,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -932,11 +1039,12 @@ check_intmax_t (const char *test_name, intmax_t computed,
printf (" should be: %jd\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -947,12 +1055,14 @@ check_uintmax_t (const char *test_name, uintmax_t computed,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -966,11 +1076,12 @@ check_uintmax_t (const char *test_name, uintmax_t computed,
printf (" should be: %ju\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
/* Return whether a test with flags EXCEPTIONS should be run. */
@@ -1211,9 +1322,11 @@ libm_test_finish (void)
fclose (ulps_file);
printf ("\nTest suite completed:\n");
- printf (" %d test cases plus %d tests for exception flags and\n"
- " %d tests for errno executed.\n",
- noTests, noExcTests, noErrnoTests);
+ printf (" %d max error test cases,\n", noMaxErrorTests);
+ printf (" %d input tests,\n", noTests);
+ printf (" - with %d tests for exception flags,\n", noExcTests);
+ printf (" - with %d tests for errno executed.\n", noErrnoTests);
+
if (noErrors)
{
printf (" %d errors occurred.\n", noErrors);
diff --git a/math/libm-test-support.h b/math/libm-test-support.h
index ba670014548e73eb..e6f03ee154e7a65d 100644
--- a/math/libm-test-support.h
+++ b/math/libm-test-support.h
@@ -170,8 +170,8 @@ extern const char doc[];
int enable_test (int);
void init_max_error (const char *, int, int);
-void print_max_error (const char *);
-void print_complex_max_error (const char *);
+void check_max_error (const char *);
+void check_complex_max_error (const char *);
void check_float (const char *, FLOAT, FLOAT, int);
void check_complex (const char *, CFLOAT, CFLOAT, int);
void check_int (const char *, int, int, int);

View File

@ -0,0 +1,320 @@
From 3de73f974fab55430177c811c9c9ba3f251d5747 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Wed, 7 Aug 2024 14:57:41 +0200
Subject: manual: Add Descriptor-Relative Access section
Reference this new section from the O_PATH documentation.
And document the functions openat, openat64, fstatat, fstatat64.
(The safety assessment for fstatat was already obsolete because
current glibc assumes kernel support for the underlying system
call.)
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/manual/filesys.texi b/manual/filesys.texi
index 47d929744e..aabb68385b 100644
--- a/manual/filesys.texi
+++ b/manual/filesys.texi
@@ -15,6 +15,7 @@ access permissions and modification times.
@menu
* Working Directory:: This is used to resolve relative
file names.
+* Descriptor-Relative Access:: Ways to control file name lookup.
* Accessing Directories:: Finding out what files a directory
contains.
* Working with Directory Trees:: Apply actions to all files or a selectable
@@ -206,6 +207,151 @@ An I/O error occurred.
@end table
@end deftypefun
+@node Descriptor-Relative Access
+@section Descriptor-Relative Access
+@cindex file name resolution based on descriptors
+@cindex descriptor-based file name resolution
+@cindex @code{@dots{}at} functions
+
+Many functions that accept file names have @code{@dots{}at} variants
+which accept a file descriptor and a file name argument instead of just
+a file name argument. For example, @code{fstatat} is the
+descriptor-based variant of the @code{fstat} function. Most such
+functions also accept an additional flags argument which changes the
+behavior of the file name lookup based on the passed @code{AT_@dots{}}
+flags.
+
+There are several reasons to use descriptor-relative access:
+
+@itemize @bullet
+@item
+The working directory is a process-wide resource, so individual threads
+cannot change it without affecting other threads in the process.
+Explicitly specifying the directory against which relative paths are
+resolved can be a thread-safe alternative to changing the working
+directory.
+
+@item
+If a program wishes to access a directory tree which is being modified
+concurrently, perhaps even by a different user on the system, the
+program must avoid looking up file names with multiple components, in
+order to detect symbolic links, using the @code{O_NOFOLLOW} flag
+(@pxref{Open-time Flags}) or the @code{AT_SYMLINK_FOLLOW} flag
+(described below). Without directory-relative access, it is necessary
+to use the @code{fchdir} function to change the working directory
+(@pxref{Working Directory}), which is not thread-safe.
+
+@item
+Listing directory contents using the @code{readdir} or @code{readdir64}
+functions (@pxref{Reading/Closing Directory}) does not provide full file
+name paths. Using @code{@dots{}at} functions, it is possible to use the
+file names directly, without having to construct such full paths.
+
+@item
+Additional flags available with some of the @code{@dots{}at} functions
+provide access to functionality which is not available otherwise.
+@end itemize
+
+The file descriptor used by these @code{@dots{}at} functions has the
+following uses:
+
+@itemize @bullet
+@item
+It can be a file descriptor referring to a directory. Such a descriptor
+can be created explicitly using the @code{open} function and the
+@code{O_RDONLY} file access mode, with or without the @code{O_DIRECTORY}
+flag. @xref{Opening and Closing Files}. Or it can be created
+implicitly by @code{opendir} and retrieved using the @code{dirfd}
+function. @xref{Opening a Directory}.
+
+If a directory descriptor is used with one of the @code{@dots{}at}
+functions, a relative file name argument is resolved relative to
+directory referred to by the file descriptor, just as if that directory
+were the current working directory. Absolute file name arguments
+(starting with @samp{/}) are resolved against the file system root, and
+the descriptor argument is effectively ignored.
+
+This means that file name lookup is not constrained to the directory of
+the descriptor. For example, it is possible to access a file
+@file{example} in the descriptor's parent directory using a file name
+argument @code{"../example"}, or in the root directory using
+@code{"/example"}.
+
+If the file descriptor refers to a directory, the empty string @code{""}
+is not a valid file name argument. It is possible to use @code{"."} to
+refer to the directory itself. Also see @code{AT_EMPTY_PATH} below.
+
+@item
+@vindex @code{AT_FDCWD}
+The special value @code{AT_FDCWD}. This means that the current working
+directory is used for the lookup if the file name is a relative. For
+@code{@dots{}at} functions with an @code{AT_@dots{}} flags argument,
+this provides a shortcut to use those flags with regular (not
+descriptor-based) file name lookups.
+
+If @code{AT_FDCWD} is used, the empty string @code{""} is not a valid
+file name argument.
+
+@item
+An arbitrary file descriptor, along with an empty string @code{""} as
+the file name argument, and the @code{AT_EMPTY_PATH} flag. In this
+case, the operation uses the file descriptor directly, without further
+file name resolution. On Linux, this allows operations on descriptors
+opened with the @code{O_PATH} flag. For regular descriptors (opened
+without @code{O_PATH}), the same functionality is also available through
+the plain descriptor-based functions (for example, @code{fstat} instead
+of @code{fstatat}).
+
+This is a GNU extension.
+@end itemize
+
+@cindex file name resolution flags
+@cindex @code{AT_*} file name resolution flags
+The flags argument in @code{@dots{}at} functions can be a combination of
+the following flags, defined in @file{fcntl.h}. Not all such functions
+support all flags, and some (such as @code{openat}) do not accept a
+flags argument at all.
+
+In the flag descriptions below, the @dfn{effective final path component}
+refers to the final component (basename) of the full path constructed
+from the descriptor and file name arguments, using file name lookup, as
+described above.
+
+@vtable @code
+@item AT_EMPTY_PATH
+This flag is used with an empty file name @code{""} and a descriptor
+which does not necessarily refer to a directory. It is most useful with
+@code{O_PATH} descriptors, as described above. This flag is a GNU
+extension.
+
+@item AT_NO_AUTOMOUNT
+If the effective final path component refers to a potential file system
+mount point controlled by an auto-mounting service, the operation does
+not trigger auto-mounting and refers to the unmounted mount point
+instead. @xref{Mount-Unmount-Remount}. If a file system has already
+been mounted at the effective final path component, the operation
+applies to the file or directory in the mounted file system, not the
+underlying file system that was mounted over. This flag is a GNU
+extension.
+
+@item AT_SYMLINK_FOLLOW
+If the effective final path component is a symbolic link, the
+operation follows the symbolic link and operates on its target. (For
+most functions, this is the default behavior.)
+
+@item AT_SYMLINK_NOFOLLOW
+If the effective final path component is a symbolic link, the
+operation operates on the symbolic link, without following it. The
+difference in behavior enabled by this flag is similar to the difference
+between the @code{lstat} and @code{stat} functions, or the behavior
+activated by the @code{O_NOFOLLOW} argument to the @code{open} function.
+Even with the @code{AT_SYMLINK_NOFOLLOW} flag present, symbolic links in
+a non-final component of the file name are still followed.
+@end vtable
+
+@strong{Note:} There is no relationship between these flags and the type
+argument to the @code{getauxval} function (with @code{AT_@dots{}}
+constants defined in @file{elf.h}). @xref{Auxiliary Vector}.
@node Accessing Directories
@section Accessing Directories
@@ -1250,10 +1396,11 @@ A hardware error occurred while trying to read or write the to filesystem.
The @code{linkat} function is analogous to the @code{link} function,
except that it identifies its source and target using a combination of a
-file descriptor (referring to a directory) and a pathname. If a
-pathnames is not absolute, it is resolved relative to the corresponding
-file descriptor. The special file descriptor @code{AT_FDCWD} denotes
-the current directory.
+file descriptor (referring to a directory) and a file name.
+@xref{Descriptor-Relative Access}. For @code{linkat}, if a file name is
+not absolute, it is resolved relative to the corresponding file
+descriptor. As usual, the special value @code{AT_FDCWD} denotes the
+current directory.
The @var{flags} argument is a combination of the following flags:
@@ -2091,9 +2238,44 @@ function is available under the name @code{fstat} and so transparently
replaces the interface for small files on 32-bit machines.
@end deftypefun
-@c fstatat will call alloca and snprintf if the syscall is not
-@c available.
-@c @safety{@mtsafe{}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
+@deftypefun int fstatat (int @var{filedes}, const char *@var{filename}, struct stat *@var{buf}, int @var{flags})
+@standards{POSIX.1, sys/stat.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function is a descriptor-relative version of the @code{fstat}
+function above. @xref{Descriptor-Relative Access}. The @var{flags}
+argument can contain a combination of the flags @code{AT_EMPTY_PATH},
+@code{AT_NO_AUTOMOUNT}, @code{AT_SYMLINK_NOFOLLOW}.
+
+Compared to @code{fstat}, the following additional error conditions can
+occur:
+
+@table @code
+@item EBADF
+The @var{filedes} argument is not a valid file descriptor.
+
+@item EINVAL
+The @var{flags} argument is not valid for this function.
+
+@item ENOTDIR
+The descriptor @var{filedes} is not associated with a directory, and
+@var{filename} is a relative file name.
+@end table
+
+When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} this
+function is in fact @code{fstatat64} since the LFS interface transparently
+replaces the normal implementation.
+@end deftypefun
+
+@deftypefun int fstatat64 (int @var{filedes}, const char *@var{filename}, struct stat64 *@var{buf}, int @var{flags})
+@standards{GNU, sys/stat.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function is the large-file variant of @code{fstatat}, similar to
+how @code{fstat64} is the variant of @code{fstat}.
+
+When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} this
+function is available under the name @code{fstatat} and so transparently
+replaces the interface for small files on 32-bit machines.
+@end deftypefun
@deftypefun int lstat (const char *@var{filename}, struct stat *@var{buf})
@standards{BSD, sys/stat.h}
diff --git a/manual/llio.texi b/manual/llio.texi
index ea84196abd..a035c3e20f 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -181,6 +181,43 @@ new, extended API using 64 bit file sizes and offsets transparently
replaces the old API.
@end deftypefun
+@deftypefun int openat (int @var{filedes}, const char *@var{filename}, int @var{flags}[, mode_t @var{mode}])
+@standards{POSIX.1, fcntl.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
+This function is the descriptor-relative variant of the @code{open}
+function. @xref{Descriptor-Relative Access}.
+
+Note that the @var{flags} argument of @code{openat} does not accept
+@code{AT_@dots{}} flags, only the flags described for the @code{open}
+function above.
+
+The @code{openat} function can fail for additional reasons:
+
+@table @code
+@item EBADF
+The @var{filedes} argument is not a valid file descriptor.
+
+@item ENOTDIR
+The descriptor @var{filedes} is not associated with a directory, and
+@var{filename} is a relative file name.
+@end table
+
+When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} this
+function is in fact @code{openat64} since the LFS interface transparently
+replaces the normal implementation.
+@end deftypefun
+
+@deftypefun int openat64 (int @var{filedes}, const char *@var{filename}, int @var{flags}[, mode_t @var{mode}])
+@standards{GNU, fcntl.h}
+The large-file variant of the @code{openat}, similar to how
+@code{open64} is the large-file variant of @code{open}.
+
+When the sources are translated with @code{_FILE_OFFSET_BITS == 64} this
+function is actually available under the name @code{openat}. I.e., the
+new, extended API using 64 bit file sizes and offsets transparently
+replaces the old API.
+@end deftypefun
+
@deftypefn {Obsolete function} int creat (const char *@var{filename}, mode_t @var{mode})
@standards{POSIX.1, fcntl.h}
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
@@ -3775,7 +3812,9 @@ contains it is still needed), and permissions are checked when the
descriptor is used later on.
For example, such descriptors can be used with the @code{fexecve}
-function (@pxref{Executing a File}).
+function (@pxref{Executing a File}). Other applications involve the
+@samp{*at} function variants, along with the @code{AT_EMPTY_PATH} flag.
+@xref{Descriptor-Relative Access}.
This access mode is specific to Linux. On @gnuhurdsystems{}, it is
possible to use @code{O_EXEC} explicitly, or specify no access modes
diff --git a/manual/startup.texi b/manual/startup.texi
index 747beed4d9..8ac3b97eed 100644
--- a/manual/startup.texi
+++ b/manual/startup.texi
@@ -665,8 +665,12 @@ basis there may be information that is not available any other way.
This function is used to inquire about the entries in the auxiliary
vector. The @var{type} argument should be one of the @samp{AT_} symbols
defined in @file{elf.h}. If a matching entry is found, the value is
-returned; if the entry is not found, zero is returned and @code{errno} is
-set to @code{ENOENT}.
+returned; if the entry is not found, zero is returned and @code{errno}
+is set to @code{ENOENT}.
+
+@strong{Note:} There is no relationship between the @samp{AT_} contants
+defined in @file{elf.h} and the file name lookup flags in
+@file{fcntl.h}. @xref{Descriptor-Relative Access}.
@end deftypefun
For some platforms, the key @code{AT_HWCAP} is the easiest way to inquire

View File

@ -0,0 +1,70 @@
commit 7fe1fde499507126f7de10ebf12fecaf77ae6602
Author: Joseph Myers <josmyers@redhat.com>
Date: Mon Oct 28 22:22:26 2024 +0000
Document further requirement on mixing streams / file descriptors
The gilbc manual has some documentation in llio.texi of requirements
for moving between I/O on FILE * streams and file descriptors on the
same open file description.
The documentation of what must be done on a FILE * stream to move from
it to either a file descriptor or another FILE * for the same open
file description seems to match POSIX. However, there is an
additional requirement in POSIX on the *second* of the two handles
being moved between, which is not mentioned in the glibc manual: "If
any previous active handle has been used by a function that explicitly
changed the file offset, except as required above for the first
handle, the application shall perform an lseek() or fseek() (as
appropriate to the type of handle) to an appropriate location.".
Document this requirement on seeking in the glibc manual, limited to
the case that seems relevant to glibc (the new channel is a previously
active stream, on which the seeking previously occurred). Note that
I'm not sure what the "except as required above for the first handle"
is meant to be about, so I haven't documented anything for it. As far
as I can tell, nothing specified for moving from the first handle
actually list calling a seek function as one of the steps to be done.
(Current POSIX doesn't seem to have any relevant rationale for this
section. The rationale in the 1996 edition says "In requiring the
seek to an appropriate location for the new handle, the application is
required to know what it is doing if it is passing streams with seeks
involved. If the required seek is not done, the results are undefined
(and in fact the program probably will not work on many common
implementations)." - which also doesn't help in understanding the
purpose of "except as required above for the first handle".)
Tested with "make info" and "make pdf".
diff --git a/manual/llio.texi b/manual/llio.texi
index 12194273801adc18..0f84a593ee92b31f 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -1097,6 +1097,27 @@ streams persist in other processes, their file positions become
undefined as a result. To prevent this, you must clean up the streams
before destroying them.
+In addition to cleaning up a stream before doing I/O using another
+linked channel, additional precautions are needed to ensure a
+well-defined file position indicator in some cases. If both the
+following conditions hold, you must set the file position indicator on
+the new channel (a stream) using a function such as @code{fseek}.
+
+@itemize @bullet
+@item
+The new linked channel is a stream that was previously active.
+
+@item
+The file position indicator was previously set on that channel (while
+it was previously active) with a function such as @code{fseek}.
+@end itemize
+
+POSIX requires such precautions in more cases: if either the old or
+the new linked channel is a stream (whether or not previously active)
+and the file position indicator was previously set on any channel
+linked to those channels with a function such as @code{fseek} or
+@code{lseek}.
+
@node Independent Channels
@subsection Independent Channels
@cindex independent channels

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,428 @@
commit 6018ba05c01b1e17d77742a123e8c443f8fc713c
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted vfprintf output specifiers
Wire vfprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 437acef216b04237..dc825f415af283ad 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s sn v vas vd
+xprintf-funcs := p as d f s sn v vas vd vf
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-vf-c.c b/stdio-common/tst-printf-format-vf-c.c
new file mode 100644
index 0000000000000000..b31b551327bb4ebe
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-vf-char.c b/stdio-common/tst-printf-format-vf-char.c
new file mode 100644
index 0000000000000000..daa2886adb9f1636
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-vf-double.c b/stdio-common/tst-printf-format-vf-double.c
new file mode 100644
index 0000000000000000..63ec8c0cae6c272e
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-vf-int.c b/stdio-common/tst-printf-format-vf-int.c
new file mode 100644
index 0000000000000000..e687099b1052d040
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-vf-ldouble.c b/stdio-common/tst-printf-format-vf-ldouble.c
new file mode 100644
index 0000000000000000..801e359dab8ca159
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-vf-llong.c b/stdio-common/tst-printf-format-vf-llong.c
new file mode 100644
index 0000000000000000..a1b9ae340c4aa5ff
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-vf-long.c b/stdio-common/tst-printf-format-vf-long.c
new file mode 100644
index 0000000000000000..7afc127b844d1e10
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-vf-s.c b/stdio-common/tst-printf-format-vf-s.c
new file mode 100644
index 0000000000000000..6faa6d0dfe4b4132
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-vf-short.c b/stdio-common/tst-printf-format-vf-short.c
new file mode 100644
index 0000000000000000..c3d17ca501974f83
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-vf-uchar.c b/stdio-common/tst-printf-format-vf-uchar.c
new file mode 100644
index 0000000000000000..643438c693abf51f
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-vf-uint.c b/stdio-common/tst-printf-format-vf-uint.c
new file mode 100644
index 0000000000000000..844192cc9ccf5db8
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-vf-ullong.c b/stdio-common/tst-printf-format-vf-ullong.c
new file mode 100644
index 0000000000000000..ab58abd7f8c4e267
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-vf-ulong.c b/stdio-common/tst-printf-format-vf-ulong.c
new file mode 100644
index 0000000000000000..e76251f9d0e3337f
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-vf-ushort.c b/stdio-common/tst-printf-format-vf-ushort.c
new file mode 100644
index 0000000000000000..bf78a919a6599054
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vfprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vf.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-vf.h b/stdio-common/tst-printf-format-vf.h
new file mode 100644
index 0000000000000000..f824364f4c041ab8
--- /dev/null
+++ b/stdio-common/tst-printf-format-vf.h
@@ -0,0 +1,34 @@
+/* Test feature wrapper for formatted 'vfprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static int
+printf_under_test (const char *restrict fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ va_start (ap, fmt);
+ result = vfprintf (stdout, fmt, ap);
+ va_end (ap);
+ if (result < 0)
+ perror ("vfprintf");
+ return result;
+}

View File

@ -0,0 +1,458 @@
commit ac72dd90905e1693c108c9f36f0c7e79d6ad5501
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted vsprintf output specifiers
Wire vsprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index dc825f415af283ad..f0c414427ab109c7 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s sn v vas vd vf
+xprintf-funcs := p as d f s sn v vas vd vf vs
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-vs-c.c b/stdio-common/tst-printf-format-vs-c.c
new file mode 100644
index 0000000000000000..72bcb5f04957c4ef
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-vs-char.c b/stdio-common/tst-printf-format-vs-char.c
new file mode 100644
index 0000000000000000..30135cf1be1616ac
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-vs-double.c b/stdio-common/tst-printf-format-vs-double.c
new file mode 100644
index 0000000000000000..56290d383ebc33c8
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-vs-int.c b/stdio-common/tst-printf-format-vs-int.c
new file mode 100644
index 0000000000000000..f954e1f4f8277c64
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-vs-ldouble.c b/stdio-common/tst-printf-format-vs-ldouble.c
new file mode 100644
index 0000000000000000..3088e42813abd537
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-vs-llong.c b/stdio-common/tst-printf-format-vs-llong.c
new file mode 100644
index 0000000000000000..348ec2c3d73b8f88
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-vs-long.c b/stdio-common/tst-printf-format-vs-long.c
new file mode 100644
index 0000000000000000..874e3ba479eda8fb
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-vs-s.c b/stdio-common/tst-printf-format-vs-s.c
new file mode 100644
index 0000000000000000..051f1b79bf2cb028
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-vs-short.c b/stdio-common/tst-printf-format-vs-short.c
new file mode 100644
index 0000000000000000..36595a82b445e8a3
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-vs-uchar.c b/stdio-common/tst-printf-format-vs-uchar.c
new file mode 100644
index 0000000000000000..8e35614110bd7d57
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-vs-uint.c b/stdio-common/tst-printf-format-vs-uint.c
new file mode 100644
index 0000000000000000..4a13d6c409ad4245
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-vs-ullong.c b/stdio-common/tst-printf-format-vs-ullong.c
new file mode 100644
index 0000000000000000..313dfaf02bda3059
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-vs-ulong.c b/stdio-common/tst-printf-format-vs-ulong.c
new file mode 100644
index 0000000000000000..5ab7e2e7fe9b237a
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-vs-ushort.c b/stdio-common/tst-printf-format-vs-ushort.c
new file mode 100644
index 0000000000000000..a4af138a2f8485ab
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vs.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-vs.h b/stdio-common/tst-printf-format-vs.h
new file mode 100644
index 0000000000000000..e00e1b085bc58150
--- /dev/null
+++ b/stdio-common/tst-printf-format-vs.h
@@ -0,0 +1,64 @@
+/* Test feature wrapper for formatted 'vsprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/next_to_fault.h>
+
+#define SPRINTF_BUFFER_SIZE 65536
+
+static struct support_next_to_fault ntf;
+
+#define PREPARE printf_under_test_init
+static void
+printf_under_test_init (int argc, char **argv)
+{
+ ntf = support_next_to_fault_allocate (SPRINTF_BUFFER_SIZE);
+}
+
+static void __attribute__ ((destructor))
+printf_under_test_fini (void)
+{
+ support_next_to_fault_free (&ntf);
+}
+
+static int
+printf_under_test (const char *restrict fmt, ...)
+{
+ char *str = ntf.buffer;
+ va_list ap;
+ int result;
+
+ va_start (ap, fmt);
+ result = vsprintf (str, fmt, ap);
+ va_end (ap);
+ if (result < 0)
+ {
+ perror ("vsprintf");
+ goto out;
+ }
+ if (fwrite (str, sizeof (*str), result, stdout) != result)
+ {
+ perror ("fwrite");
+ result = -1;
+ }
+out:
+ return result;
+}

View File

@ -0,0 +1,458 @@
commit 11a2169e4066e6b848f1e6e4c31ec4e2210cecd8
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted vsnprintf output specifiers
Wire vsnprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index f0c414427ab109c7..905a5a510f1e5bc6 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s sn v vas vd vf vs
+xprintf-funcs := p as d f s sn v vas vd vf vs vsn
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-vsn-c.c b/stdio-common/tst-printf-format-vsn-c.c
new file mode 100644
index 0000000000000000..47c8a0f5dfbddb49
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-vsn-char.c b/stdio-common/tst-printf-format-vsn-char.c
new file mode 100644
index 0000000000000000..48d4393a46d80e33
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-vsn-double.c b/stdio-common/tst-printf-format-vsn-double.c
new file mode 100644
index 0000000000000000..06c1003fb5fde4b0
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-vsn-int.c b/stdio-common/tst-printf-format-vsn-int.c
new file mode 100644
index 0000000000000000..2aae92616f2f6007
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-vsn-ldouble.c b/stdio-common/tst-printf-format-vsn-ldouble.c
new file mode 100644
index 0000000000000000..0b5aafb124307526
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-vsn-llong.c b/stdio-common/tst-printf-format-vsn-llong.c
new file mode 100644
index 0000000000000000..8e79b8384f6858c6
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-vsn-long.c b/stdio-common/tst-printf-format-vsn-long.c
new file mode 100644
index 0000000000000000..e94f7dec23ece2ca
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-vsn-s.c b/stdio-common/tst-printf-format-vsn-s.c
new file mode 100644
index 0000000000000000..efd8a4c23f5f42e6
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-vsn-short.c b/stdio-common/tst-printf-format-vsn-short.c
new file mode 100644
index 0000000000000000..3d375b59e7a990f0
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-vsn-uchar.c b/stdio-common/tst-printf-format-vsn-uchar.c
new file mode 100644
index 0000000000000000..6d0f396481d3e2d6
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-vsn-uint.c b/stdio-common/tst-printf-format-vsn-uint.c
new file mode 100644
index 0000000000000000..b637f7bdb11f7913
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-vsn-ullong.c b/stdio-common/tst-printf-format-vsn-ullong.c
new file mode 100644
index 0000000000000000..d2442715f087acaf
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-vsn-ulong.c b/stdio-common/tst-printf-format-vsn-ulong.c
new file mode 100644
index 0000000000000000..67417d174043a605
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-vsn-ushort.c b/stdio-common/tst-printf-format-vsn-ushort.c
new file mode 100644
index 0000000000000000..396ea43ae7067c86
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vsnprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vsn.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-vsn.h b/stdio-common/tst-printf-format-vsn.h
new file mode 100644
index 0000000000000000..4f25f1af767dc221
--- /dev/null
+++ b/stdio-common/tst-printf-format-vsn.h
@@ -0,0 +1,64 @@
+/* Test feature wrapper for formatted 'vsnprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/next_to_fault.h>
+
+#define SPRINTF_BUFFER_SIZE 65536
+
+static struct support_next_to_fault ntf;
+
+#define PREPARE printf_under_test_init
+static void
+printf_under_test_init (int argc, char **argv)
+{
+ ntf = support_next_to_fault_allocate (SPRINTF_BUFFER_SIZE);
+}
+
+static void __attribute__ ((destructor))
+printf_under_test_fini (void)
+{
+ support_next_to_fault_free (&ntf);
+}
+
+static int
+printf_under_test (const char *restrict fmt, ...)
+{
+ char *str = ntf.buffer;
+ va_list ap;
+ int result;
+
+ va_start (ap, fmt);
+ result = vsnprintf (str, ntf.length, fmt, ap);
+ va_end (ap);
+ if (result < 0)
+ {
+ perror ("vsnprintf");
+ goto out;
+ }
+ if (fwrite (str, sizeof (*str), result, stdout) != result)
+ {
+ perror ("fwrite");
+ result = -1;
+ }
+out:
+ return result;
+}

View File

@ -0,0 +1,459 @@
commit b350a60b6ecd77b7ec30c7969de1df8b73642e55
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted asprintf output specifiers
Wire asprintf into test infrastructure for formatted printf output
specifiers.
Owing to mtrace logging of lots of memory allocation calls these tests
take a considerable amount of time to complete, except for the character
conversion, taking from 00m20s for 'tst-printf-format-as-s --direct s',
through 01m10s and 03m53s for 'tst-printf-format-as-char --direct i' and
'tst-printf-format-as-double --direct f' respectively, to 19m24s for
'tst-printf-format-as-ldouble --direct f', all in standalone execution
from NFS on a RISC-V FU740@1.2GHz system and with output redirected over
100Mbps network via SSH. It is with the skeleton's stub implementation
of dladdr(3); execution times with regular dladdr(3) are up to over
twice longer.
Set timeouts for the tests accordingly then, with a global default for
all the asprintf tests, and then individual higher settings for double
and long double tests each.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 0a45dcb4f45c0a5d..da279a969f7a8785 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p
+xprintf-funcs := p as
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-as-c.c b/stdio-common/tst-printf-format-as-c.c
new file mode 100644
index 0000000000000000..9eaf7aec73201b4d
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-as-char.c b/stdio-common/tst-printf-format-as-char.c
new file mode 100644
index 0000000000000000..d9266d5760fb8808
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-as-double.c b/stdio-common/tst-printf-format-as-double.c
new file mode 100644
index 0000000000000000..370ce8c11bd94fe8
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-double.c
@@ -0,0 +1,22 @@
+/* Test for formatted 'asprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 32)
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-as-int.c b/stdio-common/tst-printf-format-as-int.c
new file mode 100644
index 0000000000000000..e6e10a9769f079a4
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-as-ldouble.c b/stdio-common/tst-printf-format-as-ldouble.c
new file mode 100644
index 0000000000000000..e7f72208cec76078
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-ldouble.c
@@ -0,0 +1,22 @@
+/* Test for formatted 'asprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 128)
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-as-llong.c b/stdio-common/tst-printf-format-as-llong.c
new file mode 100644
index 0000000000000000..beaad73c235c344e
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-as-long.c b/stdio-common/tst-printf-format-as-long.c
new file mode 100644
index 0000000000000000..7d968a873c3b5e29
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-as-s.c b/stdio-common/tst-printf-format-as-s.c
new file mode 100644
index 0000000000000000..baa883d5316cbf2f
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-as-short.c b/stdio-common/tst-printf-format-as-short.c
new file mode 100644
index 0000000000000000..8d0b078815f299a6
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-as-uchar.c b/stdio-common/tst-printf-format-as-uchar.c
new file mode 100644
index 0000000000000000..8e46254a2f32b457
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-as-uint.c b/stdio-common/tst-printf-format-as-uint.c
new file mode 100644
index 0000000000000000..8cf38d71a2f53358
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-as-ullong.c b/stdio-common/tst-printf-format-as-ullong.c
new file mode 100644
index 0000000000000000..30b31ed8f7b36ae1
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-as-ulong.c b/stdio-common/tst-printf-format-as-ulong.c
new file mode 100644
index 0000000000000000..9b108aa2b5132686
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-as-ushort.c b/stdio-common/tst-printf-format-as-ushort.c
new file mode 100644
index 0000000000000000..44b912fc38c46d28
--- /dev/null
+++ b/stdio-common/tst-printf-format-as-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'asprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-as.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-as.h b/stdio-common/tst-printf-format-as.h
new file mode 100644
index 0000000000000000..c30d2e2c42822f24
--- /dev/null
+++ b/stdio-common/tst-printf-format-as.h
@@ -0,0 +1,46 @@
+/* Test feature wrapper for formatted 'asprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define printf_under_test(...) \
+({ \
+ __label__ out; \
+ int result; \
+ char *str; \
+ \
+ result = asprintf (&str, __VA_ARGS__); \
+ if (result < 0) \
+ { \
+ perror ("asprintf"); \
+ goto out; \
+ } \
+ if (fwrite (str, sizeof (*str), result, stdout) != result) \
+ { \
+ perror ("fwrite"); \
+ result = -1; \
+ } \
+ free (str); \
+out: \
+ result; \
+})
+
+#ifndef TIMEOUT
+# define TIMEOUT (DEFAULT_TIMEOUT * 12)
+#endif

View File

@ -0,0 +1,452 @@
commit b3e8a756ad569fd31181b74b3729d29df3eb55f3
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted dprintf output specifiers
Wire dprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index da279a969f7a8785..2bc830597085678a 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as
+xprintf-funcs := p as d
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-d-c.c b/stdio-common/tst-printf-format-d-c.c
new file mode 100644
index 0000000000000000..61fd06654d2a957e
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-d-char.c b/stdio-common/tst-printf-format-d-char.c
new file mode 100644
index 0000000000000000..baa6e1683e923841
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-d-double.c b/stdio-common/tst-printf-format-d-double.c
new file mode 100644
index 0000000000000000..e432a9570d46e776
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-d-int.c b/stdio-common/tst-printf-format-d-int.c
new file mode 100644
index 0000000000000000..6d59b23517b54a85
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-d-ldouble.c b/stdio-common/tst-printf-format-d-ldouble.c
new file mode 100644
index 0000000000000000..67a2bae1bc4e0301
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-d-llong.c b/stdio-common/tst-printf-format-d-llong.c
new file mode 100644
index 0000000000000000..950a2b84b9fc1abc
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-d-long.c b/stdio-common/tst-printf-format-d-long.c
new file mode 100644
index 0000000000000000..4fabb41b0b013011
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-d-s.c b/stdio-common/tst-printf-format-d-s.c
new file mode 100644
index 0000000000000000..1ef896e6e7d146bc
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-d-short.c b/stdio-common/tst-printf-format-d-short.c
new file mode 100644
index 0000000000000000..17767bb30d2f0d3e
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-d-uchar.c b/stdio-common/tst-printf-format-d-uchar.c
new file mode 100644
index 0000000000000000..732479ecab2cdc4e
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-d-uint.c b/stdio-common/tst-printf-format-d-uint.c
new file mode 100644
index 0000000000000000..5b68aec803f653ac
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-d-ullong.c b/stdio-common/tst-printf-format-d-ullong.c
new file mode 100644
index 0000000000000000..0e20a1dccd58e84b
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-d-ulong.c b/stdio-common/tst-printf-format-d-ulong.c
new file mode 100644
index 0000000000000000..62085ace806b6d33
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-d-ushort.c b/stdio-common/tst-printf-format-d-ushort.c
new file mode 100644
index 0000000000000000..7d8ef76d60b70e2d
--- /dev/null
+++ b/stdio-common/tst-printf-format-d-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'dprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-d.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-d.h b/stdio-common/tst-printf-format-d.h
new file mode 100644
index 0000000000000000..af7f26c17bde88ea
--- /dev/null
+++ b/stdio-common/tst-printf-format-d.h
@@ -0,0 +1,58 @@
+/* Test feature wrapper for formatted 'dprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* We need to go through the POSIX-mandated dance to switch between
+ handles on an open file description. */
+
+#define printf_under_test(...) \
+({ \
+ __label__ out; \
+ int result; \
+ \
+ result = fflush (stdout); \
+ if (result == EOF) \
+ { \
+ perror ("fflush"); \
+ goto out; \
+ } \
+ result = lseek (STDOUT_FILENO, 0, SEEK_END); \
+ if (result < 0 && errno == ESPIPE) \
+ result = 0; \
+ if (result < 0) \
+ { \
+ perror ("lseek"); \
+ goto out; \
+ } \
+ result = dprintf (STDOUT_FILENO, __VA_ARGS__); \
+ if (result < 0) \
+ { \
+ perror ("dprintf"); \
+ goto out; \
+ } \
+ result = fseek (stdout, 0, SEEK_END); \
+ if (result < 0 && errno == ESPIPE) \
+ result = 0; \
+ if (result < 0) \
+ perror ("fseek"); \
+out: \
+ result; \
+})

View File

@ -0,0 +1,423 @@
commit 1dc5cdc3da19e10d47e50a5ea2ea3ce62ee2fa82
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted fprintf output specifiers
Wire fprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 2bc830597085678a..3a812073784fa3b6 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d
+xprintf-funcs := p as d f
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-f-c.c b/stdio-common/tst-printf-format-f-c.c
new file mode 100644
index 0000000000000000..1db9e2b5f3bb2d32
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-f-char.c b/stdio-common/tst-printf-format-f-char.c
new file mode 100644
index 0000000000000000..a492f318620bc82e
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-f-double.c b/stdio-common/tst-printf-format-f-double.c
new file mode 100644
index 0000000000000000..906ef0b90b9e7d1d
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-f-int.c b/stdio-common/tst-printf-format-f-int.c
new file mode 100644
index 0000000000000000..92dc0c919771ae26
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-f-ldouble.c b/stdio-common/tst-printf-format-f-ldouble.c
new file mode 100644
index 0000000000000000..0a0c88d64c873061
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-f-llong.c b/stdio-common/tst-printf-format-f-llong.c
new file mode 100644
index 0000000000000000..ceb8d035faaf0a12
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-f-long.c b/stdio-common/tst-printf-format-f-long.c
new file mode 100644
index 0000000000000000..a4a5dca5ebd7b3a4
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-f-s.c b/stdio-common/tst-printf-format-f-s.c
new file mode 100644
index 0000000000000000..da0e0f8bacab6992
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-f-short.c b/stdio-common/tst-printf-format-f-short.c
new file mode 100644
index 0000000000000000..3abd134d0aeeef87
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-f-uchar.c b/stdio-common/tst-printf-format-f-uchar.c
new file mode 100644
index 0000000000000000..f104cde37b322b60
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-f-uint.c b/stdio-common/tst-printf-format-f-uint.c
new file mode 100644
index 0000000000000000..0e1fdb4b367032a2
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-f-ullong.c b/stdio-common/tst-printf-format-f-ullong.c
new file mode 100644
index 0000000000000000..b4669fcbb7dd3282
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-f-ulong.c b/stdio-common/tst-printf-format-f-ulong.c
new file mode 100644
index 0000000000000000..3f4f900362a153b5
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-f-ushort.c b/stdio-common/tst-printf-format-f-ushort.c
new file mode 100644
index 0000000000000000..d49c2371403e20a6
--- /dev/null
+++ b/stdio-common/tst-printf-format-f-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'fprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-f.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-f.h b/stdio-common/tst-printf-format-f.h
new file mode 100644
index 0000000000000000..efb3283a032f44a7
--- /dev/null
+++ b/stdio-common/tst-printf-format-f.h
@@ -0,0 +1,29 @@
+/* Test feature wrapper for formatted 'fprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+#define printf_under_test(...) \
+({ \
+ int result; \
+ \
+ result = fprintf (stdout, __VA_ARGS__); \
+ if (result < 0) \
+ perror ("fprintf"); \
+ result; \
+})

View File

@ -0,0 +1,454 @@
commit c683ac8520e8064e7be3a22922d80849271290ac
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted sprintf output specifiers
Wire sprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 3a812073784fa3b6..7522cd76cc26a3a5 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f
+xprintf-funcs := p as d f s
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-s-c.c b/stdio-common/tst-printf-format-s-c.c
new file mode 100644
index 0000000000000000..87dad077b9c05216
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-s-char.c b/stdio-common/tst-printf-format-s-char.c
new file mode 100644
index 0000000000000000..f67ac94a5dd70cf4
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-s-double.c b/stdio-common/tst-printf-format-s-double.c
new file mode 100644
index 0000000000000000..16186b5dc55eabaf
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-s-int.c b/stdio-common/tst-printf-format-s-int.c
new file mode 100644
index 0000000000000000..2ed7b2df471cd96d
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-s-ldouble.c b/stdio-common/tst-printf-format-s-ldouble.c
new file mode 100644
index 0000000000000000..0362cc50f78ffdfa
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-s-llong.c b/stdio-common/tst-printf-format-s-llong.c
new file mode 100644
index 0000000000000000..b49f84998a7e7ca2
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-s-long.c b/stdio-common/tst-printf-format-s-long.c
new file mode 100644
index 0000000000000000..49224d7f29d7e65c
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-s-s.c b/stdio-common/tst-printf-format-s-s.c
new file mode 100644
index 0000000000000000..3a400f8907895db0
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-s-short.c b/stdio-common/tst-printf-format-s-short.c
new file mode 100644
index 0000000000000000..c98a808cff51c52a
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-s-uchar.c b/stdio-common/tst-printf-format-s-uchar.c
new file mode 100644
index 0000000000000000..befc36894975a9a1
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-s-uint.c b/stdio-common/tst-printf-format-s-uint.c
new file mode 100644
index 0000000000000000..f3a4c49632a3be07
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-s-ullong.c b/stdio-common/tst-printf-format-s-ullong.c
new file mode 100644
index 0000000000000000..4ce559037921e01f
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-s-ulong.c b/stdio-common/tst-printf-format-s-ulong.c
new file mode 100644
index 0000000000000000..81f9eea893c194d2
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-s-ushort.c b/stdio-common/tst-printf-format-s-ushort.c
new file mode 100644
index 0000000000000000..4b1cca6e6cf6b342
--- /dev/null
+++ b/stdio-common/tst-printf-format-s-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'sprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-s.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-s.h b/stdio-common/tst-printf-format-s.h
new file mode 100644
index 0000000000000000..7d1e72cffb7b20fb
--- /dev/null
+++ b/stdio-common/tst-printf-format-s.h
@@ -0,0 +1,60 @@
+/* Test feature wrapper for formatted 'sprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/next_to_fault.h>
+
+#define SPRINTF_BUFFER_SIZE 65536
+
+static struct support_next_to_fault ntf;
+
+#define PREPARE printf_under_test_init
+static void
+printf_under_test_init (int argc, char **argv)
+{
+ ntf = support_next_to_fault_allocate (SPRINTF_BUFFER_SIZE);
+}
+
+static void __attribute__ ((destructor))
+printf_under_test_fini (void)
+{
+ support_next_to_fault_free (&ntf);
+}
+
+#define printf_under_test(...) \
+({ \
+ __label__ out; \
+ char *str = ntf.buffer; \
+ int result; \
+ \
+ result = sprintf (str, __VA_ARGS__); \
+ if (result < 0) \
+ { \
+ perror ("sprintf"); \
+ goto out; \
+ } \
+ if (fwrite (str, sizeof (*str), result, stdout) != result) \
+ { \
+ perror ("fwrite"); \
+ result = -1; \
+ } \
+out: \
+ result; \
+})

View File

@ -0,0 +1,454 @@
commit 0b6379cb98590c28088f017ddcc0edb8ad7d0131
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted snprintf output specifiers
Wire snprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 7522cd76cc26a3a5..88b89ce13ffbadc4 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s
+xprintf-funcs := p as d f s sn
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-sn-c.c b/stdio-common/tst-printf-format-sn-c.c
new file mode 100644
index 0000000000000000..59f51d635bc46d28
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-sn-char.c b/stdio-common/tst-printf-format-sn-char.c
new file mode 100644
index 0000000000000000..8b682dd2d52f04d2
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-sn-double.c b/stdio-common/tst-printf-format-sn-double.c
new file mode 100644
index 0000000000000000..4719a58d84bda809
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-sn-int.c b/stdio-common/tst-printf-format-sn-int.c
new file mode 100644
index 0000000000000000..94c42f246fc8ce49
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-sn-ldouble.c b/stdio-common/tst-printf-format-sn-ldouble.c
new file mode 100644
index 0000000000000000..921f3ffe3b79a05d
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-sn-llong.c b/stdio-common/tst-printf-format-sn-llong.c
new file mode 100644
index 0000000000000000..013552791e087d0c
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-sn-long.c b/stdio-common/tst-printf-format-sn-long.c
new file mode 100644
index 0000000000000000..58c8912746c1108b
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-sn-s.c b/stdio-common/tst-printf-format-sn-s.c
new file mode 100644
index 0000000000000000..aa3f170c14790926
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-sn-short.c b/stdio-common/tst-printf-format-sn-short.c
new file mode 100644
index 0000000000000000..f7baa1211d16e203
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-sn-uchar.c b/stdio-common/tst-printf-format-sn-uchar.c
new file mode 100644
index 0000000000000000..6ae5f121bd76ab9d
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-sn-uint.c b/stdio-common/tst-printf-format-sn-uint.c
new file mode 100644
index 0000000000000000..f0a0c3063f89781a
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-sn-ullong.c b/stdio-common/tst-printf-format-sn-ullong.c
new file mode 100644
index 0000000000000000..0dc0a50c4f2362a2
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-sn-ulong.c b/stdio-common/tst-printf-format-sn-ulong.c
new file mode 100644
index 0000000000000000..23ff5a27d7c25c34
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-sn-ushort.c b/stdio-common/tst-printf-format-sn-ushort.c
new file mode 100644
index 0000000000000000..1c5cffbeb414048e
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'snprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-sn.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-sn.h b/stdio-common/tst-printf-format-sn.h
new file mode 100644
index 0000000000000000..ec2645bf57da8bbb
--- /dev/null
+++ b/stdio-common/tst-printf-format-sn.h
@@ -0,0 +1,60 @@
+/* Test feature wrapper for formatted 'snprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/next_to_fault.h>
+
+#define SPRINTF_BUFFER_SIZE 65536
+
+static struct support_next_to_fault ntf;
+
+#define PREPARE printf_under_test_init
+static void
+printf_under_test_init (int argc, char **argv)
+{
+ ntf = support_next_to_fault_allocate (SPRINTF_BUFFER_SIZE);
+}
+
+static void __attribute__ ((destructor))
+printf_under_test_fini (void)
+{
+ support_next_to_fault_free (&ntf);
+}
+
+#define printf_under_test(...) \
+({ \
+ __label__ out; \
+ char *str = ntf.buffer; \
+ int result; \
+ \
+ result = snprintf (str, ntf.length, __VA_ARGS__); \
+ if (result < 0) \
+ { \
+ perror ("snprintf"); \
+ goto out; \
+ } \
+ if (fwrite (str, sizeof (*str), result, stdout) != result) \
+ { \
+ perror ("fwrite"); \
+ result = -1; \
+ } \
+out: \
+ result; \
+})

View File

@ -0,0 +1,428 @@
commit bad554d9b4f10988eb7fdb814fbaa5e89416d781
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted vprintf output specifiers
Wire vprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 88b89ce13ffbadc4..fd34891ea439c684 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s sn
+xprintf-funcs := p as d f s sn v
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-v-c.c b/stdio-common/tst-printf-format-v-c.c
new file mode 100644
index 0000000000000000..94aa3042aaee6d97
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-v-char.c b/stdio-common/tst-printf-format-v-char.c
new file mode 100644
index 0000000000000000..c813d81e53956295
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-v-double.c b/stdio-common/tst-printf-format-v-double.c
new file mode 100644
index 0000000000000000..90cc1704eb3da2f3
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-v-int.c b/stdio-common/tst-printf-format-v-int.c
new file mode 100644
index 0000000000000000..6529425b263975c8
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-v-ldouble.c b/stdio-common/tst-printf-format-v-ldouble.c
new file mode 100644
index 0000000000000000..813f4a510dc833cc
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-v-llong.c b/stdio-common/tst-printf-format-v-llong.c
new file mode 100644
index 0000000000000000..270ad08bf5e948fd
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-v-long.c b/stdio-common/tst-printf-format-v-long.c
new file mode 100644
index 0000000000000000..2f5f653fecb25040
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-v-s.c b/stdio-common/tst-printf-format-v-s.c
new file mode 100644
index 0000000000000000..ebc253b3e83291f2
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-v-short.c b/stdio-common/tst-printf-format-v-short.c
new file mode 100644
index 0000000000000000..92a59d9fd3972f1e
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-v-uchar.c b/stdio-common/tst-printf-format-v-uchar.c
new file mode 100644
index 0000000000000000..045ffd2864f8158f
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-v-uint.c b/stdio-common/tst-printf-format-v-uint.c
new file mode 100644
index 0000000000000000..17b1ce3aa7780209
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-v-ullong.c b/stdio-common/tst-printf-format-v-ullong.c
new file mode 100644
index 0000000000000000..590b04f339e01cf6
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-v-ulong.c b/stdio-common/tst-printf-format-v-ulong.c
new file mode 100644
index 0000000000000000..6747677a42b38e37
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-v-ushort.c b/stdio-common/tst-printf-format-v-ushort.c
new file mode 100644
index 0000000000000000..1e782715627f7b77
--- /dev/null
+++ b/stdio-common/tst-printf-format-v-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-v.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-v.h b/stdio-common/tst-printf-format-v.h
new file mode 100644
index 0000000000000000..711b290b59df8781
--- /dev/null
+++ b/stdio-common/tst-printf-format-v.h
@@ -0,0 +1,34 @@
+/* Test feature wrapper for formatted 'vprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static int
+printf_under_test (const char *restrict fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ va_start (ap, fmt);
+ result = vprintf (fmt, ap);
+ va_end (ap);
+ if (result < 0)
+ perror ("vprintf");
+ return result;
+}

View File

@ -0,0 +1,454 @@
commit 349670f8093d920d4d683472c88029f6901f7ae7
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted vasprintf output specifiers
Wire vasprintf into test infrastructure for formatted printf output
specifiers.
Owing to mtrace logging these tests take amounts of time to complete
similar to those of corresponding asprintf tests, so set timeouts for
the tests accordingly, with a global default for all the vasprintf
tests, and then individual higher settings for double and long double
tests each.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index fd34891ea439c684..2675d7741fe496d4 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s sn v
+xprintf-funcs := p as d f s sn v vas
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-vas-c.c b/stdio-common/tst-printf-format-vas-c.c
new file mode 100644
index 0000000000000000..f8cf814c8c3bc293
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-vas-char.c b/stdio-common/tst-printf-format-vas-char.c
new file mode 100644
index 0000000000000000..39c6e73977f3f32f
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-vas-double.c b/stdio-common/tst-printf-format-vas-double.c
new file mode 100644
index 0000000000000000..25a21bb0adc2726f
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-double.c
@@ -0,0 +1,22 @@
+/* Test for formatted 'vasprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 32)
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-vas-int.c b/stdio-common/tst-printf-format-vas-int.c
new file mode 100644
index 0000000000000000..9cd70c8fcbae1c03
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-vas-ldouble.c b/stdio-common/tst-printf-format-vas-ldouble.c
new file mode 100644
index 0000000000000000..60c3933fab1b9216
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-ldouble.c
@@ -0,0 +1,22 @@
+/* Test for formatted 'vasprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 128)
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-vas-llong.c b/stdio-common/tst-printf-format-vas-llong.c
new file mode 100644
index 0000000000000000..5d5322b8b9dfe0a4
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-vas-long.c b/stdio-common/tst-printf-format-vas-long.c
new file mode 100644
index 0000000000000000..d9651053f8f14dcd
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-vas-s.c b/stdio-common/tst-printf-format-vas-s.c
new file mode 100644
index 0000000000000000..6d74ab83e3038b44
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-vas-short.c b/stdio-common/tst-printf-format-vas-short.c
new file mode 100644
index 0000000000000000..a6d76a97055fbb89
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-vas-uchar.c b/stdio-common/tst-printf-format-vas-uchar.c
new file mode 100644
index 0000000000000000..c3dee11b7d8092d9
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-vas-uint.c b/stdio-common/tst-printf-format-vas-uint.c
new file mode 100644
index 0000000000000000..e56e89374db69c3f
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-vas-ullong.c b/stdio-common/tst-printf-format-vas-ullong.c
new file mode 100644
index 0000000000000000..05691bc3181c6d18
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-vas-ulong.c b/stdio-common/tst-printf-format-vas-ulong.c
new file mode 100644
index 0000000000000000..767d9cb6a6ac64a2
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-vas-ushort.c b/stdio-common/tst-printf-format-vas-ushort.c
new file mode 100644
index 0000000000000000..284d79f75364504f
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vasprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vas.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-vas.h b/stdio-common/tst-printf-format-vas.h
new file mode 100644
index 0000000000000000..3e38e729ec97ceed
--- /dev/null
+++ b/stdio-common/tst-printf-format-vas.h
@@ -0,0 +1,50 @@
+/* Test feature wrapper for formatted 'vasprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+printf_under_test (const char *restrict fmt, ...)
+{
+ va_list ap;
+ int result;
+ char *str;
+
+ va_start (ap, fmt);
+ result = vasprintf (&str, fmt, ap);
+ va_end (ap);
+ if (result < 0)
+ {
+ perror ("vasprintf");
+ goto out;
+ }
+ if (fwrite (str, sizeof (*str), result, stdout) != result)
+ {
+ perror ("fwrite");
+ result = -1;
+ }
+ free (str);
+out:
+ return result;
+}
+
+#ifndef TIMEOUT
+# define TIMEOUT (DEFAULT_TIMEOUT * 12)
+#endif

View File

@ -0,0 +1,456 @@
commit fae4eacae75e4f2767998aca703d6efaae2a747f
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Thu Nov 7 06:14:24 2024 +0000
stdio-common: Add tests for formatted vdprintf output specifiers
Wire vdprintf into test infrastructure for formatted printf output
specifiers.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 2675d7741fe496d4..437acef216b04237 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -23,7 +23,7 @@ subdir := stdio-common
include ../Makeconfig
# List of markers for printf family function tests.
-xprintf-funcs := p as d f s sn v vas
+xprintf-funcs := p as d f s sn v vas vd
# List of data types and formats for individual per-conversion printf tests.
fmt-convs := double ldouble
diff --git a/stdio-common/tst-printf-format-vd-c.c b/stdio-common/tst-printf-format-vd-c.c
new file mode 100644
index 0000000000000000..209b1784896a0bfd
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-c.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for the 'c' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-c.c"
diff --git a/stdio-common/tst-printf-format-vd-char.c b/stdio-common/tst-printf-format-vd-char.c
new file mode 100644
index 0000000000000000..8286b6d5b227e83a
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-char.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for signed char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-char.c"
diff --git a/stdio-common/tst-printf-format-vd-double.c b/stdio-common/tst-printf-format-vd-double.c
new file mode 100644
index 0000000000000000..e89a2ca5983697ce
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-double.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-double.c"
diff --git a/stdio-common/tst-printf-format-vd-int.c b/stdio-common/tst-printf-format-vd-int.c
new file mode 100644
index 0000000000000000..598a888b1c937361
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-int.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-int.c"
diff --git a/stdio-common/tst-printf-format-vd-ldouble.c b/stdio-common/tst-printf-format-vd-ldouble.c
new file mode 100644
index 0000000000000000..d3ada6ff0bcdd9c1
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-ldouble.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for long double conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-ldouble.c"
diff --git a/stdio-common/tst-printf-format-vd-llong.c b/stdio-common/tst-printf-format-vd-llong.c
new file mode 100644
index 0000000000000000..ea6ea7b2157dc0c9
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-llong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-llong.c"
diff --git a/stdio-common/tst-printf-format-vd-long.c b/stdio-common/tst-printf-format-vd-long.c
new file mode 100644
index 0000000000000000..4ee1cdacffb4fe77
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-long.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-long.c"
diff --git a/stdio-common/tst-printf-format-vd-s.c b/stdio-common/tst-printf-format-vd-s.c
new file mode 100644
index 0000000000000000..df7cf9a6fbf04c9b
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-s.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for the 's' conversion.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-s.c"
diff --git a/stdio-common/tst-printf-format-vd-short.c b/stdio-common/tst-printf-format-vd-short.c
new file mode 100644
index 0000000000000000..87128c8303b57cd8
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-short.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-short.c"
diff --git a/stdio-common/tst-printf-format-vd-uchar.c b/stdio-common/tst-printf-format-vd-uchar.c
new file mode 100644
index 0000000000000000..90dea719471dcb30
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-uchar.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for unsigned char conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-uchar.c"
diff --git a/stdio-common/tst-printf-format-vd-uint.c b/stdio-common/tst-printf-format-vd-uint.c
new file mode 100644
index 0000000000000000..feb95dc018ee20fe
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-uint.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for unsigned int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-uint.c"
diff --git a/stdio-common/tst-printf-format-vd-ullong.c b/stdio-common/tst-printf-format-vd-ullong.c
new file mode 100644
index 0000000000000000..8f62fb0aeeaca3a3
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-ullong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for unsigned long long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-ullong.c"
diff --git a/stdio-common/tst-printf-format-vd-ulong.c b/stdio-common/tst-printf-format-vd-ulong.c
new file mode 100644
index 0000000000000000..59b2015cd33aaede
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-ulong.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for unsigned long int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-ulong.c"
diff --git a/stdio-common/tst-printf-format-vd-ushort.c b/stdio-common/tst-printf-format-vd-ushort.c
new file mode 100644
index 0000000000000000..5d096502d9f44959
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd-ushort.c
@@ -0,0 +1,20 @@
+/* Test for formatted 'vdprintf' output for unsigned short int conversions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-printf-format-vd.h"
+#include "tst-printf-format-skeleton-ushort.c"
diff --git a/stdio-common/tst-printf-format-vd.h b/stdio-common/tst-printf-format-vd.h
new file mode 100644
index 0000000000000000..d721edadc6f7786b
--- /dev/null
+++ b/stdio-common/tst-printf-format-vd.h
@@ -0,0 +1,62 @@
+/* Test feature wrapper for formatted 'vdprintf' output.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* We need to go through the POSIX-mandated dance to switch between
+ handles on an open file description. */
+
+static int
+printf_under_test (const char *restrict fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ result = fflush (stdout);
+ if (result == EOF)
+ {
+ perror ("fflush");
+ goto out;
+ }
+ result = lseek (STDOUT_FILENO, 0, SEEK_END);
+ if (result < 0 && errno == ESPIPE)
+ result = 0;
+ if (result < 0)
+ {
+ perror ("lseek");
+ goto out;
+ }
+ va_start (ap, fmt);
+ result = vdprintf (STDOUT_FILENO, fmt, ap);
+ va_end (ap);
+ if (result < 0)
+ {
+ perror ("vdprintf");
+ goto out;
+ }
+ result = fseek (stdout, 0, SEEK_END);
+ if (result < 0 && errno == ESPIPE)
+ result = 0;
+ if (result < 0)
+ perror ("fseek");
+out:
+ return result;
+}

View File

@ -0,0 +1,287 @@
From 4945ffc88a8ad49280bae64165683ddfd12b2390 Mon Sep 17 00:00:00 2001
From: DJ Delorie <dj@redhat.com>
Date: Wed, 7 Aug 2024 16:55:16 -0400
Subject: fgets: more tests
Add more tests for unusual situations fgets() might see:
* zero size file
* zero sized buffer
* NULL buffer
* NUL data
* writable stream
* closed stream
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 89871d0de8..03d597f8e6 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -209,6 +209,7 @@ tests := \
tst-fdopen \
tst-ferror \
tst-fgets \
+ tst-fgets2 \
tst-fileno \
tst-fmemopen \
tst-fmemopen2 \
diff --git a/stdio-common/tst-fgets2.c b/stdio-common/tst-fgets2.c
new file mode 100644
index 0000000000..5b78447ea9
--- /dev/null
+++ b/stdio-common/tst-fgets2.c
@@ -0,0 +1,253 @@
+/* Test for additional fgets error handling.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <libc-diag.h>
+#include <stdio.h>
+#include <error.h>
+#include <errno.h>
+#include <limits.h>
+#include <mcheck.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <support/support.h>
+#include <support/check.h>
+
+/* This avoids compiler warnings about passing NULL where a valid
+ pointer is expected. */
+static void *volatile null = NULL;
+
+/* Implementation of our FILE stream backend. */
+
+static int bytes_read;
+static int cookie_valid = 0;
+struct Cookie {
+ const char *buffer;
+ int bufptr;
+ int bufsz;
+};
+
+#define VALIDATE_COOKIE() if (! cookie_valid) { \
+ FAIL ("call to %s after file closed", __FUNCTION__); \
+ return -1; \
+ }
+
+static ssize_t
+io_read (void *vcookie, char *buf, size_t size)
+{
+ struct Cookie *cookie = (struct Cookie *) vcookie;
+
+ VALIDATE_COOKIE ();
+
+ if (size > cookie->bufsz - cookie->bufptr)
+ size = cookie->bufsz - cookie->bufptr;
+
+ memcpy (buf, cookie->buffer + cookie->bufptr, size);
+ cookie->bufptr += size;
+ bytes_read += size;
+ return size;
+}
+
+static ssize_t
+io_write (void *vcookie, const char *buf, size_t size)
+{
+ VALIDATE_COOKIE ();
+ FAIL_EXIT1 ("io_write called");
+}
+
+static int
+io_seek (void *vcookie, off64_t *position, int whence)
+{
+ VALIDATE_COOKIE ();
+ FAIL_EXIT1 ("io_seek called");
+}
+
+static int
+io_clean (void *vcookie)
+{
+ struct Cookie *cookie = (struct Cookie *) vcookie;
+
+ VALIDATE_COOKIE ();
+
+ cookie->buffer = NULL;
+ cookie->bufsz = 0;
+ cookie->bufptr = 0;
+
+ cookie_valid = 0;
+ free (cookie);
+ return 0;
+}
+
+cookie_io_functions_t io_funcs = {
+ .read = io_read,
+ .write = io_write,
+ .seek = io_seek,
+ .close = io_clean
+};
+
+FILE *
+io_open (const char *buffer, int buflen, const char *mode, void **vcookie)
+{
+ FILE *f;
+ struct Cookie *cookie;
+
+ cookie = (struct Cookie *) xcalloc (1, sizeof (struct Cookie));
+ *vcookie = cookie;
+ cookie_valid = 1;
+
+ cookie->buffer = buffer;
+ cookie->bufsz = buflen;
+ bytes_read = 0;
+
+ f = fopencookie (cookie, mode, io_funcs);
+ if (f == NULL)
+ FAIL_EXIT1 ("fopencookie failed");
+
+ clearerr (f);
+ return f;
+}
+
+/* The test cases. */
+
+#define my_open(s,l,m) io_open (s, l, m, (void *) &cookie)
+
+#define TEST_COMPARE_0x11(buf, len) \
+ TEST_COMPARE_BLOB (buf + (len), sizeof (buf) - (len), \
+ buf2, sizeof (buf) - (len));
+
+#define check_flags(f, expected_eof, expected_err) \
+ { \
+ if (expected_eof) \
+ TEST_VERIFY (feof (f) != 0); \
+ else \
+ TEST_VERIFY (feof (f) == 0); \
+ if (expected_err) \
+ TEST_VERIFY (ferror (f) != 0); \
+ else \
+ TEST_VERIFY (ferror (f) == 0); \
+ }
+
+static int
+do_test (void)
+{
+ FILE *f;
+ struct Cookie *cookie;
+ char buf [10];
+ char buf2 [10];
+ char *returned_string;
+
+ memset (buf2, 0x11, sizeof (buf2));
+
+ printf ("testing base operation...\n");
+ f = my_open ("hello\n", 6, "r");
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, f);
+ TEST_VERIFY (returned_string == buf);
+ TEST_COMPARE_BLOB (buf, bytes_read + 1, "hello\n\0", 7);
+ TEST_COMPARE_0x11 (buf, bytes_read + 1);
+ check_flags (f, 0, 0);
+
+ fclose (f);
+
+ printf ("testing zero size file...\n");
+ f = my_open ("hello\n", 0, "r");
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, f);
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+ check_flags (f, 1, 0);
+ fclose (f);
+
+ printf ("testing zero size buffer...\n");
+ f = my_open ("hello\n", 6, "r");
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, 0, f);
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+ check_flags (f, 0, 0);
+ fclose (f);
+
+ printf ("testing NULL buffer with empty stream...\n");
+ f = my_open ("hello\n", 0, "r");
+ memset (buf, 0x11, sizeof (buf));
+
+ returned_string = fgets (null, sizeof (buf), f);
+
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+ check_flags (f, 1, 0);
+ fclose (f);
+
+ printf ("testing embedded NUL...\n");
+ f = my_open ("hel\0lo\n", 7, "r");
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, f);
+ TEST_VERIFY (returned_string == buf);
+ TEST_COMPARE_BLOB (buf, bytes_read + 1, "hel\0lo\n\0", 8);
+ TEST_COMPARE_0x11 (buf, bytes_read + 1);
+ check_flags (f, 0, 0);
+ fclose (f);
+
+ printf ("testing writable stream...\n");
+ f = my_open ("hel\0lo\n", 7, "w");
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, f);
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+ check_flags (f, 0, 1);
+ fclose (f);
+
+ printf ("testing closed fd stream...\n");
+ int fd = open ("/dev/null", O_RDONLY);
+ f = fdopen (fd, "r");
+ close (fd);
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, f);
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+ check_flags (f, 0, 1);
+ fclose (f);
+
+#ifdef IO_DEBUG
+ /* These tests only pass if glibc is built with -DIO_DEBUG, but are
+ included for reference. */
+
+ printf ("testing NULL descriptor...\n");
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, null);
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+
+ printf ("testing closed descriptor...\n");
+ f = my_open ("hello\n", 7, "r");
+ fclose (f);
+ memset (buf, 0x11, sizeof (buf));
+ returned_string = fgets (buf, sizeof (buf) - 1, f);
+ TEST_VERIFY (returned_string == NULL);
+ TEST_VERIFY (bytes_read == 0);
+#endif
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,578 @@
commit 45c42b65c29422b773ac94771aa71165e245f8f8
Author: Martin Coufal <mcoufal@redhat.com>
Date: Thu Jan 23 13:04:06 2025 +0100
Add new tests for fopen
Adding some basic tests for fopen, testing different modes, stream
positioning and concurrent read/write operation on files.
Reviewed-by: DJ Delorie <dj@redhat.com>
# Conflicts:
# sysdeps/pthread/Makefile (new test added)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 74e0edff73a9e468..fe69e48849cb9819 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -201,6 +201,7 @@ tests := \
tst-fmemopen2 \
tst-fmemopen3 \
tst-fmemopen4 \
+ tst-fopen \
tst-fphex \
tst-fphex-wide \
tst-fread \
diff --git a/stdio-common/tst-fopen.c b/stdio-common/tst-fopen.c
new file mode 100644
index 0000000000000000..8c1fefd116f9f581
--- /dev/null
+++ b/stdio-common/tst-fopen.c
@@ -0,0 +1,279 @@
+/* Basic test for fopen.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+
+#define APPENDED_TEXT "This is appended text. "
+#define DEFAULT_TEXT "Lorem ipsum dolor sit amet, consectetur " \
+ "adipiscing elit, sed do eiusmod tempor incididunt ut labore et " \
+ "dolore magna aliqua."
+#define MAX_BUFFER_SIZE 300
+
+
+static int
+do_test (void)
+{
+ char *temp_file;
+ FILE *fd_file = NULL;
+ char read_buffer[MAX_BUFFER_SIZE] = "";
+ size_t ret;
+
+ /* Prepare files. */
+ int fd = create_temp_file ("tst-fopen.", &temp_file);
+ TEST_VERIFY_EXIT (fd != -1);
+ fd_file = fdopen (fd, "w");
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ xfclose (fd_file);
+
+ /* Test 1: This checks for fopen with mode "r". Open text file for
+ reading. The stream is positioned at the beginning of the file. */
+ printf ("Test 1: This checks for fopen with mode \"r\".\n");
+ fd_file = fopen (temp_file, "r");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0);
+ /* Write should fail. */
+ errno = 0;
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_VERIFY (ferror (fd_file) != 0);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (ret, 0);
+ clearerr (fd_file);
+ /* Opening non-existent file should fail. */
+ xfclose (fd_file);
+ errno = 0;
+ fd_file = fopen ("file-that-does-not-exist", "r");
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, ENOENT);
+ TEST_VERIFY (fd_file == NULL);
+
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 2: This checks for fopen with mode "r+". Open for reading and
+ writing. The stream is positioned at the beginning of the file. */
+ printf ("Test 2: This checks for fopen with mode \"r+\".\n");
+ fd_file = fopen (temp_file, "r+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0);
+ fflush (fd_file);
+ /* File position indicator expected at 0 + read bytes. */
+ TEST_COMPARE (ftell (fd_file), ret);
+ /* Write should succeed. */
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ /* Opening non-existent file should fail. */
+ xfclose (fd_file);
+ errno = 0;
+ fd_file = fopen ("file-that-does-not-exist", "r+");
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, ENOENT);
+ TEST_VERIFY (fd_file == NULL);
+
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 3: This checks for fopen with mode "w". Truncate file to zero
+ length or create text file for writing. The stream is positioned
+ at the beginning of the file. */
+ printf ("Test 3: This checks for fopen with mode \"w\".\n");
+ fd_file = fopen (temp_file, "w");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should fail. */
+ errno = 0;
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_VERIFY (ferror (fd_file) != 0);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (ret, 0);
+ clearerr (fd_file);
+ /* Write should succeed. */
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "w");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 4: This checks for fopen with mode "w+". Open for reading and
+ writing. The file is created if it does not exist, otherwise it is
+ truncated. The stream is positioned at the beginning of the file.
+ */
+ printf ("Test 4: This checks for fopen with mode \"w+\".\n");
+ fd_file = fopen (temp_file, "w+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, 0);
+ TEST_VERIFY (read_buffer[0] == '\0');
+ /* Write should succeed. */
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "w+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 5: This checks for fopen with mode "a". Open for appending
+ (writing at end of file). The file is created if it does not
+ exist. The stream is positioned at the end of the file. */
+ printf ("Test 5: This checks for fopen with mode \"a\".\n");
+ fd_file = fopen (temp_file, "a");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT));
+ /* Read should fail. */
+ errno = 0;
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_VERIFY (ferror (fd_file) != 0);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (ret, 0);
+ clearerr (fd_file);
+ /* Write should succeed. */
+ ret = fwrite (APPENDED_TEXT, sizeof (char), strlen (APPENDED_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (APPENDED_TEXT));
+ /* The file position indicator for the stream is advanced by the
+ * number of bytes successfully read or written. */
+ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT) + ret);
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "a");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 6: This checks for fopen with mode "a+". Open for reading and
+ appending (writing at end of file). The file is created if it does
+ not exist. Output is always appended to the end of the file. The
+ initial file position for reading is at the beginning of the file,
+ but it is advanced to the end prior to each write. */
+ printf ("Test 6: This checks for fopen with mode \"a+\".\n");
+ errno = 0;
+ fd_file = fopen (temp_file, "a+");
+ TEST_COMPARE (errno, 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT));
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT APPENDED_TEXT) == 0);
+ /* Write should succeed. */
+ const char* SECOND_APPEND = "This is second append.";
+ ret = fwrite (SECOND_APPEND, sizeof (char), strlen (SECOND_APPEND), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (SECOND_APPEND));
+ /* The file position indicator for the stream is advanced by the
+ number of bytes successfully read or written. */
+ TEST_COMPARE (ftell (fd_file),
+ strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT) + ret);
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "a+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 7: This checks for fopen with other valid modes set, such as
+ "rc", "we" or "am". The test calls fopen with these modes and
+ checks that no errors appear. */
+ printf ("Test 7: This checks for fopen with other valid modes set, "
+ "such as \"rc\", \"we\" or \"am\".\n");
+ /* These modes all operate correctly with the file already present. */
+ static const char *valid_modes[] =
+ { "rc", "we", "am", "r+x", "wb+", "ab", 0 };
+ const char **p = valid_modes;
+ while (*p != 0)
+ {
+ fd_file = fopen (temp_file, *p);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ xfclose (fd_file);
+ ++p;
+ }
+
+ /* Test 8: This checks for fopen with invalid modes. The test calls
+ fopen with these modes and checks that opening existing files with
+ invalid mode fails and that opening non-existing files with invalid
+ mode doesn't create a new file. */
+ printf ("Test 8: This checks for fopen with invalid modes.\n");
+ static const char *invalid_modes[] = { "0", "tr", "z", "x", " ", 0 };
+ p = invalid_modes;
+ while (*p != 0)
+ {
+ errno = 0;
+ fd_file = fopen (temp_file, *p);
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, EINVAL);
+ errno = 0;
+ fd_file = fopen ("/tmp/file-that-does-not-exist", *p);
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, EINVAL);
+ ++p;
+ TEST_VERIFY (access ("/tmp/file-that-does-not-exist", F_OK) == -1);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 43fcdf1182e735e1..58c33a8e49d517ad 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -131,6 +131,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
tst-sem18 \
tst-sem19 \
tst-join16 \
+ tst-fopen-threaded \
# tests
tests-time64 := \
diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c
new file mode 100644
index 0000000000000000..5c792c93e3711621
--- /dev/null
+++ b/sysdeps/pthread/tst-fopen-threaded.c
@@ -0,0 +1,250 @@
+/* Test for fread and fwrite with multiple threads.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* Description of test intent.
+ The test creates NUM_THREADS threads for reading and writing to the
+ prepared file. The prepared file contains 'NUM_THREADS - 1' bytes
+ where each byte is unique number from 0 to 'NUM_THREADS - 2'. If all
+ operations are correctly multi-threaded safe then all concurent read
+ operations should succeed and read a unique 1 byte value. The last
+ thread to read should get an EOF. In concurrent write, all write
+ operations should succeed and the file should contain all unique 1
+ byte values from 0 to 'NUM_THREADS - 1'. Both concurrent read and
+ concurrent write tests are repeated ITERS times to increase
+ the probability of detecting concurrency issues. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+#include <support/xthread.h>
+
+#define NUM_THREADS 100
+#define ITERS 10
+
+char *temp_file;
+pthread_barrier_t barrier;
+
+struct thread_data
+{
+ FILE *fd;
+ /* Read value or value to be written. */
+ unsigned char value;
+ bool eof;
+};
+
+static void *
+threadReadRoutine (void *argv)
+{
+ struct thread_data *my_data;
+ unsigned char read_buffer;
+ int ret = 0;
+ my_data = (struct thread_data *) argv;
+ /* Wait for all threads to be ready to read. */
+ xpthread_barrier_wait (&barrier);
+
+ ret =
+ fread (&read_buffer, sizeof (char), sizeof (read_buffer), my_data->fd);
+ if (feof (my_data->fd) != 0)
+ {
+ clearerr (my_data->fd);
+ my_data->eof = true;
+ }
+ else
+ {
+ TEST_COMPARE (ret, 1);
+ /* Save the read value. */
+ my_data->value = read_buffer;
+ }
+ TEST_COMPARE (ferror (my_data->fd), 0);
+ return NULL;
+}
+
+void *
+threadWriteRoutine (void *argv)
+{
+ struct thread_data *my_data;
+ int ret = 0;
+ my_data = (struct thread_data *) argv;
+ /* Wait for all threads to be ready to write. */
+ xpthread_barrier_wait (&barrier);
+
+ ret = fwrite (&my_data->value, sizeof (unsigned char), 1, my_data->fd);
+ TEST_COMPARE (ferror (my_data->fd), 0);
+ TEST_COMPARE (feof (my_data->fd), 0);
+ TEST_COMPARE (ret, 1);
+ return NULL;
+}
+
+void *
+threadOpenCloseRoutine (void *argv)
+{
+ /* Wait for all threads to be ready to call fopen and fclose. */
+ xpthread_barrier_wait (&barrier);
+
+ FILE *fd = xfopen ("/tmp/openclosetest", "w+");
+ xfclose (fd);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ FILE *fd_file = NULL;
+ unsigned char buffer[NUM_THREADS] = "0";
+ size_t ret = 0;
+ pthread_t threads[NUM_THREADS];
+ struct thread_data thread_data_array[NUM_THREADS];
+ bool present_values[NUM_THREADS] = { false };
+
+ /* Prepare files. */
+ for (int i = 0; i < NUM_THREADS; i++)
+ buffer[i] = i;
+ int fd = create_temp_file ("tst-fopen.", &temp_file);
+ TEST_VERIFY_EXIT (fd != -1);
+ fd_file = fdopen (fd, "w");
+ /* NUM_THREADS - 1: last thread will read EOF */
+ ret = fwrite (buffer, sizeof (unsigned char), NUM_THREADS - 1, fd_file);
+ TEST_COMPARE (ret, NUM_THREADS - 1);
+ xfclose (fd_file);
+
+ /* Test 1: Concurrent read. */
+ for (int reps = 1; reps <= ITERS; reps++)
+ {
+ fd_file = xfopen (temp_file, "r");
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ thread_data_array[i].fd = fd_file;
+ /* Initialize with highest possible value so it's easier to debug if
+ anything goes wrong. */
+ thread_data_array[i].value = 255;
+ thread_data_array[i].eof = false;
+
+ threads[i] =
+ xpthread_create (support_small_stack_thread_attribute (),
+ threadReadRoutine,
+ (void *) &thread_data_array[i]);
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ xpthread_join (threads[i]);
+ }
+ xpthread_barrier_destroy (&barrier);
+ xfclose (fd_file);
+
+ /* Verify read values. */
+ int eof_cnt = 0;
+ for (int i = 0; i < NUM_THREADS; i++)
+ present_values[i] = false;
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ if (thread_data_array[i].eof)
+ {
+ /* EOF was read. */
+ present_values[NUM_THREADS - 1] = true;
+ eof_cnt++;
+ }
+ else
+ {
+ /* The same value shouldn't be read twice. */
+ TEST_VERIFY (!present_values[thread_data_array[i].value]);
+ present_values[thread_data_array[i].value] = true;
+ }
+ }
+ /* EOF is read exactly once. */
+ TEST_COMPARE (eof_cnt, 1);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ /* All values should be read. */
+ TEST_VERIFY (present_values[i]);
+ }
+ }
+
+ /* Test 2: Concurrent write. */
+ for (int reps = 1; reps <= ITERS; reps++)
+ {
+ fd_file = xfopen (temp_file, "w");
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ thread_data_array[i].fd = fd_file;
+ thread_data_array[i].value = i;
+
+ threads[i] =
+ xpthread_create (support_small_stack_thread_attribute (),
+ threadWriteRoutine,
+ (void *) &thread_data_array[i]);
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ xpthread_join (threads[i]);
+ }
+ xpthread_barrier_destroy (&barrier);
+ xfclose (fd_file);
+
+ /* Verify written values. */
+ for (int i = 0; i < NUM_THREADS; i++)
+ present_values[i] = false;
+ memset (buffer, 0, NUM_THREADS);
+ fd_file = xfopen (temp_file, "r");
+ ret = fread (buffer, sizeof (unsigned char), NUM_THREADS, fd_file);
+ TEST_COMPARE (ret, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ /* The same value shouldn't be written twice. */
+ TEST_VERIFY (!present_values[buffer[i]]);
+ present_values[buffer[i]] = true;
+ }
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ /* All values should be written. */
+ TEST_VERIFY (present_values[i]);
+ }
+ xfclose (fd_file);
+ }
+
+ /* Test 3: Concurrent open/close. */
+ for (int reps = 1; reps <= ITERS; reps++)
+ {
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ threads[i] =
+ xpthread_create (support_small_stack_thread_attribute (),
+ threadOpenCloseRoutine, NULL);
+ }
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ xpthread_join (threads[i]);
+ }
+ xpthread_barrier_destroy (&barrier);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,171 @@
Partial backport (libio/Makefile, stdio-common/Makefile only) of:
commit a7fe3e805d2ee128ac5f43b2a24201726d41cc04
Author: Carlos O'Donell <carlos@redhat.com>
Date: Wed Jun 19 11:48:05 2024 -0400
Fix conditionals on mtrace-based tests (bug 31892)
The conditionals for several mtrace-based tests in catgets, elf, libio,
malloc, misc, nptl, posix, and stdio-common were incorrect leading to
test failures when bootstrapping glibc without perl.
The correct conditional for mtrace-based tests requires three checks:
first checking for run-built-tests, then build-shared, and lastly that
PERL is not equal to "no" (missing perl).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
stdio-common/Makefile
(missing C2x tests tst-printf-binary, tst-printf-intn,
tst-printf-oct, missing test tst-vfprintf-width-i18n
in the downstream tree, but downstream backported
tst-ungetc-leak-mem earlier)
diff --git a/libio/Makefile b/libio/Makefile
index 418102c4c0d8c25a..2ef144268af98f34 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -231,15 +231,28 @@ tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace \
tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
-generated += test-fmemopen.mtrace test-fmemopen.check
-generated += tst-fdopen-seek-failure.mtrace tst-fdopen-seek-failure.check
-generated += tst-fopenloc.mtrace tst-fopenloc.check
-generated += tst-bz22415.mtrace tst-bz22415.check
-
aux := fileops genops stdfiles stdio strops
+ifeq ($(run-built-tests),yes)
+ifeq ($(build-shared),yes)
+ifneq ($(PERL),no)
+generated += \
+ test-fmemopen.check \
+ test-fmemopen.mtrace \
+ tst-bz22415.check \
+ tst-bz22415.mtrace \
+ tst-bz24228.check \
+ tst-bz24228.mtrace \
+ tst-fdopen-seek-failure.check \
+ tst-fdopen-seek-failure.mtrace \
+ tst-fopenloc.check \
+ tst-fopenloc.mtrace \
+ # generated
+endif
+endif
+endif
+
ifeq ($(build-shared),yes)
-generated += tst-bz24228.mtrace tst-bz24228.check
aux += oldfileops oldstdfiles
endif
@@ -250,16 +263,23 @@ shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \
ifeq ($(run-built-tests),yes)
tests-special += \
- $(objpfx)test-fmemopen-mem.out \
$(objpfx)test-freopen.out \
- $(objpfx)tst-bz22415-mem.out \
- $(objpfx)tst-fdopen-seek-failure-mem.out \
# tests-special
ifeq (yes,$(build-shared))
# Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
# library is enabled since they depend on tst-fopenloc.out.
-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
- $(objpfx)tst-bz24228-mem.out
+tests-special += $(objpfx)tst-fopenloc-cmp.out
+ifeq ($(build-shared),yes)
+ifneq ($(PERL),no)
+tests-special += \
+ $(objpfx)test-fmemopen-mem.out \
+ $(objpfx)tst-bz22415-mem.out \
+ $(objpfx)tst-bz24228-mem.out \
+ $(objpfx)tst-fdopen-seek-failure-mem.out \
+ $(objpfx)tst-fopenloc-mem.out \
+ # tests-special
+endif
+endif
endif
tests += \
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 1eaea991dd63e20c..bc314af0617e1647 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -184,10 +184,6 @@ tests := \
tst-perror \
tst-popen \
tst-popen2 \
- tst-printf-bz18872 \
- tst-printf-bz25691 \
- tst-printf-fp-free \
- tst-printf-fp-leak \
tst-printf-round \
tst-printfsz \
tst-put-error \
@@ -208,7 +204,6 @@ tests := \
tst-unlockedio \
tst-vfprintf-mbs-prec \
tst-vfprintf-user-type \
- tst-vfprintf-width-prec \
tst-vfprintf-width-prec-alloc \
tst-wc-printf \
tstdiomisc \
@@ -217,6 +212,20 @@ tests := \
xbug \
# tests
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests += \
+ tst-printf-bz18872 \
+ tst-printf-bz25691 \
+ tst-printf-fp-free \
+ tst-printf-fp-leak \
+ tst-vfprintf-width-prec \
+ # tests
+endif
+endif
+endif
+
test-srcs = \
tst-printf \
tst-printfsz-islongdouble \
@@ -225,15 +234,20 @@ test-srcs = \
ifeq ($(run-built-tests),yes)
tests-special += \
- $(objpfx)tst-printf-bz18872-mem.out \
- $(objpfx)tst-printf-bz25691-mem.out \
- $(objpfx)tst-printf-fp-free-mem.out \
- $(objpfx)tst-printf-fp-leak-mem.out \
$(objpfx)tst-printf.out \
$(objpfx)tst-printfsz-islongdouble.out \
$(objpfx)tst-setvbuf1-cmp.out \
$(objpfx)tst-unbputc.out \
$(objpfx)tst-ungetc-leak-mem.out \
+ # tests-special
+
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests-special += \
+ $(objpfx)tst-printf-bz18872-mem.out \
+ $(objpfx)tst-printf-bz25691-mem.out \
+ $(objpfx)tst-printf-fp-free-mem.out \
+ $(objpfx)tst-printf-fp-leak-mem.out \
$(objpfx)tst-vfprintf-width-prec-mem.out \
# tests-special
@@ -253,6 +267,8 @@ generated += \
tst-vfprintf-width-prec-mem.out \
tst-vfprintf-width-prec.mtrace \
# generated
+endif
+endif
endif # $(run-built-tests)
tests-special += $(objpfx)tst-errno-manual.out

View File

@ -0,0 +1,79 @@
commit 3e4a01870ef9605ccf6475215a4b32aa86d5d206
Author: Aaron Merey <amerey@redhat.com>
Date: Thu Aug 29 12:02:25 2024 -0400
Test fclose on an unopened file.
Add new file libio/tst-fclosed-unopened.c that tests whether fclose on
an unopened file returns EOF.
Calling fclose on unopened files normally causes a use-after-free bug,
however the standard streams are an exception since they are not
deallocated by fclose.
fclose returning EOF for unopened files is not part of the external
contract but there are dependancies on this behaviour. For example,
gnulib's close_stdout in lib/closeout.c.
Tested for x86_64.
Signed-off-by: Aaron Merey <amerey@redhat.com>
diff --git a/libio/Makefile b/libio/Makefile
index 2ef144268af98f34..f0ecb6b775a543af 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -76,6 +76,7 @@ tests = \
tst-eof \
tst-ext \
tst-ext2 \
+ tst-fclose-unopened \
tst-fdopen-seek-failure \
tst-fgetc-after-eof \
tst-fgetwc \
diff --git a/libio/tst-fclose-unopened.c b/libio/tst-fclose-unopened.c
new file mode 100644
index 0000000000000000..1f1cad042d8d72bf
--- /dev/null
+++ b/libio/tst-fclose-unopened.c
@@ -0,0 +1,40 @@
+/* Test using fclose on an unopened file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <support/check.h>
+
+/* Verify that fclose on an unopened file returns EOF. This is not part
+ of the fclose external contract but there are dependancies on this
+ behaviour. */
+
+static int
+do_test (void)
+{
+ TEST_COMPARE (fclose (stdin), 0);
+
+ /* Attempt to close the unopened file and verify that EOF is returned.
+ Calling fclose on a file twice normally causes a use-after-free bug,
+ however the standard streams are an exception since they are not
+ deallocated by fclose. */
+ TEST_COMPARE (fclose (stdin), EOF);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,155 @@
commit 35dc62de3d5d73a91d4ca8fa9799b510a34d170d
Author: Aaron Merey <amerey@redhat.com>
Date: Thu Sep 19 09:53:23 2024 -0400
Add another test for fclose on an unopened file
Add new file libio/tst-fclose-unopened2.c that tests whether fclose on an
unopened file returns EOF.
This test differs from tst-fclose-unopened.c by ensuring the file's buffer
is allocated prior to double-fclose. A comment in tst-fclose-unopened.c
now clarifies that it is testing a file with an unallocated buffer.
Calling fclose on unopened files normally causes a use-after-free bug,
however the standard streams are an exception since they are not
deallocated by fclose.
Tested for x86_64.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/libio/Makefile b/libio/Makefile
index f0ecb6b775a543af..8b2d8aaae563788b 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -77,6 +77,7 @@ tests = \
tst-ext \
tst-ext2 \
tst-fclose-unopened \
+ tst-fclose-unopened2 \
tst-fdopen-seek-failure \
tst-fgetc-after-eof \
tst-fgetwc \
@@ -220,6 +221,9 @@ LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
tst_wprintf2-ARGS = "Some Text"
+tst-fclose-unopened2-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-fclose-unopened2.mtrace \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
tst-fdopen-seek-failure-ENV = \
@@ -244,6 +248,8 @@ generated += \
tst-bz22415.mtrace \
tst-bz24228.check \
tst-bz24228.mtrace \
+ tst-fclose-unopened2.check \
+ tst-fclose-unopened2.mtrace \
tst-fdopen-seek-failure.check \
tst-fdopen-seek-failure.mtrace \
tst-fopenloc.check \
@@ -276,6 +282,7 @@ tests-special += \
$(objpfx)test-fmemopen-mem.out \
$(objpfx)tst-bz22415-mem.out \
$(objpfx)tst-bz24228-mem.out \
+ $(objpfx)tst-fclose-unopened2-mem.out \
$(objpfx)tst-fdopen-seek-failure-mem.out \
$(objpfx)tst-fopenloc-mem.out \
# tests-special
@@ -363,6 +370,11 @@ $(objpfx)test-fmemopen-mem.out: $(objpfx)test-fmemopen.out
$(common-objpfx)malloc/mtrace $(objpfx)test-fmemopen.mtrace > $@; \
$(evaluate-test)
+$(objpfx)tst-fclose-unopened2-mem.out: $(objpfx)tst-fclose-unopened2.out
+ $(common-objpfx)malloc/mtrace \
+ $(objpfx)tst-fclose-unopened2.mtrace > $@; \
+ $(evaluate-test)
+
$(objpfx)tst-fdopen-seek-failure-mem.out: $(objpfx)tst-fdopen-seek-failure.out
$(common-objpfx)malloc/mtrace \
$(objpfx)tst-fdopen-seek-failure.mtrace > $@; \
diff --git a/libio/tst-fclose-unopened.c b/libio/tst-fclose-unopened.c
index 1f1cad042d8d72bf..4fed2ffdfe8cf9b4 100644
--- a/libio/tst-fclose-unopened.c
+++ b/libio/tst-fclose-unopened.c
@@ -19,9 +19,11 @@
#include <stdio.h>
#include <support/check.h>
-/* Verify that fclose on an unopened file returns EOF. This is not part
- of the fclose external contract but there are dependancies on this
- behaviour. */
+/* Verify that fclose on an unopened file returns EOF. This test uses
+ a file with an unallocated buffer.
+
+ This is not part of the fclose external contract but there are
+ dependencies on this behaviour. */
static int
do_test (void)
diff --git a/libio/tst-fclose-unopened2.c b/libio/tst-fclose-unopened2.c
new file mode 100644
index 0000000000000000..1e99d9dc3d561b80
--- /dev/null
+++ b/libio/tst-fclose-unopened2.c
@@ -0,0 +1,51 @@
+/* Test using fclose on an unopened file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <mcheck.h>
+#include <stdio.h>
+#include <support/check.h>
+
+/* Verify that fclose on an unopened file returns EOF. This test uses
+ a file with an allocated buffer.
+
+ This is not part of the fclose external contract but there are
+ dependencies on this behaviour. */
+
+static int
+do_test (void)
+{
+ mtrace ();
+
+ /* Input file tst-fclose-unopened2.input has 6 bytes plus newline. */
+ char buf[6];
+
+ /* Read from the file to ensure its internal buffer is allocated. */
+ TEST_COMPARE (fread (buf, 1, sizeof (buf), stdin), sizeof (buf));
+
+ TEST_COMPARE (fclose (stdin), 0);
+
+ /* Attempt to close the unopened file and verify that EOF is returned.
+ Calling fclose on a file twice normally causes a use-after-free bug,
+ however the standard streams are an exception since they are not
+ deallocated by fclose. */
+ TEST_COMPARE (fclose (stdin), EOF);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/libio/tst-fclose-unopened2.input b/libio/tst-fclose-unopened2.input
new file mode 100644
index 0000000000000000..399f9ba41aff870b
--- /dev/null
+++ b/libio/tst-fclose-unopened2.input
@@ -0,0 +1 @@
+fclose

View File

@ -0,0 +1,273 @@
commit 1d72fa3cfa046f7293421a7e58f2a272474ea901
Author: Sergey Kolosov <skolosov@redhat.com>
Date: Wed Sep 25 15:51:23 2024 +0200
stdio-common: Add new test for fdopen
This commit adds fdopen test with all modes.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index a6816f8bffbd21e0..8c94f0aea0049f56 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -163,6 +163,7 @@ tests := \
tst-bz11319-fortify2 \
tst-cookie \
tst-fdopen \
+ tst-fdopen2 \
tst-ferror \
tst-fgets \
tst-fgets2 \
diff --git a/stdio-common/tst-fdopen2.c b/stdio-common/tst-fdopen2.c
new file mode 100644
index 0000000000000000..0c6625f25853aed5
--- /dev/null
+++ b/stdio-common/tst-fdopen2.c
@@ -0,0 +1,246 @@
+/* Test the fdopen function.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <support/temp_file.h>
+
+char *tmp_dir;
+char *path_to_file;
+
+void
+prepare_tmp_dir (void)
+{
+ tmp_dir = support_create_temp_directory ("tst-fdopen2");
+ path_to_file = xasprintf ("%s/tst-fdopen2.txt", tmp_dir);
+}
+
+/* open temp file descriptor with mode. */
+int
+open_tmp_fd (int mode)
+{
+ int fd = xopen (path_to_file, mode, 0644);
+ return fd;
+}
+
+
+/* close and remove temp file with close. */
+void
+close_tmp_fd (int fd)
+{
+ xclose (fd);
+ xunlink (path_to_file);
+}
+
+/* close and remove temp file with fclose. */
+void
+close_tmp_fp (FILE *fp)
+{
+ fclose (fp);
+ xunlink (path_to_file);
+}
+
+/* test "w" fdopen mode. */
+void
+do_test_fdopen_w (void)
+{
+ int fd, ret;
+ FILE *fp;
+ fd = open_tmp_fd (O_WRONLY | O_CREAT | O_TRUNC);
+
+ /* test mode mismatch. */
+ fp = fdopen (fd, "r");
+ if (fp != NULL || errno != EINVAL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, r) should fail with EINVAL: %m", fd);
+ }
+
+ fp = fdopen (fd, "w");
+ if (fp == NULL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, w): %m", fd);
+ }
+
+ const void *buf = "AAAA";
+ ret = fwrite (buf, 1, 4, fp);
+ if (ret != 4)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fwrite (): %m");
+ }
+
+ unsigned char buf2[4];
+ rewind (fp);
+ clearerr (fp);
+ /* fread should fail in "w" mode */
+ ret = fread (buf2, 1, 4, fp);
+ if (ret != 0 || ferror (fp) == 0)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fread should fail in \"w\" mode");
+ }
+
+ fclose (fp);
+}
+
+/* test "r" fdopen mode. */
+void
+do_test_fdopen_r (void)
+{
+ int fd, ret;
+ FILE *fp;
+ fd = open_tmp_fd (O_RDONLY);
+
+ /* test mode mismatch. */
+ fp = fdopen (fd, "w");
+ if (fp != NULL || errno != EINVAL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, w) should fail with EINVAL: %m", fd);
+ }
+
+ fp = fdopen (fd, "r");
+ if (fp == NULL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, w): %m", fd);
+ }
+
+ const void *buf = "BBBB";
+ /* fwrite should fail in "r" mode. */
+ ret = fwrite (buf, 1, 4, fp);
+ if (ret != 0 || ferror (fp) == 0)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fwrite should fail in \"r\" mode");
+ }
+
+ unsigned char buf2[4];
+ ret = fread (buf2, 1, 4, fp);
+ if (ret != 4)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fread (): %m");
+ }
+
+ fclose (fp);
+}
+
+/* test "a" fdopen mode. */
+void
+do_test_fdopen_a (void)
+{
+ int fd, ret;
+ FILE *fp;
+ fd = open_tmp_fd (O_WRONLY | O_CREAT | O_APPEND);
+
+ /* test mode mismatch. */
+ fp = fdopen (fd, "r+");
+ if (fp != NULL || errno != EINVAL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, \"r+\") should fail with EINVAL: %m", fd);
+ }
+
+ fp = fdopen (fd, "a");
+ if (fp == NULL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, w): %m", fd);
+ }
+
+ const void *buf = "CCCC";
+ ret = fwrite (buf, 1, 4, fp);
+ if (ret != 4)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fwrite (): %m");
+ }
+
+ /* fread should fail in "a" mode. */
+ unsigned char buf2[4];
+ clearerr (fp);
+ ret = fread (buf2, 1, 4, fp);
+ if (ret != 0 || ferror (fp) == 0)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fread should fail \"a\" mode");
+ }
+
+ fclose (fp);
+}
+
+void
+do_test_fdopen_mode (int mode, const char *fmode)
+{
+ int fd, ret;
+ FILE *fp;
+ fd = open_tmp_fd (mode);
+
+ fp = fdopen (fd, fmode);
+ if (fp == NULL)
+ {
+ close_tmp_fd (fd);
+ FAIL_EXIT1 ("fdopen (%d, %s): %m", fd, fmode);
+ }
+
+ const void *buf = "EEEE";
+ ret = fwrite (buf, 1, 4, fp);
+ if (ret != 4)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fwrite () in mode:%s returns %d: %m", fmode, ret);
+ }
+
+ rewind (fp);
+ unsigned char buf2[4];
+ ret = fread (buf2, 1, 4, fp);
+ if (ret != 4)
+ {
+ close_tmp_fp (fp);
+ FAIL_EXIT1 ("fread () in mode:%s returns %d: %m", fmode, ret);
+ }
+
+ fclose (fp);
+}
+
+static int
+do_test (void)
+{
+
+ prepare_tmp_dir ();
+
+ do_test_fdopen_w ();
+ do_test_fdopen_r ();
+ do_test_fdopen_a ();
+
+ /* test r+ w+ a+ fdopen modes. */
+ do_test_fdopen_mode (O_RDWR, "r+");
+ do_test_fdopen_mode (O_RDWR | O_CREAT | O_TRUNC, "w+");
+ do_test_fdopen_mode (O_RDWR | O_CREAT | O_APPEND, "a+");
+ xunlink (path_to_file);
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,167 @@
commit d14c977c65aac7db35bb59380ef99d6582c4f930
Author: Joseph Myers <josmyers@redhat.com>
Date: Tue Sep 24 14:06:22 2024 +0000
Add tests of fread
There seem to be no glibc tests specifically for the fread function.
Add basic tests of that function.
Tested for x86_64.
Conflicts:
stdio-common/Makefile
(usual tests conflict)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 8c94f0aea0049f56..1eaea991dd63e20c 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -174,6 +174,7 @@ tests := \
tst-fmemopen4 \
tst-fphex \
tst-fphex-wide \
+ tst-fread \
tst-fseek \
tst-fwrite \
tst-gets \
diff --git a/stdio-common/tst-fread.c b/stdio-common/tst-fread.c
new file mode 100644
index 0000000000000000..4d9a7895f66a7980
--- /dev/null
+++ b/stdio-common/tst-fread.c
@@ -0,0 +1,134 @@
+/* Test fread.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+int
+do_test (void)
+{
+ char *temp_dir = support_create_temp_directory ("tst-fread");
+ char *file1 = xasprintf ("%s/file1", temp_dir);
+ support_write_file_string (file1, "file1");
+ add_temp_file (file1);
+ FILE *fp;
+ size_t ret;
+ char buf[1024];
+
+ verbose_printf ("test single-byte reads\n");
+ fp = xfopen (file1, "r");
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 1, 2, fp);
+ TEST_COMPARE (ret, 2);
+ TEST_COMPARE (buf[0], 'f');
+ TEST_COMPARE (buf[1], 'i');
+ TEST_COMPARE (feof (fp), 0);
+ TEST_COMPARE (ftell (fp), 2);
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 1, 3, fp);
+ TEST_COMPARE (ret, 3);
+ TEST_COMPARE (buf[0], 'l');
+ TEST_COMPARE (buf[1], 'e');
+ TEST_COMPARE (buf[2], '1');
+ TEST_COMPARE (ftell (fp), 5);
+ TEST_COMPARE (feof (fp), 0);
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 1, 1, fp);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (ftell (fp), 5);
+ xfclose (fp);
+
+ verbose_printf ("test single-byte reads, EOF part way through\n");
+ fp = xfopen (file1, "r");
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 1, sizeof buf, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE (buf[0], 'f');
+ TEST_COMPARE (buf[1], 'i');
+ TEST_COMPARE (buf[2], 'l');
+ TEST_COMPARE (buf[3], 'e');
+ TEST_COMPARE (buf[4], '1');
+ TEST_COMPARE (!!feof (fp), 1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (ftell (fp), 5);
+ xfclose (fp);
+
+ verbose_printf ("test multi-byte reads\n");
+ fp = xfopen (file1, "r");
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 2, 2, fp);
+ TEST_COMPARE (ret, 2);
+ TEST_COMPARE (buf[0], 'f');
+ TEST_COMPARE (buf[1], 'i');
+ TEST_COMPARE (buf[2], 'l');
+ TEST_COMPARE (buf[3], 'e');
+ TEST_COMPARE (feof (fp), 0);
+ TEST_COMPARE (ftell (fp), 4);
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 3, 3, fp);
+ TEST_COMPARE (ret, 0);
+ /* The bytes written for a partial element read are unspecified. */
+ TEST_COMPARE (!!feof (fp), 1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (ftell (fp), 5);
+ xfclose (fp);
+
+ verbose_printf ("test read error\n");
+ fp = xfopen (file1, "r");
+ xclose (fileno (fp));
+ memset (buf, 0, sizeof buf);
+ ret = fread (buf, 1, sizeof buf, fp);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE (feof (fp), 0);
+ TEST_COMPARE (!!ferror (fp), 1);
+ fclose (fp);
+
+ verbose_printf ("test zero size\n");
+ fp = xfopen (file1, "r");
+ ret = fread (buf, 0, SIZE_MAX, fp);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE (feof (fp), 0);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (ftell (fp), 0);
+ xfclose (fp);
+
+ verbose_printf ("test zero items\n");
+ fp = xfopen (file1, "r");
+ ret = fread (buf, SIZE_MAX, 0, fp);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE (feof (fp), 0);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (ftell (fp), 0);
+ xfclose (fp);
+
+ free (temp_dir);
+ free (file1);
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,67 @@
commit e3fdbe9f39747206b9c3fbb0219f29fd5b35d020
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Apr 8 17:36:07 2021 -0300
support: Add xmkfifo
Wrapper support mkfifo.
diff --git a/support/Makefile b/support/Makefile
index 25e8bbefd78c2268..0273c0f6306720c9 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -137,6 +137,7 @@ libsupport-routines = \
xmemstream \
xmkdir \
xmkdirp \
+ xmkfifo \
xmmap \
xmprotect \
xmunmap \
diff --git a/support/xmkfifo.c b/support/xmkfifo.c
new file mode 100644
index 0000000000000000..a8e196dbc209a47d
--- /dev/null
+++ b/support/xmkfifo.c
@@ -0,0 +1,29 @@
+/* mkfifo with error checking.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+void
+xmkfifo (const char *pathname, mode_t mode)
+{
+ int r = mkfifo (pathname, mode);
+ if (r < 0)
+ FAIL_EXIT1 ("mkfifo (%s, 0%o): %m", pathname, mode);
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index a25ecf1cf38ef328..94b1e1eb1b1e8253 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -61,6 +61,7 @@ void xsymlink (const char *target, const char *linkpath);
void xchdir (const char *path);
void xfchmod (int fd, mode_t mode);
void xchmod (const char *pathname, mode_t mode);
+void xmkfifo (const char *pathname, mode_t mode);
/* Equivalent of "mkdir -p". */
void xmkdirp (const char *, mode_t);

View File

@ -0,0 +1,30 @@
commit 6948ee4edf0c57c556f8d5f394d9191216d05780
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Sep 28 21:06:11 2024 +0200
stdio-common: Fix memory leak in tst-freopen4* tests on UNSUPPORTED
The temp_dir allocation leaks if support_can_chroot returns false.
diff --git a/stdio-common/tst-freopen4-main.c b/stdio-common/tst-freopen4-main.c
index e169442cf4df2e9d..7284677a97e10af6 100644
--- a/stdio-common/tst-freopen4-main.c
+++ b/stdio-common/tst-freopen4-main.c
@@ -33,7 +33,7 @@ int
do_test (void)
{
mtrace ();
- char *temp_dir = support_create_temp_directory ("tst-freopen4");
+ char *temp_dir;
FILE *fp;
int ret;
@@ -45,6 +45,8 @@ do_test (void)
support_become_root ();
if (!support_can_chroot ())
return EXIT_UNSUPPORTED;
+
+ temp_dir = support_create_temp_directory ("tst-freopen4");
xchroot (temp_dir);
/* Test freopen with NULL, renamed file. This verifies that

View File

@ -0,0 +1,216 @@
commit 42c810c2cf3554afbdd60885b7da6bb4e702466f
Author: Joseph Myers <josmyers@redhat.com>
Date: Mon Oct 7 19:44:25 2024 +0000
Add freopen special-case tests: thread cancellation
Add tests of freopen adding or removing "c" (non-cancelling I/O) from
the mode string (so completing my planned tests of freopen with
different features used in the mode strings). Note that it's in the
nature of the uncertain time at which cancellation might act (possibly
during freopen, possibly during subsequent reads) that these can leak
memory or file descriptors, so these do not include leak tests.
Tested for x86_64.
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index c920f55ed2119900..09d3622823203f74 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -180,10 +180,12 @@ tests := \
tst-freopen4 \
tst-freopen5 \
tst-freopen6 \
+ tst-freopen7 \
tst-freopen64-2 \
tst-freopen64-3 \
tst-freopen64-4 \
tst-freopen64-6 \
+ tst-freopen64-7 \
tst-fseek \
tst-fwrite \
tst-getline \
@@ -480,3 +482,6 @@ $(objpfx)tst-setvbuf1-cmp.out: tst-setvbuf1.expect $(objpfx)tst-setvbuf1.out
$(objpfx)tst-printf-round: $(libm)
$(objpfx)tst-scanf-round: $(libm)
+
+$(objpfx)tst-freopen7: $(shared-thread-library)
+$(objpfx)tst-freopen64-7: $(shared-thread-library)
diff --git a/stdio-common/tst-freopen64-7.c b/stdio-common/tst-freopen64-7.c
new file mode 100644
index 0000000000000000..f34c2805210079b9
--- /dev/null
+++ b/stdio-common/tst-freopen64-7.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen64
+#include <tst-freopen7-main.c>
diff --git a/stdio-common/tst-freopen7-main.c b/stdio-common/tst-freopen7-main.c
new file mode 100644
index 0000000000000000..965e0b4adce750cc
--- /dev/null
+++ b/stdio-common/tst-freopen7-main.c
@@ -0,0 +1,155 @@
+/* Test freopen cancellation handling.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mcheck.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#include <support/check.h>
+#include <support/file_contents.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+
+char *file1, *file2, *file3, *fifo;
+
+sem_t sem;
+
+void *
+test_rc_to_r (void *p)
+{
+ int ret;
+ FILE *fp, *fp2;
+ ret = sem_post (&sem);
+ TEST_VERIFY_EXIT (ret == 0);
+ fp = xfopen (file1, "rc");
+ for (int i = 0; i < 1000000; i++)
+ {
+ fgetc (fp);
+ fseek (fp, 0, SEEK_SET);
+ }
+ fp2 = xfopen (file3, "wc");
+ fputs ("rc_to_r got to freopen", fp2);
+ xfclose (fp2);
+ /* Cancellation should occur at some point from here onwards
+ (possibly leaking memory and file descriptors associated with the
+ FILE). */
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ for (;;)
+ {
+ fgetc (fp);
+ fseek (fp, 0, SEEK_SET);
+ }
+}
+
+void *
+test_r_to_rc (void *p)
+{
+ int ret;
+ FILE *fp;
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (fifo, "rc", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = sem_post (&sem);
+ TEST_VERIFY_EXIT (ret == 0);
+ /* No cancellation should occur for I/O on fifo. */
+ ret = fgetc (fp);
+ /* At this point, the other thread has called pthread_cancel and
+ then written a byte to the fifo, so this thread is cancelled at
+ the next cancellation point. */
+ TEST_VERIFY (ret == 'x');
+ xfclose (fp);
+ fp = xfopen (file3, "wc");
+ fputs ("r_to_rc got to fclose", fp);
+ xfclose (fp);
+ pthread_testcancel ();
+ FAIL_EXIT1 ("test_r_to_rc not cancelled\n");
+}
+
+int
+do_test (void)
+{
+ char *temp_dir = support_create_temp_directory ("tst-freopen-cancel");
+ file1 = xasprintf ("%s/file1", temp_dir);
+ support_write_file_string (file1, "file1");
+ add_temp_file (file1);
+ file2 = xasprintf ("%s/file2", temp_dir);
+ support_write_file_string (file2, "file2");
+ add_temp_file (file2);
+ file3 = xasprintf ("%s/file3", temp_dir);
+ support_write_file_string (file3, "file3");
+ add_temp_file (file3);
+ fifo = xasprintf ("%s/fifo", temp_dir);
+ xmkfifo (fifo, 0666);
+ add_temp_file (fifo);
+ int ret;
+ pthread_t thr;
+ void *retval;
+
+ /* Test changing to/from c (cancellation disabled). */
+
+ verbose_printf ("Testing rc -> r\n");
+ ret = sem_init (&sem, 0, 0);
+ TEST_VERIFY_EXIT (ret == 0);
+ thr = xpthread_create (NULL, test_rc_to_r, NULL);
+ ret = sem_wait (&sem);
+ TEST_VERIFY_EXIT (ret == 0);
+ xpthread_cancel (thr);
+ ret = pthread_join (thr, &retval);
+ TEST_COMPARE (ret, 0);
+ TEST_VERIFY (retval == PTHREAD_CANCELED);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file3, "rc_to_r got to freopen");
+
+ verbose_printf ("Testing r -> rc\n");
+ ret = sem_init (&sem, 0, 0);
+ TEST_VERIFY_EXIT (ret == 0);
+ thr = xpthread_create (NULL, test_r_to_rc, NULL);
+ FILE *fp = xfopen (fifo, "w");
+ ret = sem_wait (&sem);
+ TEST_VERIFY_EXIT (ret == 0);
+ /* This call happens while, or before, the other thread is waiting
+ to read a character from the fifo. It thus verifies that
+ cancellation does not occur from the fgetc call in that thread
+ (it should instead occur only in pthread_testcancel call),
+ because the expected string is only written to file3 after that
+ thread closes the fifo. */
+ xpthread_cancel (thr);
+ fputc ('x', fp);
+ xfclose (fp);
+ ret = pthread_join (thr, &retval);
+ TEST_COMPARE (ret, 0);
+ TEST_VERIFY (retval == PTHREAD_CANCELED);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file3, "r_to_rc got to fclose");
+
+ free (temp_dir);
+ free (file1);
+ free (file2);
+ free (file3);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-freopen7.c b/stdio-common/tst-freopen7.c
new file mode 100644
index 0000000000000000..03d0de798e3d2616
--- /dev/null
+++ b/stdio-common/tst-freopen7.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen
+#include <tst-freopen7-main.c>

View File

@ -0,0 +1,168 @@
commit da55fae9e277a0c138d4395fee505e5d2f8b2b84
Author: Carlos O'Donell <carlos@redhat.com>
Date: Tue May 23 08:34:56 2023 -0400
support: Reformat Makefile.
Add list end markers.
Sort text using scripts/sort-makefile-lines.py.
No code generation changes observed in non-test binary artifacts.
No regressions on x86_64 and i686.
Conflicts:
support/Makefile
(different backport order)
diff --git a/support/Makefile b/support/Makefile
index 0273c0f6306720c9..17a4157563f9ecd6 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -41,7 +41,7 @@ libsupport-routines = \
resolv_response_context_free \
resolv_test \
set_fortify_handler \
- support_stack_alloc \
+ support-open-dev-null-range \
support_become_root \
support_can_chroot \
support_capture_subprocess \
@@ -65,12 +65,11 @@ libsupport-routines = \
support_fuse \
support_isolate_in_subprocess \
support_need_proc \
+ support_openpty \
support_path_support_time64 \
+ support_paths \
support_process_state \
support_ptrace \
- support-open-dev-null-range \
- support_openpty \
- support_paths \
support_quote_blob \
support_quote_blob_wide \
support_quote_string \
@@ -84,6 +83,8 @@ libsupport-routines = \
support_shared_allocate \
support_small_stack_thread_attribute \
support_socket_so_timestamp_time64 \
+ support_stack_alloc \
+ support_stack_alloc \
support_stat_nanoseconds \
support_subprocess \
support_test_compare_blob \
@@ -96,11 +97,11 @@ libsupport-routines = \
support_write_file_string \
temp_file \
timespec \
- timespec-time64 \
timespec-add \
timespec-add-time64 \
timespec-sub \
timespec-sub-time64 \
+ timespec-time64 \
write_message \
xaccept \
xaccept4 \
@@ -108,6 +109,8 @@ libsupport-routines = \
xbind \
xcalloc \
xchdir \
+ xchmod \
+ xchmod \
xchroot \
xclock_gettime \
xclock_gettime_time64 \
@@ -116,7 +119,6 @@ libsupport-routines = \
xclone \
xclose \
xclosedir \
- xchmod \
xconnect \
xcopy_file_range \
xdlfcn \
@@ -147,11 +149,17 @@ libsupport-routines = \
xpipe \
xpoll \
xposix_memalign \
+ xposix_spawn \
+ xposix_spawn \
+ xposix_spawn_file_actions_addclose \
+ xposix_spawn_file_actions_addclose \
+ xposix_spawn_file_actions_adddup2 \
+ xposix_spawn_file_actions_adddup2 \
xpthread_attr_destroy \
xpthread_attr_init \
+ xpthread_attr_setaffinity_np \
xpthread_attr_setdetachstate \
xpthread_attr_setguardsize \
- xpthread_attr_setaffinity_np \
xpthread_attr_setstack \
xpthread_attr_setstacksize \
xpthread_barrier_destroy \
@@ -162,8 +170,8 @@ libsupport-routines = \
xpthread_barrierattr_setpshared \
xpthread_cancel \
xpthread_check_return \
- xpthread_cond_wait \
xpthread_cond_signal \
+ xpthread_cond_wait \
xpthread_create \
xpthread_detach \
xpthread_join \
@@ -182,8 +190,8 @@ libsupport-routines = \
xpthread_mutexattr_setrobust \
xpthread_mutexattr_settype \
xpthread_once \
- xpthread_rwlock_init \
xpthread_rwlock_destroy \
+ xpthread_rwlock_init \
xpthread_rwlock_rdlock \
xpthread_rwlock_unlock \
xpthread_rwlock_wrlock \
@@ -204,9 +212,6 @@ libsupport-routines = \
xsigstack \
xsocket \
xstatx \
- xposix_spawn \
- xposix_spawn_file_actions_addclose \
- xposix_spawn_file_actions_adddup2 \
xstrdup \
xstrndup \
xsymlink \
@@ -215,6 +220,7 @@ libsupport-routines = \
xuselocale \
xwaitpid \
xwrite \
+ # libsupport-routines
libsupport-static-only-routines := $(libsupport-routines)
# Only build one variant of the library.
@@ -278,8 +284,16 @@ LDLIBS-test-container = $(libsupport)
others += test-container
others-noinstall += test-container
-others += shell-container echo-container true-container
-others-noinstall += shell-container echo-container true-container
+others += \
+ echo-container \
+ shell-container \
+ true-container \
+ # others
+others-noinstall += \
+ echo-container \
+ shell-container \
+ true-container \
+ # others-noinstall
others += $(LINKS_DSO_PROGRAM)
others-noinstall += $(LINKS_DSO_PROGRAM)
@@ -317,6 +331,7 @@ tests = \
tst-xdirent \
tst-xreadlink \
tst-xsigstack \
+ # tests
ifeq ($(run-built-tests),yes)
tests-special = \

View File

@ -0,0 +1,261 @@
commit 96d0bf98cafd0b63721f369ca21ec64590551d47
Author: Joseph Myers <josmyers@redhat.com>
Date: Tue Sep 3 13:53:01 2024 +0000
Add support/ code for checking file contents
For use in freopen tests, add various support/ helper interfaces for
use in checking file contents.
Tested for x86_64.
diff --git a/support/Makefile b/support/Makefile
index 38ad266a0dec8e36..e70322cea06f137b 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -48,6 +48,8 @@ libsupport-routines = \
support_check_stat_fd \
support_check_stat_path \
support_chroot \
+ support_compare_file_bytes \
+ support_compare_file_string \
support_copy_file \
support_copy_file_range \
support_create_timer \
@@ -64,6 +66,8 @@ libsupport-routines = \
support_fuse \
support_isolate_in_subprocess \
support_need_proc \
+ support_open_and_compare_file_bytes \
+ support_open_and_compare_file_string \
support_openpty \
support_path_support_time64 \
support_paths \
diff --git a/support/file_contents.h b/support/file_contents.h
new file mode 100644
index 0000000000000000..9b2d750aae8a885a
--- /dev/null
+++ b/support/file_contents.h
@@ -0,0 +1,63 @@
+/* Functionality for checking file contents.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_FILE_CONTENTS_H
+#define SUPPORT_FILE_CONTENTS_H
+
+#include <support/check.h>
+#include <stdio.h>
+
+__BEGIN_DECLS
+
+/* Check that an already-open file has exactly the given bytes,
+ starting at the current location in the file. The file position
+ indicator is updated to point after the bytes compared. Return 0
+ if equal, 1 otherwise or on read error. */
+int support_compare_file_bytes (FILE *fp, const char *contents, size_t length);
+
+/* Check that an already-open file has exactly the given string as
+ contents, starting at the current offset. The file position
+ indicator is updated to point after the bytes compared. Return 0
+ if equal, 1 otherwise or on read error. */
+int support_compare_file_string (FILE *fp, const char *contents);
+
+/* Check that a not-currently-open file has exactly the given bytes.
+ Return 0 if equal, 1 otherwise or on read error. */
+int support_open_and_compare_file_bytes (const char *file,
+ const char *contents,
+ size_t length);
+
+/* Check that a not-currently-open file has exactly the given string
+ as contents, starting at the current offset. Return 0 if equal, 1
+ otherwise or on read error. */
+int support_open_and_compare_file_string (const char *file,
+ const char *contents);
+
+/* Compare bytes read from an open file with the given string. The
+ file position indicator is updated to point after the bytes
+ compared. */
+#define TEST_COMPARE_FILE_STRING(FP, CONTENTS) \
+ TEST_COMPARE (support_compare_file_string (FP, CONTENTS), 0)
+
+/* Read a file and compare bytes read from it with the given string. */
+#define TEST_OPEN_AND_COMPARE_FILE_STRING(FILE, CONTENTS) \
+ TEST_COMPARE (support_open_and_compare_file_string (FILE, CONTENTS), 0)
+
+__END_DECLS
+
+#endif /* SUPPORT_FILE_CONTENTS_H */
diff --git a/support/support_compare_file_bytes.c b/support/support_compare_file_bytes.c
new file mode 100644
index 0000000000000000..e261e1da8f7b02b2
--- /dev/null
+++ b/support/support_compare_file_bytes.c
@@ -0,0 +1,42 @@
+/* Compare bytes from an open file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+#include <support/file_contents.h>
+
+/* Check that an already-open file has exactly the given bytes,
+ starting at the current offset. */
+
+int
+support_compare_file_bytes (FILE *fp, const char *contents, size_t length)
+{
+ int c;
+ while (length > 0)
+ {
+ c = getc (fp);
+ if (c == EOF || (unsigned char) c != (unsigned char) contents[0])
+ return 1;
+ contents++;
+ length--;
+ }
+ c = getc (fp);
+ if (c != EOF || ferror (fp))
+ return 1;
+ return 0;
+}
diff --git a/support/support_compare_file_string.c b/support/support_compare_file_string.c
new file mode 100644
index 0000000000000000..04513c3af197037d
--- /dev/null
+++ b/support/support_compare_file_string.c
@@ -0,0 +1,28 @@
+/* Compare string from an open file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <support/file_contents.h>
+
+int
+support_compare_file_string (FILE *fp, const char *contents)
+{
+ return support_compare_file_bytes (fp, contents, strlen (contents));
+}
diff --git a/support/support_open_and_compare_file_bytes.c b/support/support_open_and_compare_file_bytes.c
new file mode 100644
index 0000000000000000..f804ed8e460d82f0
--- /dev/null
+++ b/support/support_open_and_compare_file_bytes.c
@@ -0,0 +1,33 @@
+/* Compare bytes from a file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/file_contents.h>
+#include <support/xstdio.h>
+
+/* Check that a not-currently-open file has exactly the given
+ bytes. */
+
+int
+support_open_and_compare_file_bytes (const char *file, const char *contents,
+ size_t length)
+{
+ FILE *fp = xfopen (file, "r");
+ int ret = support_compare_file_bytes (fp, contents, length);
+ xfclose (fp);
+ return ret;
+}
diff --git a/support/support_open_and_compare_file_string.c b/support/support_open_and_compare_file_string.c
new file mode 100644
index 0000000000000000..2b596d4c88b697f2
--- /dev/null
+++ b/support/support_open_and_compare_file_string.c
@@ -0,0 +1,32 @@
+/* Compare string from a file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+#include <support/file_contents.h>
+#include <support/xstdio.h>
+
+/* Check that a not-currently-open file has exactly the given string
+ as contents, starting at the current offset. */
+
+int
+support_open_and_compare_file_string (const char *file, const char *contents)
+{
+ return support_open_and_compare_file_bytes (file, contents,
+ strlen (contents));
+}

View File

@ -0,0 +1,739 @@
commit ed4bb289cf739f537deb735eaa01be531df084b9
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Sep 4 16:32:21 2024 +0000
Add more thorough tests of freopen
freopen is rather minimally tested in libio/tst-freopen and
libio/test-freopen. Add some more thorough tests, covering different
cases for change of mode in particular. The tests are run for both
freopen and freopen64 (given that those functions have two separate
copies of much of the code, so any bug fix directly in the freopen
code would probably need applying in both places).
Note that there are two parts of the tests disabled because of bugs
discovered through running the tests, with bug numbers given in
comments. I expect to address those separately. The tests also don't
cover changes to cancellation ("c" in mode); I think that will better
be handled through a separate test. Also to handle separately:
testing on stdin / stdout / stderr; documenting lack of support for
streams opened with popen / fmemopen / open_memstream / fopencookie;
maybe also a chroot test without /proc; maybe also more thorough tests
for large file handling on 32-bit systems (freopen64).
Tested for x86_64.
Conflicts:
stdio-common/Makefile
(tst-fread already backported)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index ea8598bbe3a6dfdd..5eddc4bfbf4e7fb9 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -175,6 +175,10 @@ tests := \
tst-fphex \
tst-fphex-wide \
tst-fread \
+ tst-freopen2 \
+ tst-freopen3 \
+ tst-freopen64-2 \
+ tst-freopen64-3 \
tst-fseek \
tst-fwrite \
tst-getline \
@@ -246,6 +250,8 @@ tests-special += \
ifeq (yes,$(build-shared))
ifneq ($(PERL),no)
tests-special += \
+ $(objpfx)tst-freopen2-mem.out \
+ $(objpfx)tst-freopen64-2-mem.out \
$(objpfx)tst-getline-enomem-mem.out \
$(objpfx)tst-getline-mem.out \
$(objpfx)tst-printf-bz18872-mem.out \
@@ -256,6 +262,10 @@ tests-special += \
# tests-special
generated += \
+ tst-freopen2-mem.out \
+ tst-freopen2.mtrace \
+ tst-freopen64-2-mem.out \
+ tst-freopen64-2.mtrace \
tst-getline-enomem-mem.out \
tst-getline-enomem.mtrace \
tst-getline-mem.out \
@@ -328,6 +338,12 @@ tst-getline-ENV = \
tst-getline-enomem-ENV = \
MALLOC_TRACE=$(objpfx)tst-getline-enomem.mtrace \
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen2-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen2.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen64-2-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen64-2.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c
new file mode 100644
index 0000000000000000..22b21afebf709563
--- /dev/null
+++ b/stdio-common/tst-freopen2-main.c
@@ -0,0 +1,526 @@
+/* Test freopen.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/file_contents.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+
+#define START_TEST(DESC) \
+ do \
+ { \
+ fds = support_descriptors_list (); \
+ verbose_printf (DESC); \
+ } \
+ while (0)
+
+#define END_TEST \
+ do \
+ { \
+ support_descriptors_check (fds); \
+ support_descriptors_free (fds); \
+ } \
+ while (0)
+
+int
+do_test (void)
+{
+ mtrace ();
+ struct support_descriptors *fds;
+ char *temp_dir = support_create_temp_directory ("tst-freopen2");
+ char *file1 = xasprintf ("%s/file1", temp_dir);
+ support_write_file_string (file1, "file1");
+ add_temp_file (file1);
+ char *file2 = xasprintf ("%s/file2", temp_dir);
+ support_write_file_string (file2, "file2");
+ add_temp_file (file2);
+ char *file3 = xasprintf ("%s/file3", temp_dir);
+ char *file4 = xasprintf ("%s/file4", temp_dir);
+ char *file1a = xasprintf ("%s/file1a", temp_dir);
+ FILE *fp;
+ int ret;
+ wint_t wc;
+
+ /* Test each pair of old and new modes from r w a. */
+
+ START_TEST ("Testing r -> r\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "file2");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("Testing r -> w\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("File2new", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file1, "file1");
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "File2new");
+ END_TEST;
+
+ START_TEST ("Testing r -> a\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "a", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("3", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "File2new3");
+ END_TEST;
+
+ START_TEST ("Testing w -> r\n");
+ fp = xfopen (file1, "w");
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "File2new3");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("Testing w -> w\n");
+ fp = xfopen (file1, "w");
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("next", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file1, "");
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "next");
+ END_TEST;
+
+ START_TEST ("Testing w -> a\n");
+ fp = xfopen (file1, "w");
+ fp = FREOPEN (file2, "a", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("4", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "next4");
+ END_TEST;
+
+ START_TEST ("Testing a -> r\n");
+ fp = xfopen (file1, "a");
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "next4");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("Testing a -> w\n");
+ fp = xfopen (file1, "a");
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("another", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another");
+ END_TEST;
+
+ START_TEST ("Testing a -> a\n");
+ fp = xfopen (file1, "a");
+ fp = FREOPEN (file2, "a", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("5", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another5");
+ END_TEST;
+
+ /* Test for file originally opened with fopen64. */
+ START_TEST ("Testing fopen64 a -> a\n");
+ fp = fopen64 (file1, "a");
+ TEST_VERIFY_EXIT (fp != NULL);
+ fp = FREOPEN (file2, "a", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("64", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another564");
+ END_TEST;
+
+ /* Test calling freopen more than once on the same FILE *. */
+
+ START_TEST ("Testing r -> w -> r\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("freopen-twice", fp);
+ TEST_VERIFY (ret >= 0);
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice");
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "freopen-twice");
+ END_TEST;
+
+ START_TEST ("Testing r -> w -> r (exactly one freopen64)\n");
+ fp = xfopen (file1, "r");
+ fp = OTHER_FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("freopen-twice64", fp);
+ TEST_VERIFY (ret >= 0);
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64");
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "freopen-twice64");
+ END_TEST;
+
+ /* Test changing to/from b (binary, no-op). */
+
+ START_TEST ("Testing rb -> r\n");
+ fp = xfopen (file1, "rb");
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("Testing r -> rb\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "rb", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test changing to/from + (read-and-write). */
+
+ START_TEST ("Testing r -> w+\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "w+", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("latest", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = fseek (fp, 0, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE_FILE_STRING (fp, "latest");
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "latest");
+ END_TEST;
+
+ START_TEST ("Testing w -> a+\n");
+ fp = xfopen (file1, "w");
+ fp = FREOPEN (file2, "a+", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("suffix", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = fseek (fp, 0, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE_FILE_STRING (fp, "latestsuffix");
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "latestsuffix");
+ END_TEST;
+
+ START_TEST ("Testing a -> r+\n");
+ fp = xfopen (file1, "a");
+ fp = FREOPEN (file2, "r+", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "latestsuffix");
+ ret = fseek (fp, 0, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ ret = fputs ("new", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "newestsuffix");
+ END_TEST;
+
+ START_TEST ("Testing r+ -> w\n");
+ fp = xfopen (file1, "r+");
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("plusto", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = fseek (fp, 0, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ errno = 0;
+ TEST_COMPARE (fgetc (fp), EOF);
+ TEST_COMPARE (errno, EBADF);
+ clearerr (fp);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plusto");
+ END_TEST;
+
+ START_TEST ("Testing w+ -> a\n");
+ fp = xfopen (file1, "w+");
+ fp = FREOPEN (file2, "a", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("more", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = fseek (fp, 0, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ errno = 0;
+ TEST_COMPARE (fgetc (fp), EOF);
+ TEST_COMPARE (errno, EBADF);
+ clearerr (fp);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plustomore");
+ END_TEST;
+
+ START_TEST ("Testing a+ -> r\n");
+ fp = xfopen (file1, "a+");
+ fp = FREOPEN (file2, "rr", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
+ ret = fputs ("2", fp);
+ TEST_COMPARE (ret, EOF);
+ clearerr (fp);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plustomore");
+ END_TEST;
+
+ /* Test changing to/from e (FD_CLOEXEC). */
+
+ START_TEST ("Testing re -> r\n");
+ fp = xfopen (file1, "re");
+ ret = fcntl (fileno (fp), F_GETFD);
+ TEST_VERIFY (ret != -1);
+ TEST_COMPARE (ret & FD_CLOEXEC, FD_CLOEXEC);
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fcntl (fileno (fp), F_GETFD);
+ TEST_VERIFY (ret != -1);
+#if 0 /* Fails to clear FD_CLOEXEC (bug 32134). */
+ TEST_COMPARE (ret & FD_CLOEXEC, 0);
+#endif
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("Testing r -> re\n");
+ fp = xfopen (file1, "r");
+ ret = fcntl (fileno (fp), F_GETFD);
+ TEST_VERIFY (ret != -1);
+ TEST_COMPARE (ret & FD_CLOEXEC, 0);
+ fp = FREOPEN (file2, "re", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fcntl (fileno (fp), F_GETFD);
+ TEST_VERIFY (ret != -1);
+ TEST_COMPARE (ret & FD_CLOEXEC, FD_CLOEXEC);
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test changing to/from m (mmap) (a no-op as far as testing
+ semantics is concerned). */
+
+ START_TEST ("Testing rm -> r\n");
+ fp = xfopen (file1, "rm");
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("Testing r -> rm\n");
+ fp = xfopen (file1, "r");
+ fp = FREOPEN (file2, "rm", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test changing to/from x (O_EXCL). */
+
+ START_TEST ("Testing wx -> w\n");
+ fp = xfopen (file3, "wx");
+ add_temp_file (file3);
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = fputs ("wxtow", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "wxtow");
+ END_TEST;
+
+ START_TEST ("Testing w -> wx (file does not exist)\n");
+ fp = xfopen (file1, "w");
+ fp = FREOPEN (file4, "wx", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ add_temp_file (file4);
+ ret = fputs ("wtowx", fp);
+ TEST_VERIFY (ret >= 0);
+ xfclose (fp);
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file4, "wtowx");
+ END_TEST;
+
+ /* Test with ,ccs=CHARSET. */
+
+ START_TEST ("testing w,ccs=utf-8 -> r\n");
+ fp = xfopen (file1, "w,ccs=utf-8");
+ ret = fputws (L"\xc0\xc1", fp);
+ TEST_VERIFY (ret >= 0);
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "wxtow");
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("testing w,ccs=iso-8859-1 -> r,ccs=utf-8\n");
+ fp = xfopen (file2, "w,ccs=iso-8859-1");
+ ret = fputws (L"\xc0\xc1", fp);
+ TEST_VERIFY (ret >= 0);
+#if 0 /* Doesn't work (bug 23675). */
+ fp = FREOPEN (file1, "r,ccs=utf-8", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+#else /* Works instead. */
+ xfclose (fp);
+ fp = xfopen (file1, "r,ccs=utf-8");
+#endif
+ wc = fgetwc (fp);
+ TEST_COMPARE (wc, (wint_t) 0xc0);
+ wc = fgetwc (fp);
+ TEST_COMPARE (wc, (wint_t) 0xc1);
+ wc = fgetwc (fp);
+ TEST_COMPARE (wc, WEOF);
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("testing r,ccs=utf-8 -> r\n");
+ fp = xfopen (file1, "r,ccs=utf-8");
+ fp = FREOPEN (file1, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "\u00c0\u00c1");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test that errors closing the old file are ignored. */
+
+ START_TEST ("testing errors closing old file ignored\n");
+ fp = xfopen ("/dev/full", "w");
+ fputc ('x', fp);
+ fp = FREOPEN (file1, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "\u00c0\u00c1");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test that error / EOF state from the old file are cleared. */
+
+ START_TEST ("testing error state from old file cleared\n");
+ fp = xfopen ("/dev/full", "w");
+ fputc ('x', fp);
+ fflush (fp);
+ TEST_VERIFY (ferror (fp));
+ TEST_VERIFY (!feof (fp));
+ fp = FREOPEN (file2, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_VERIFY (!ferror (fp));
+ TEST_VERIFY (!feof (fp));
+ xfclose (fp);
+ END_TEST;
+
+ START_TEST ("testing EOF state from old file cleared\n");
+ fp = xfopen ("/dev/null", "r");
+ fgetc (fp);
+ TEST_VERIFY (!ferror (fp));
+ TEST_VERIFY (feof (fp));
+ fp = FREOPEN (file2, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_VERIFY (!ferror (fp));
+ TEST_VERIFY (!feof (fp));
+ xfclose (fp);
+ END_TEST;
+
+ /* Test freopen with NULL, same mode (should flush content and reset
+ file offset). */
+
+ START_TEST ("testing freopen with NULL, same mode\n");
+ fp = xfopen (file1, "r+");
+ ret = fputs ("same mode", fp);
+ TEST_VERIFY (ret >= 0);
+ fp = FREOPEN (NULL, "r+", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "same mode");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test freopen with NULL, different mode. */
+
+ START_TEST ("testing freopen with NULL, different mode\n");
+ fp = xfopen (file1, "w");
+ ret = fputs ("different mode", fp);
+ TEST_VERIFY (ret >= 0);
+ fp = FREOPEN (NULL, "r", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "different mode");
+ xfclose (fp);
+ END_TEST;
+
+ /* Test freopen with NULL, renamed file. This verifies that
+ reopening succeeds (and resets the file position indicator to
+ start of file) even when the original path could no longer be
+ opened. */
+
+ START_TEST ("testing freopen with NULL, renamed file\n");
+ fp = xfopen (file1, "r+");
+ ret = fputs ("file has been renamed", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = rename (file1, file1a);
+ TEST_COMPARE (ret, 0);
+ fp = FREOPEN (NULL, "r+", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "file has been renamed");
+ xfclose (fp);
+ ret = rename (file1a, file1);
+ TEST_COMPARE (ret, 0);
+ END_TEST;
+
+ /* Test freopen with NULL, deleted file. This verifies that
+ reopening succeeds (and resets the file position indicator to
+ start of file) even when the original path could no longer be
+ opened. */
+
+ START_TEST ("testing freopen with NULL, deleted file\n");
+ fp = xfopen (file1, "r+");
+ ret = fputs ("file has now been deleted", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = remove (file1);
+ TEST_COMPARE (ret, 0);
+ fp = FREOPEN (NULL, "r+", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_COMPARE_FILE_STRING (fp, "file has now been deleted");
+ xfclose (fp);
+ /* Recreate the file so it is present when expected for temporary
+ file deletion. */
+ support_write_file_string (file1, "file1");
+ END_TEST;
+
+ free (temp_dir);
+ free (file1);
+ free (file2);
+ free (file3);
+ free (file4);
+ free (file1a);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-freopen2.c b/stdio-common/tst-freopen2.c
new file mode 100644
index 0000000000000000..11ec7a9783b7caa3
--- /dev/null
+++ b/stdio-common/tst-freopen2.c
@@ -0,0 +1,3 @@
+#define FREOPEN freopen
+#define OTHER_FREOPEN freopen64
+#include <tst-freopen2-main.c>
diff --git a/stdio-common/tst-freopen3-main.c b/stdio-common/tst-freopen3-main.c
new file mode 100644
index 0000000000000000..5107e1f98e189e4b
--- /dev/null
+++ b/stdio-common/tst-freopen3-main.c
@@ -0,0 +1,90 @@
+/* Test freopen failure.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/file_contents.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+
+#define START_TEST(DESC) \
+ do \
+ { \
+ fds = support_descriptors_list (); \
+ verbose_printf (DESC); \
+ } \
+ while (0)
+
+#define END_TEST \
+ do \
+ { \
+ support_descriptors_check (fds); \
+ support_descriptors_free (fds); \
+ } \
+ while (0)
+
+int
+do_test (void)
+{
+ struct support_descriptors *fds;
+ char *temp_dir = support_create_temp_directory ("tst-freopen3");
+ char *file1 = xasprintf ("%s/file1", temp_dir);
+ support_write_file_string (file1, "file1");
+ add_temp_file (file1);
+ char *file2 = xasprintf ("%s/file2", temp_dir);
+ support_write_file_string (file2, "file2");
+ add_temp_file (file2);
+ char *file_nodir = xasprintf ("%s/nodir/file", temp_dir);
+ FILE *fp;
+ int ret;
+ int fd;
+
+ START_TEST ("Testing w -> wx (file exists)\n");
+ fp = xfopen (file1, "w");
+ fp = FREOPEN (file2, "wx", fp);
+ TEST_VERIFY (fp == NULL);
+ END_TEST;
+
+ /* Test old file is closed even when opening the new file fails. */
+
+ START_TEST ("testing r -> r (opening new file fails)\n");
+ fp = xfopen (file1, "r");
+ fd = fileno (fp);
+ fp = FREOPEN (file_nodir, "r", fp);
+ TEST_VERIFY (fp == NULL);
+ errno = 0;
+ ret = fcntl (fd, F_GETFL);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EBADF);
+ END_TEST;
+
+ free (temp_dir);
+ free (file1);
+ free (file2);
+ free (file_nodir);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-freopen3.c b/stdio-common/tst-freopen3.c
new file mode 100644
index 0000000000000000..5041b6b2332c8af1
--- /dev/null
+++ b/stdio-common/tst-freopen3.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen
+#include <tst-freopen3-main.c>
diff --git a/stdio-common/tst-freopen64-2.c b/stdio-common/tst-freopen64-2.c
new file mode 100644
index 0000000000000000..88fdc64d8c6548f5
--- /dev/null
+++ b/stdio-common/tst-freopen64-2.c
@@ -0,0 +1,3 @@
+#define FREOPEN freopen64
+#define OTHER_FREOPEN freopen
+#include <tst-freopen2-main.c>
diff --git a/stdio-common/tst-freopen64-3.c b/stdio-common/tst-freopen64-3.c
new file mode 100644
index 0000000000000000..b91b6d2c033a1a79
--- /dev/null
+++ b/stdio-common/tst-freopen64-3.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen64
+#include <tst-freopen3-main.c>

View File

@ -0,0 +1,69 @@
commit f512634ddef242ef0ff025ddeba64ce51035040f
Author: Joseph Myers <josmyers@redhat.com>
Date: Thu Sep 5 11:15:29 2024 +0000
Clear flags2 flags set from mode in freopen (bug 32134)
As reported in bug 32134, freopen does not clear the flags set in
fp->_flags2 by the "e", "m" or "c" mode characters. Clear these so
that they can be set or not as appropriate from the mode string passed
to freopen. The relevant test for "e" in tst-freopen2-main.c is
enabled accordingly; "c" is expected to be covered in a separately
written test (and while tst-freopen2-main.c does include transitions
to and from "m", that's not really a semantic flag intended to result
in behaving in an observably different way).
Tested for x86_64.
diff --git a/libio/freopen.c b/libio/freopen.c
index c947a5aecfde3c80..bed034d89441f200 100644
--- a/libio/freopen.c
+++ b/libio/freopen.c
@@ -63,6 +63,9 @@ freopen (const char *filename, const char *mode, FILE *fp)
up here. */
_IO_old_file_close_it (fp);
_IO_JUMPS_FUNC_UPDATE (fp, &_IO_old_file_jumps);
+ fp->_flags2 &= ~(_IO_FLAGS2_MMAP
+ | _IO_FLAGS2_NOTCANCEL
+ | _IO_FLAGS2_CLOEXEC);
result = _IO_old_file_fopen (fp, gfilename, mode);
}
else
@@ -72,6 +75,9 @@ freopen (const char *filename, const char *mode, FILE *fp)
_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+ fp->_flags2 &= ~(_IO_FLAGS2_MMAP
+ | _IO_FLAGS2_NOTCANCEL
+ | _IO_FLAGS2_CLOEXEC);
result = _IO_file_fopen (fp, gfilename, mode, 1);
if (result != NULL)
result = __fopen_maybe_mmap (result);
diff --git a/libio/freopen64.c b/libio/freopen64.c
index fb02c201bd83c401..9a314c65c1d8a5a4 100644
--- a/libio/freopen64.c
+++ b/libio/freopen64.c
@@ -56,6 +56,9 @@ freopen64 (const char *filename, const char *mode, FILE *fp)
_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+ fp->_flags2 &= ~(_IO_FLAGS2_MMAP
+ | _IO_FLAGS2_NOTCANCEL
+ | _IO_FLAGS2_CLOEXEC);
result = _IO_file_fopen (fp, gfilename, mode, 0);
fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
if (result != NULL)
diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c
index 22b21afebf709563..5dad41c76b02e6de 100644
--- a/stdio-common/tst-freopen2-main.c
+++ b/stdio-common/tst-freopen2-main.c
@@ -308,9 +308,7 @@ do_test (void)
TEST_VERIFY_EXIT (fp != NULL);
ret = fcntl (fileno (fp), F_GETFD);
TEST_VERIFY (ret != -1);
-#if 0 /* Fails to clear FD_CLOEXEC (bug 32134). */
TEST_COMPARE (ret & FD_CLOEXEC, 0);
-#endif
TEST_COMPARE_FILE_STRING (fp, "plustomore");
xfclose (fp);
END_TEST;

View File

@ -0,0 +1,119 @@
commit 9c0d6f7a1046aba111e25e34ec07242853e859dc
Author: Joseph Myers <josmyers@redhat.com>
Date: Thu Sep 5 11:16:59 2024 +0000
Fix memory leak on freopen error return (bug 32140)
As reported in bug 32140, freopen leaks the FILE object when it
returns NULL: there is no valid use of the FILE * pointer (including
passing to freopen again or to fclose) after such an error return, so
the underlying object should be freed. Add code to free it.
Note 1: while I think it's clear from the relevant standards that the
object should be freed and the FILE * can't be used after the call in
this case (the stream is closed, which ends the lifetime of the FILE),
it's entirely possible that some existing code does in fact try to use
the existing FILE * in some way and could be broken by this change.
(Though the most common case for freopen may be stdin / stdout /
stderr, which _IO_deallocate_file explicitly checks for and does not
deallocate.)
Note 2: the deallocation is only done in the _IO_IS_FILEBUF case.
Other kinds of streams bypass all the freopen logic handling closing
the file, meaning a call to _IO_deallocate_file would neither be safe
(the FILE might still be linked into the list of all open FILEs) nor
sufficient (other internal memory allocations associated with the file
would not have been freed). I think the validity of freopen for any
other kind of stream will need clarifying with the Austin Group, but
if it is valid in any such case (where "valid" means "not undefined
behavior so required to close the stream" rather than "required to
successfully associate the stream with the new file in cases where
fopen would work"), more significant changes would be needed to ensure
the stream gets fully closed.
Tested for x86_64.
diff --git a/libio/freopen.c b/libio/freopen.c
index bed034d89441f200..03f8961a61b12e80 100644
--- a/libio/freopen.c
+++ b/libio/freopen.c
@@ -114,5 +114,7 @@ freopen (const char *filename, const char *mode, FILE *fp)
end:
_IO_release_lock (fp);
+ if (result == NULL && (fp->_flags & _IO_IS_FILEBUF) != 0)
+ _IO_deallocate_file (fp);
return result;
}
diff --git a/libio/freopen64.c b/libio/freopen64.c
index 9a314c65c1d8a5a4..abcbd80a5bd92e69 100644
--- a/libio/freopen64.c
+++ b/libio/freopen64.c
@@ -94,5 +94,7 @@ freopen64 (const char *filename, const char *mode, FILE *fp)
end:
_IO_release_lock (fp);
+ if (result == NULL && (fp->_flags & _IO_IS_FILEBUF) != 0)
+ _IO_deallocate_file (fp);
return result;
}
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 5eddc4bfbf4e7fb9..bd3c785537ba0330 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -251,7 +251,9 @@ ifeq (yes,$(build-shared))
ifneq ($(PERL),no)
tests-special += \
$(objpfx)tst-freopen2-mem.out \
+ $(objpfx)tst-freopen3-mem.out \
$(objpfx)tst-freopen64-2-mem.out \
+ $(objpfx)tst-freopen64-3-mem.out \
$(objpfx)tst-getline-enomem-mem.out \
$(objpfx)tst-getline-mem.out \
$(objpfx)tst-printf-bz18872-mem.out \
@@ -264,8 +266,12 @@ tests-special += \
generated += \
tst-freopen2-mem.out \
tst-freopen2.mtrace \
+ tst-freopen3-mem.out \
+ tst-freopen3.mtrace \
tst-freopen64-2-mem.out \
tst-freopen64-2.mtrace \
+ tst-freopen64-3-mem.out \
+ tst-freopen64-3.mtrace \
tst-getline-enomem-mem.out \
tst-getline-enomem.mtrace \
tst-getline-mem.out \
@@ -344,6 +350,12 @@ tst-freopen2-ENV = \
tst-freopen64-2-ENV = \
MALLOC_TRACE=$(objpfx)tst-freopen64-2.mtrace \
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen3-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen3.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen64-3-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen64-3.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-freopen3-main.c b/stdio-common/tst-freopen3-main.c
index 5107e1f98e189e4b..990a6e5921843793 100644
--- a/stdio-common/tst-freopen3-main.c
+++ b/stdio-common/tst-freopen3-main.c
@@ -18,6 +18,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <mcheck.h>
#include <stdio.h>
#include <stdlib.h>
@@ -48,6 +49,7 @@
int
do_test (void)
{
+ mtrace ();
struct support_descriptors *fds;
char *temp_dir = support_create_temp_directory ("tst-freopen3");
char *file1 = xasprintf ("%s/file1", temp_dir);

View File

@ -0,0 +1,86 @@
commit e44ca1c085b3bd41266c882ea1cb0fd436231635
Author: Joseph Myers <josmyers@redhat.com>
Date: Thu Sep 5 20:08:10 2024 +0000
Fix freopen handling of ,ccs= (bug 23675)
As reported in bug 23675 and shown up in the recently added tests of
different cases of freopen (relevant part of the test currently
conditioned under #if 0 to avoid a failure resulting from this bug),
freopen wrongly forces the stream to unoriented even when a mode with
,ccs= is specified, though such a mode is supposed to result in a
wide-oriented stream. Move the clearing of _mode to before the actual
reopening occurs, so that the main fopen implementation can leave a
wide-oriented stream in the ,ccs= case.
Tested for x86_64.
diff --git a/libio/freopen.c b/libio/freopen.c
index 03f8961a61b12e80..d71a4cfffdc35280 100644
--- a/libio/freopen.c
+++ b/libio/freopen.c
@@ -66,6 +66,7 @@ freopen (const char *filename, const char *mode, FILE *fp)
fp->_flags2 &= ~(_IO_FLAGS2_MMAP
| _IO_FLAGS2_NOTCANCEL
| _IO_FLAGS2_CLOEXEC);
+ fp->_mode = 0;
result = _IO_old_file_fopen (fp, gfilename, mode);
}
else
@@ -78,6 +79,7 @@ freopen (const char *filename, const char *mode, FILE *fp)
fp->_flags2 &= ~(_IO_FLAGS2_MMAP
| _IO_FLAGS2_NOTCANCEL
| _IO_FLAGS2_CLOEXEC);
+ fp->_mode = 0;
result = _IO_file_fopen (fp, gfilename, mode, 1);
if (result != NULL)
result = __fopen_maybe_mmap (result);
@@ -85,9 +87,6 @@ freopen (const char *filename, const char *mode, FILE *fp)
fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
if (result != NULL)
{
- /* unbound stream orientation */
- result->_mode = 0;
-
if (fd != -1 && _IO_fileno (result) != fd)
{
/* At this point we have both file descriptors already allocated,
diff --git a/libio/freopen64.c b/libio/freopen64.c
index abcbd80a5bd92e69..64af2c5f7c80a3e9 100644
--- a/libio/freopen64.c
+++ b/libio/freopen64.c
@@ -59,15 +59,13 @@ freopen64 (const char *filename, const char *mode, FILE *fp)
fp->_flags2 &= ~(_IO_FLAGS2_MMAP
| _IO_FLAGS2_NOTCANCEL
| _IO_FLAGS2_CLOEXEC);
+ fp->_mode = 0;
result = _IO_file_fopen (fp, gfilename, mode, 0);
fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
if (result != NULL)
result = __fopen_maybe_mmap (result);
if (result != NULL)
{
- /* unbound stream orientation */
- result->_mode = 0;
-
if (fd != -1 && _IO_fileno (result) != fd)
{
/* At this point we have both file descriptors already allocated,
diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c
index 5dad41c76b02e6de..74c3125fca697fe3 100644
--- a/stdio-common/tst-freopen2-main.c
+++ b/stdio-common/tst-freopen2-main.c
@@ -386,13 +386,8 @@ do_test (void)
fp = xfopen (file2, "w,ccs=iso-8859-1");
ret = fputws (L"\xc0\xc1", fp);
TEST_VERIFY (ret >= 0);
-#if 0 /* Doesn't work (bug 23675). */
fp = FREOPEN (file1, "r,ccs=utf-8", fp);
TEST_VERIFY_EXIT (fp != NULL);
-#else /* Works instead. */
- xfclose (fp);
- fp = xfopen (file1, "r,ccs=utf-8");
-#endif
wc = fgetwc (fp);
TEST_COMPARE (wc, (wint_t) 0xc0);
wc = fgetwc (fp);

View File

@ -0,0 +1,33 @@
commit a2509a8bc955988f01f389a1cf74db3a9da42409
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Sep 6 20:38:23 2024 +0000
Document limitations on streams passed to freopen
As recently discussed, document that freopen does not work with
streams opened with functions such as popen, fmemopen, open_memstream
or fopencookie. I've filed
<https://austingroupbugs.net/view.php?id=1855> to clarify this issue
in POSIX.
Tested with "make info" and "make html".
diff --git a/manual/stdio.texi b/manual/stdio.texi
index 60ab7e7a5d505bb6..a2d9292a787b9fa3 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -330,6 +330,14 @@ this ability, so using @code{freopen} is more portable.
When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} on a
32 bit machine this function is in fact @code{freopen64} since the LFS
interface replaces transparently the old interface.
+
+@Theglibc{} only supports use of @code{freopen} on streams opened with
+@code{fopen} or @code{fopen64} and on the original values of the
+standard streams @code{stdin}, @code{stdout}, and @code{stderr}; such
+a stream may be reopened multiple times with @code{freopen}. If it is
+called on another kind of stream (opened with functions such as
+@code{popen}, @code{fmemopen}, @code{open_memstream}, and
+@code{fopencookie}), @code{freopen} fails and returns a null pointer.
@end deftypefun
@deftypefun {FILE *} freopen64 (const char *@var{filename}, const char *@var{opentype}, FILE *@var{stream})

View File

@ -0,0 +1,495 @@
commit e0f3bf10acf4aab27752847828bfecd3fce41190
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Sep 20 23:26:31 2024 +0000
Add freopen special-case tests: chroot, EFBIG, stdin/stdout/stderr
Add tests of special cases for freopen that were omitted from the more
general tests of different modes and similar issues. The special
cases in the three tests here are logically unconnected, it was simply
convenient to put these tests in one patch.
* Test freopen with a NULL path to the new file, in a chroot. Rather
than asserting that this fails (logically, failure in this case is
an implementation detail; it's not required for freopen to rely on
/proc), verify that either it fails (without memory leaks) or that
it succeeds and behaves as expected on success. There is no check
for file descriptor leaks because the machinery for that also
depends on /proc, so can't be used in a chroot.
* Test that freopen and freopen64 are genuinely different in
configurations with 32-bit off_t by checking for an EFBIG trying to
write past 2GB in a file opened with freopen in such a configuration
but no error with 64-bit off_t or when opening with freopen64.
* Test freopen of stdin, stdout and stderr.
Tested for x86_64 and x86.
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index bd3c785537ba0330..c920f55ed2119900 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -177,8 +177,13 @@ tests := \
tst-fread \
tst-freopen2 \
tst-freopen3 \
+ tst-freopen4 \
+ tst-freopen5 \
+ tst-freopen6 \
tst-freopen64-2 \
tst-freopen64-3 \
+ tst-freopen64-4 \
+ tst-freopen64-6 \
tst-fseek \
tst-fwrite \
tst-getline \
@@ -252,8 +257,13 @@ ifneq ($(PERL),no)
tests-special += \
$(objpfx)tst-freopen2-mem.out \
$(objpfx)tst-freopen3-mem.out \
+ $(objpfx)tst-freopen4-mem.out \
+ $(objpfx)tst-freopen5-mem.out \
+ $(objpfx)tst-freopen6-mem.out \
$(objpfx)tst-freopen64-2-mem.out \
$(objpfx)tst-freopen64-3-mem.out \
+ $(objpfx)tst-freopen64-4-mem.out \
+ $(objpfx)tst-freopen64-6-mem.out \
$(objpfx)tst-getline-enomem-mem.out \
$(objpfx)tst-getline-mem.out \
$(objpfx)tst-printf-bz18872-mem.out \
@@ -268,10 +278,20 @@ generated += \
tst-freopen2.mtrace \
tst-freopen3-mem.out \
tst-freopen3.mtrace \
+ tst-freopen4-mem.out \
+ tst-freopen4.mtrace \
+ tst-freopen5-mem.out \
+ tst-freopen5.mtrace \
+ tst-freopen6-mem.out \
+ tst-freopen6.mtrace \
tst-freopen64-2-mem.out \
tst-freopen64-2.mtrace \
tst-freopen64-3-mem.out \
tst-freopen64-3.mtrace \
+ tst-freopen64-4-mem.out \
+ tst-freopen64-4.mtrace \
+ tst-freopen64-6-mem.out \
+ tst-freopen64-6.mtrace \
tst-getline-enomem-mem.out \
tst-getline-enomem.mtrace \
tst-getline-mem.out \
@@ -356,6 +376,21 @@ tst-freopen3-ENV = \
tst-freopen64-3-ENV = \
MALLOC_TRACE=$(objpfx)tst-freopen64-3.mtrace \
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen4-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen4.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen64-4-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen64-4.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen5-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen5.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen6-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen6.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-freopen64-6-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-freopen64-6.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-freopen4-main.c b/stdio-common/tst-freopen4-main.c
new file mode 100644
index 0000000000000000..e169442cf4df2e9d
--- /dev/null
+++ b/stdio-common/tst-freopen4-main.c
@@ -0,0 +1,100 @@
+/* Test freopen in chroot.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/check.h>
+#include <support/file_contents.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+int
+do_test (void)
+{
+ mtrace ();
+ char *temp_dir = support_create_temp_directory ("tst-freopen4");
+ FILE *fp;
+ int ret;
+
+ /* These chroot tests verify that either reopening a renamed or
+ deleted file works even in the absence of /proc, or that it fails
+ (without memory leaks); thus, for example, such reopening does
+ not crash in the absence of /proc. */
+
+ support_become_root ();
+ if (!support_can_chroot ())
+ return EXIT_UNSUPPORTED;
+ xchroot (temp_dir);
+
+ /* Test freopen with NULL, renamed file. This verifies that
+ reopening succeeds (and resets the file position indicator to
+ start of file) even when the original path could no longer be
+ opened, or fails without a memory leak. (It is not possible to
+ use <support/descriptors.h> to test for file descriptor leaks
+ here, because that also depends on /proc.) */
+
+ verbose_printf ("testing freopen with NULL, renamed file\n");
+ fp = xfopen ("/file1", "w+");
+ ret = fputs ("file has been renamed", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = rename ("/file1", "/file1a");
+ TEST_COMPARE (ret, 0);
+ fp = FREOPEN (NULL, "r+", fp);
+ if (fp != NULL)
+ {
+ puts ("freopen of renamed file succeeded");
+ TEST_COMPARE_FILE_STRING (fp, "file has been renamed");
+ xfclose (fp);
+ }
+ else
+ puts ("freopen of renamed file failed (OK)");
+ ret = rename ("/file1a", "/file1");
+ TEST_COMPARE (ret, 0);
+
+ /* Test freopen with NULL, deleted file. This verifies that
+ reopening succeeds (and resets the file position indicator to
+ start of file) even when the original path could no longer be
+ opened, or fails without a memory leak. */
+
+ verbose_printf ("testing freopen with NULL, deleted file\n");
+ fp = xfopen ("/file1", "r+");
+ ret = fputs ("file has now been deleted", fp);
+ TEST_VERIFY (ret >= 0);
+ ret = remove ("/file1");
+ TEST_COMPARE (ret, 0);
+ fp = FREOPEN (NULL, "r+", fp);
+ if (fp != NULL)
+ {
+ puts ("freopen of deleted file succeeded");
+ TEST_COMPARE_FILE_STRING (fp, "file has now been deleted");
+ xfclose (fp);
+ }
+ else
+ puts ("freopen of deleted file failed (OK)");
+
+ free (temp_dir);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-freopen4.c b/stdio-common/tst-freopen4.c
new file mode 100644
index 0000000000000000..f39ec0d21730879f
--- /dev/null
+++ b/stdio-common/tst-freopen4.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen
+#include <tst-freopen4-main.c>
diff --git a/stdio-common/tst-freopen5.c b/stdio-common/tst-freopen5.c
new file mode 100644
index 0000000000000000..f32626bccfe5c10a
--- /dev/null
+++ b/stdio-common/tst-freopen5.c
@@ -0,0 +1,144 @@
+/* Test freopen and freopen64 with large offsets.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+
+#define START_TEST(DESC) \
+ do \
+ { \
+ fds = support_descriptors_list (); \
+ verbose_printf (DESC); \
+ } \
+ while (0)
+
+#define END_TEST \
+ do \
+ { \
+ support_descriptors_check (fds); \
+ support_descriptors_free (fds); \
+ } \
+ while (0)
+
+int
+do_test (void)
+{
+ mtrace ();
+ struct support_descriptors *fds;
+ FILE *fp;
+ int ret;
+
+ char *temp_dir = support_create_temp_directory ("tst-freopen5");
+ /* This file is removed at the end of each test rather than left
+ around between tests to avoid problems with subsequent tests
+ reopening it as a large (2GB + 1 byte) file. */
+ char *file1 = xasprintf ("%s/file1", temp_dir);
+
+ /* fopen with freopen64: large offsets OK. */
+ START_TEST ("testing fopen with freopen64\n");
+ fp = fopen ("/dev/null", "r");
+ TEST_VERIFY_EXIT (fp != NULL);
+ fp = freopen64 (file1, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ setbuf (fp, NULL);
+ ret = fseeko64 (fp, 1LL << 32, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ ret = fputc ('x', fp);
+ TEST_COMPARE (ret, 'x');
+ xfclose (fp);
+ ret = remove (file1);
+ TEST_COMPARE (ret, 0);
+ END_TEST;
+
+ /* fopen64 with freopen64: large offsets OK. */
+ START_TEST ("testing fopen64 with freopen64\n");
+ fp = fopen64 ("/dev/null", "r");
+ TEST_VERIFY_EXIT (fp != NULL);
+ fp = freopen64 (file1, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ setbuf (fp, NULL);
+ ret = fseeko64 (fp, 1LL << 32, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ ret = fputc ('x', fp);
+ TEST_COMPARE (ret, 'x');
+ xfclose (fp);
+ ret = remove (file1);
+ TEST_COMPARE (ret, 0);
+ END_TEST;
+
+ /* fopen with freopen: large offsets not OK on 32-bit systems. */
+ START_TEST ("testing fopen with freopen\n");
+ fp = fopen ("/dev/null", "r");
+ TEST_VERIFY_EXIT (fp != NULL);
+ fp = freopen (file1, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ setbuf (fp, NULL);
+ ret = fseeko64 (fp, 1LL << 32, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ errno = 0;
+ ret = fputc ('x', fp);
+ if (sizeof (off_t) == 4)
+ {
+ TEST_COMPARE (ret, EOF);
+ TEST_COMPARE (errno, EFBIG);
+ }
+ else
+ TEST_COMPARE (ret, 'x');
+ fclose (fp);
+ ret = remove (file1);
+ TEST_COMPARE (ret, 0);
+ END_TEST;
+
+ /* fopen64 with freopen: large offsets not OK on 32-bit systems. */
+ START_TEST ("testing fopen64 with freopen\n");
+ fp = fopen64 ("/dev/null", "r");
+ TEST_VERIFY_EXIT (fp != NULL);
+ fp = freopen (file1, "w", fp);
+ TEST_VERIFY_EXIT (fp != NULL);
+ setbuf (fp, NULL);
+ ret = fseeko64 (fp, 1LL << 32, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ errno = 0;
+ ret = fputc ('x', fp);
+ if (sizeof (off_t) == 4)
+ {
+ TEST_COMPARE (ret, EOF);
+ TEST_COMPARE (errno, EFBIG);
+ }
+ else
+ TEST_COMPARE (ret, 'x');
+ fclose (fp);
+ ret = remove (file1);
+ TEST_COMPARE (ret, 0);
+ END_TEST;
+
+ free (temp_dir);
+ free (file1);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-freopen6-main.c b/stdio-common/tst-freopen6-main.c
new file mode 100644
index 0000000000000000..f493f42fd7486b72
--- /dev/null
+++ b/stdio-common/tst-freopen6-main.c
@@ -0,0 +1,98 @@
+/* Test freopen of stdin / stdout / stderr.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/file_contents.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+
+int
+do_test (void)
+{
+ mtrace ();
+ char *temp_dir = support_create_temp_directory ("tst-freopen6");
+ char *file1 = xasprintf ("%s/file1", temp_dir);
+ support_write_file_string (file1, "file1");
+ add_temp_file (file1);
+ FILE *fp;
+ int ret;
+
+ verbose_printf ("Testing reopening stdin\n");
+ fp = FREOPEN (file1, "r", stdin);
+ TEST_VERIFY_EXIT (fp == stdin);
+ ret = getchar ();
+ TEST_COMPARE (ret, 'f');
+ ret = getchar ();
+ TEST_COMPARE (ret, 'i');
+ ret = getchar ();
+ TEST_COMPARE (ret, 'l');
+ ret = getchar ();
+ TEST_COMPARE (ret, 'e');
+ ret = getchar ();
+ TEST_COMPARE (ret, '1');
+ ret = getchar ();
+ TEST_COMPARE (ret, EOF);
+ xfclose (fp);
+
+ verbose_printf ("Testing reopening stderr\n");
+ fp = FREOPEN (file1, "w+", stderr);
+ TEST_VERIFY_EXIT (fp == stderr);
+ errno = EINVAL;
+ perror ("test");
+ ret = fseek (fp, 0, SEEK_SET);
+ TEST_COMPARE (ret, 0);
+ TEST_COMPARE_FILE_STRING (fp, "test: Invalid argument\n");
+ xfclose (fp);
+
+ verbose_printf ("Testing reopening stdout\n");
+ /* Defer checks until the old stdout has been restored to make it
+ more likely any errors are written to the old stdout (rather than
+ the temporary file used for the redirected stdout). */
+ int old_stdout = dup (STDOUT_FILENO);
+ TEST_VERIFY_EXIT (old_stdout != -1);
+ int ret_fseek = 0;
+ int ret_compare = 0;
+ fp = FREOPEN (file1, "w+", stdout);
+ int fp_eq_stdout = fp == stdout;
+ if (fp != NULL)
+ {
+ printf ("reopened\n");
+ ret_fseek = fseek (fp, 0, SEEK_SET);
+ ret_compare = support_compare_file_string (fp, "reopened\n");
+ }
+ xfclose (fp);
+ stdout = fdopen (old_stdout, "w");
+ TEST_VERIFY (fp_eq_stdout);
+ TEST_COMPARE (ret_fseek, 0);
+ TEST_COMPARE (ret_compare, 0);
+ xfclose (stdout);
+
+ free (temp_dir);
+ free (file1);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-freopen6.c b/stdio-common/tst-freopen6.c
new file mode 100644
index 0000000000000000..8fd6957b54fa9bc2
--- /dev/null
+++ b/stdio-common/tst-freopen6.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen
+#include <tst-freopen6-main.c>
diff --git a/stdio-common/tst-freopen64-4.c b/stdio-common/tst-freopen64-4.c
new file mode 100644
index 0000000000000000..1411be2bfa0105c1
--- /dev/null
+++ b/stdio-common/tst-freopen64-4.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen64
+#include <tst-freopen4-main.c>
diff --git a/stdio-common/tst-freopen64-6.c b/stdio-common/tst-freopen64-6.c
new file mode 100644
index 0000000000000000..3ec509a36c2471f6
--- /dev/null
+++ b/stdio-common/tst-freopen64-6.c
@@ -0,0 +1,2 @@
+#define FREOPEN freopen64
+#include <tst-freopen6-main.c>

View File

@ -0,0 +1,34 @@
From 53fcdf5f743aa9b02972eec658e66f96d6a63386 Mon Sep 17 00:00:00 2001
From: Alejandro Colomar <alx@kernel.org>
Date: Sat, 16 Nov 2024 16:51:31 +0100
Subject: Silence most -Wzero-as-null-pointer-constant diagnostics
Replace 0 by NULL and {0} by {}.
Omit a few cases that aren't so trivial to fix.
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117059>
Link: <https://software.codidact.com/posts/292718/292759#answer-292759>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Conflicts
All except libioP.h
Removed - unneeded, wouldn't apply
diff --git a/libio/libioP.h b/libio/libioP.h
index a83a411fdf..34bf91fcd8 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -915,9 +915,10 @@ extern int _IO_vscanf (const char *, va_list) __THROW;
# else
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (FILE *) CHAIN, FD, \
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
+ NULL, NULL, (FILE *) CHAIN, FD, \
0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock, _IO_pos_BAD,\
- NULL, WDP, 0 }
+ NULL, WDP, NULL }
# endif
#else
# ifdef _IO_USE_OLD_IO_FILE

View File

@ -0,0 +1,52 @@
From bd0ea9ff7e8d5f7d54112dfa96d541c3c60e36ae Mon Sep 17 00:00:00 2001
From: Alejandro Colomar <alx@kernel.org>
Date: Tue, 17 Dec 2024 00:22:19 +0100
Subject: libio: Use NULL instead of 0 as a null pointer constant
This was missed in a recent global change.
Fixes: 53fcdf5f743a (2024-11-25, "Silence most -Wzero-as-null-pointer-constant diagnostics")
Reported-by: "Maciej W. Rozycki" <macro@redhat.com>
Cc: Siddhesh Poyarekar <siddhesh@sourceware.org>
Cc: Bruno Haible <bruno@clisp.org>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Xi Ruoyao <xry111@xry111.site>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Joseph Myers <josmyers@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Maciej W. Rozycki <macro@redhat.com>
diff --git a/libio/libioP.h b/libio/libioP.h
index 34bf91fcd8..70e2bdfc9d 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -910,7 +910,8 @@ extern int _IO_vscanf (const char *, va_list) __THROW;
# ifdef _IO_USE_OLD_IO_FILE
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (FILE *) CHAIN, FD, \
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
+ NULL, NULL, (FILE *) CHAIN, FD, \
0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock }
# else
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
@@ -924,14 +925,16 @@ extern int _IO_vscanf (const char *, va_list) __THROW;
# ifdef _IO_USE_OLD_IO_FILE
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (FILE *) CHAIN, FD, \
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
+ NULL, NULL, (FILE *) CHAIN, FD, \
0, _IO_pos_BAD }
# else
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (FILE *) CHAIN, FD, \
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
+ NULL, NULL, (FILE *) CHAIN, FD, \
0, _IO_pos_BAD, 0, 0, { 0 }, 0, _IO_pos_BAD, \
- NULL, WDP, 0 }
+ NULL, WDP, NULL }
# endif
#endif

View File

@ -0,0 +1,21 @@
From cfdd9e7aa45cdc575df237e2d2eee3219a06829b Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue, 17 Dec 2024 17:36:36 -0500
Subject: libio: Fix last NULL-as-0 issue in libioP.h
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Maciej W. Rozycki <macro@redhat.com>
diff --git a/libio/libioP.h b/libio/libioP.h
index 70e2bdfc9d..ad45579e13 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -933,7 +933,7 @@ extern int _IO_vscanf (const char *, va_list) __THROW;
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
NULL, NULL, (FILE *) CHAIN, FD, \
- 0, _IO_pos_BAD, 0, 0, { 0 }, 0, _IO_pos_BAD, \
+ 0, _IO_pos_BAD, 0, 0, { 0 }, NULL, _IO_pos_BAD, \
NULL, WDP, NULL }
# endif
#endif

View File

@ -0,0 +1,405 @@
From ae5062201d7e9d18fe88bff4bc71088374c394fb Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu, 7 Nov 2024 11:16:04 -0500
Subject: ungetc: Guarantee single char pushback
The C standard requires that ungetc guarantees at least one pushback,
but the malloc call to allocate the pushback buffer could fail, thus
violating that requirement. Fix this by adding a single byte pushback
buffer in the FILE struct that the pushback can fall back to if malloc
fails.
The side-effect is that if the initial malloc fails and the 1-byte
fallback buffer is used, future resizing (if it succeeds) will be
2-bytes, 4-bytes and so on, which is suboptimal but it's after a malloc
failure, so maybe even desirable.
A future optimization here could be to have the pushback code use the
single byte buffer first and only fall back to malloc for subsequent
calls.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Maciej W. Rozycki <macro@redhat.com>
Conflicts:
libio/bits/types/struct_FILE.h
libio/fileops.c
libio/genops.c
libio/libioP.h
libio/oldfileops.c
libio/wfileops.c
stdio-common/Makefile
Copyright year conflicts in all files
Rebase for altered context and line numbers
diff -rupN a/libio/bits/types/struct_FILE.h b/libio/bits/types/struct_FILE.h
--- a/libio/bits/types/struct_FILE.h 2021-08-01 21:33:43.000000000 -0400
+++ b/libio/bits/types/struct_FILE.h 2024-12-19 00:34:04.289351714 -0500
@@ -1,4 +1,5 @@
/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -70,7 +71,9 @@ struct _IO_FILE
struct _IO_FILE *_chain;
int _fileno;
- int _flags2;
+ int _flags2:24;
+ /* Fallback buffer to use when malloc fails to allocate one. */
+ char _short_backupbuf[1];
__off_t _old_offset; /* This used to be _offset but it's too small. */
/* 1+column number of pbase(); 0 is unknown. */
diff -rupN a/libio/fileops.c b/libio/fileops.c
--- a/libio/fileops.c 2021-08-01 21:33:43.000000000 -0400
+++ b/libio/fileops.c 2024-12-19 00:34:04.294351763 -0500
@@ -1,4 +1,5 @@
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
Written by Per Bothner <bothner@cygnus.com>.
@@ -480,7 +481,7 @@ _IO_new_file_underflow (FILE *fp)
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
@@ -932,7 +933,7 @@ _IO_new_file_seekoff (FILE *fp, off64_t
/* It could be that we already have a pushback buffer. */
if (fp->_IO_read_base != NULL)
{
- free (fp->_IO_read_base);
+ _IO_free_backup_buf (fp, fp->_IO_read_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
@@ -1282,7 +1283,7 @@ _IO_file_xsgetn (FILE *fp, void *data, s
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
diff -rupN a/libio/genops.c b/libio/genops.c
--- a/libio/genops.c 2024-12-18 23:17:35.150703172 -0500
+++ b/libio/genops.c 2024-12-19 00:34:04.300351821 -0500
@@ -1,4 +1,5 @@
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -187,7 +188,7 @@ _IO_free_backup_area (FILE *fp)
{
if (_IO_in_backup (fp))
_IO_switch_to_main_get_area (fp); /* Just in case. */
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_IO_save_base = NULL;
fp->_IO_save_end = NULL;
fp->_IO_backup_base = NULL;
@@ -235,7 +236,7 @@ save_for_backup (FILE *fp, char *end_p)
memcpy (new_buffer + avail,
fp->_IO_read_base + least_mark,
needed_size);
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_IO_save_base = new_buffer;
fp->_IO_save_end = new_buffer + avail + needed_size;
}
@@ -611,7 +612,7 @@ _IO_default_finish (FILE *fp, int dummy)
if (fp->_IO_save_base)
{
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_IO_save_base = NULL;
}
@@ -996,11 +997,14 @@ _IO_default_pbackfail (FILE *fp, int c)
else if (!_IO_have_backup (fp))
{
/* No backup buffer: allocate one. */
- /* Use nshort buffer, if unused? (probably not) FIXME */
int backup_size = 128;
char *bbuf = (char *) malloc (backup_size);
if (bbuf == NULL)
- return EOF;
+ {
+ /* Guarantee a 1-char pushback. */
+ bbuf = fp->_short_backupbuf;
+ backup_size = 1;
+ }
fp->_IO_save_base = bbuf;
fp->_IO_save_end = fp->_IO_save_base + backup_size;
fp->_IO_backup_base = fp->_IO_save_end;
@@ -1020,7 +1024,7 @@ _IO_default_pbackfail (FILE *fp, int c)
return EOF;
memcpy (new_buf + (new_size - old_size), fp->_IO_read_base,
old_size);
- free (fp->_IO_read_base);
+ _IO_free_backup_buf (fp, fp->_IO_read_base);
_IO_setg (fp, new_buf, new_buf + (new_size - old_size),
new_buf + new_size);
fp->_IO_backup_base = fp->_IO_read_ptr;
diff -rupN a/libio/libioP.h b/libio/libioP.h
--- a/libio/libioP.h 2024-12-18 23:17:36.823719449 -0500
+++ b/libio/libioP.h 2024-12-19 00:34:04.305351870 -0500
@@ -1,4 +1,5 @@
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -809,30 +810,30 @@ extern int _IO_vscanf (const char *, va_
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, (FILE *) CHAIN, FD, \
- 0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock }
+ NULL, NULL, (FILE *) CHAIN, FD, 0, { 0 }, \
+ _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock }
# else
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, (FILE *) CHAIN, FD, \
- 0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock, _IO_pos_BAD,\
- NULL, WDP, NULL }
+ NULL, NULL, (FILE *) CHAIN, FD, 0, { 0 }, \
+ _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock, \
+ _IO_pos_BAD, NULL, WDP, NULL }
# endif
#else
# ifdef _IO_USE_OLD_IO_FILE
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, (FILE *) CHAIN, FD, \
- 0, _IO_pos_BAD }
+ NULL, NULL, (FILE *) CHAIN, FD, 0, { 0 }, \
+ _IO_pos_BAD }
# else
# define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \
{ _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, (FILE *) CHAIN, FD, \
- 0, _IO_pos_BAD, 0, 0, { 0 }, NULL, _IO_pos_BAD, \
- NULL, WDP, NULL }
+ NULL, NULL, (FILE *) CHAIN, FD, 0, { 0 }, \
+ _IO_pos_BAD, 0, 0, { 0 }, NULL, \
+ _IO_pos_BAD, NULL, WDP, NULL }
# endif
#endif
@@ -951,6 +952,15 @@ IO_validate_vtable (const struct _IO_jum
return vtable;
}
+/* In case of an allocation failure, we resort to using the fixed buffer
+ _SHORT_BACKUPBUF. Free PTR unless it points to that buffer. */
+static __always_inline void
+_IO_free_backup_buf (FILE *fp, char *ptr)
+{
+ if (ptr != fp->_short_backupbuf)
+ free (ptr);
+}
+
/* Character set conversion. */
enum __codecvt_result
diff -rupN a/libio/oldfileops.c b/libio/oldfileops.c
--- a/libio/oldfileops.c 2021-08-01 21:33:43.000000000 -0400
+++ b/libio/oldfileops.c 2024-12-19 00:34:04.311351928 -0500
@@ -1,4 +1,5 @@
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
Written by Per Bothner <bothner@cygnus.com>.
@@ -310,7 +311,7 @@ _IO_old_file_underflow (FILE *fp)
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
@@ -463,7 +464,7 @@ _IO_old_file_seekoff (FILE *fp, off64_t
/* It could be that we already have a pushback buffer. */
if (fp->_IO_read_base != NULL)
{
- free (fp->_IO_read_base);
+ _IO_free_backup_buf (fp, fp->_IO_read_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
diff -rupN a/libio/wfileops.c b/libio/wfileops.c
--- a/libio/wfileops.c 2024-12-18 23:17:34.277694679 -0500
+++ b/libio/wfileops.c 2024-12-19 00:34:04.316351977 -0500
@@ -1,4 +1,5 @@
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@cygnus.com>.
Based on the single byte version by Per Bothner <bothner@cygnus.com>.
@@ -177,7 +178,7 @@ _IO_wfile_underflow (FILE *fp)
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
- free (fp->_IO_save_base);
+ _IO_free_backup_buf (fp, fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
diff -rupN a/stdio-common/Makefile b/stdio-common/Makefile
--- a/stdio-common/Makefile 2024-12-18 23:17:36.527716569 -0500
+++ b/stdio-common/Makefile 2024-12-19 00:34:04.320352016 -0500
@@ -1,4 +1,5 @@
# Copyright (C) 1991-2021 Free Software Foundation, Inc.
+# Copyright The GNU Toolchain Authors.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -242,6 +243,7 @@ tests := \
tst-tmpnam \
tst-ungetc \
tst-ungetc-leak \
+ tst-ungetc-nomem \
tst-unlockedio \
tst-vfprintf-mbs-prec \
tst-vfprintf-user-type \
diff -rupN a/stdio-common/tst-ungetc-nomem.c b/stdio-common/tst-ungetc-nomem.c
--- a/stdio-common/tst-ungetc-nomem.c 1969-12-31 19:00:00.000000000 -0500
+++ b/stdio-common/tst-ungetc-nomem.c 2024-12-19 00:34:04.324352055 -0500
@@ -0,0 +1,121 @@
+/* Test ungetc behavior with malloc failures.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+
+static volatile bool fail = false;
+
+/* Induce a malloc failure whenever FAIL is set; we use the __LIBC_MALLOC entry
+ point to avoid the other alternative, which is RTLD_NEXT. */
+void *
+malloc (size_t sz)
+{
+ if (fail)
+ return NULL;
+
+ static void *(*real_malloc) (size_t);
+
+ if (real_malloc == NULL)
+ real_malloc = dlsym (RTLD_NEXT, "malloc");
+
+ return real_malloc (sz);
+}
+
+static int
+do_test (void)
+{
+ char *filename = NULL;
+ struct stat props = {};
+ size_t bufsz = 0;
+
+ create_temp_file ("tst-ungetc-nomem.", &filename);
+ if (stat (filename, &props) != 0)
+ FAIL_EXIT1 ("Could not get file status: %m\n");
+
+ FILE *fp = fopen (filename, "w");
+
+ /* The libio buffer sizes are the same as block size. This is to ensure that
+ the test runs at the read underflow boundary as well. */
+ bufsz = props.st_blksize + 2;
+
+ char *buf = xmalloc (bufsz);
+ memset (buf, 'a', bufsz);
+
+ if (fwrite (buf, sizeof (char), bufsz, fp) != bufsz)
+ FAIL_EXIT1 ("fwrite failed: %m\n");
+ xfclose (fp);
+
+ /* Begin test. */
+ fp = xfopen (filename, "r");
+
+ while (!feof (fp))
+ {
+ /* Reset the pushback buffer state. */
+ fseek (fp, 0, SEEK_CUR);
+
+ fail = true;
+ /* 1: First ungetc should always succeed, as the standard requires. */
+ TEST_COMPARE (ungetc ('b', fp), 'b');
+
+ /* 2: This will result in resizing, which should fail. */
+ TEST_COMPARE (ungetc ('c', fp), EOF);
+
+ /* 3: Now allow the resizing, which should immediately fill up the buffer
+ too, since this allocates only double the current buffer, i.e.
+ 2-bytes. */
+ fail = false;
+ TEST_COMPARE (ungetc ('d', fp), 'd');
+
+ /* 4: And fail again because this again forces an alloc, which fails. */
+ fail = true;
+ TEST_COMPARE (ungetc ('e', fp), EOF);
+
+ /* 5: Enable allocations again so that we now get a 4-byte buffer. Now
+ both calls should work. */
+ fail = false;
+ TEST_COMPARE (ungetc ('f', fp), 'f');
+ fail = true;
+ TEST_COMPARE (ungetc ('g', fp), 'g');
+
+ /* Drain out the x's. */
+ TEST_COMPARE (fgetc (fp), 'g');
+ TEST_COMPARE (fgetc (fp), 'f');
+ TEST_COMPARE (fgetc (fp), 'd');
+
+ /* Finally, drain out the first char we had pushed back, followed by one
+ more char from the stream, if present. */
+ TEST_COMPARE (fgetc (fp), 'b');
+ char c = fgetc (fp);
+ if (!feof (fp))
+ TEST_COMPARE (c, 'a');
+ }
+
+ /* Final sanity check before we're done. */
+ TEST_COMPARE (ferror (fp), 0);
+ xfclose (fp);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,26 @@
Downstream-only patch to restore the extern ABI for functions
like fprintf that use the FILE * type. Rebuilds of applications
receive ABI change reports because of this installed header change
(indirect subtype change in libabigail terms), and given that
this part of struct _IO_FILE is strictly internal, there is no
need to expose this change to installed headers.
diff --git a/libio/bits/types/struct_FILE.h b/libio/bits/types/struct_FILE.h
index 0e73f89f813ef3b8..f7f756a701ce0e93 100644
--- a/libio/bits/types/struct_FILE.h
+++ b/libio/bits/types/struct_FILE.h
@@ -71,9 +71,14 @@ struct _IO_FILE
struct _IO_FILE *_chain;
int _fileno;
+#ifdef _LIBC
int _flags2:24;
/* Fallback buffer to use when malloc fails to allocate one. */
char _short_backupbuf[1];
+#else
+ /* Legacy ABI for ABI checking outside of glibc. */
+ int _flags2;
+#endif
__off_t _old_offset; /* This used to be _offset but it's too small. */
/* 1+column number of pbase(); 0 is unknown. */

View File

@ -0,0 +1,49 @@
commit 207d64feb26279e152c50744e3c37e68491aca99
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Aug 14 17:15:46 2024 +0000
Test errno setting on strtod overflow in tst-strtod-round
We have no tests that errno is set to ERANGE on overflow of
strtod-family functions (we do have some tests for underflow, in
tst-strtod-underflow). Add such tests to tst-strtod-round.
Tested for x86_64.
diff --git a/stdlib/tst-strtod-round-skeleton.c b/stdlib/tst-strtod-round-skeleton.c
index f60b9a00e9e8d262..1ff1977112bda7a8 100644
--- a/stdlib/tst-strtod-round-skeleton.c
+++ b/stdlib/tst-strtod-round-skeleton.c
@@ -21,6 +21,7 @@
declared in the headers. */
#define _LIBC_TEST 1
#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <errno.h>
#include <fenv.h>
#include <float.h>
#include <math.h>
@@ -205,7 +206,9 @@ struct test {
#define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
{ \
feclearexcept (FE_ALL_EXCEPT); \
+ errno = 0; \
FTYPE f = STRTO (FSUF) (s, NULL); \
+ int new_errno = errno; \
if (f != expected->FSUF \
|| (copysign ## CSUF) (1.0 ## LSUF, f) \
!= (copysign ## CSUF) (1.0 ## LSUF, expected->FSUF)) \
@@ -254,6 +257,14 @@ struct test {
printf ("ignoring this exception error\n"); \
} \
} \
+ if (overflow->FSUF && new_errno != ERANGE) \
+ { \
+ printf (FNPFXS "to" #FSUF \
+ " (" STRM ") left errno == %d," \
+ " not %d (ERANGE)\n", \
+ s, new_errno, ERANGE); \
+ result = 1; \
+ } \
} \
}

View File

@ -0,0 +1,38 @@
commit 378039ca578c2ea93095a1e710d96f58c68a3997
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Sep 20 23:24:45 2024 +0000
Add tests of more strtod special cases
There is very little test coverage of inputs to strtod-family
functions that don't contain anything that can be parsed as a number
(one test of ".y" in tst-strtod2), and none that I can see of skipping
initial whitespace. Add some tests of these things to tst-strtod2.
Tested for x86_64.
diff --git a/stdlib/tst-strtod2.c b/stdlib/tst-strtod2.c
index c84bd792c1a3f511..d00bc13323c50622 100644
--- a/stdlib/tst-strtod2.c
+++ b/stdlib/tst-strtod2.c
@@ -31,6 +31,20 @@ struct test_strto ## FSUF \
{ "0x1px", 1.0 ## LSUF, 3 }, \
{ "0x1p+x", 1.0 ## LSUF, 3 }, \
{ "0x1p-x", 1.0 ## LSUF, 3 }, \
+ { "", 0.0 ## LSUF, 0 }, \
+ { ".", 0.0 ## LSUF, 0 }, \
+ { "-", 0.0 ## LSUF, 0 }, \
+ { "-.", 0.0 ## LSUF, 0 }, \
+ { ".e", 0.0 ## LSUF, 0 }, \
+ { "-.e", 0.0 ## LSUF, 0 }, \
+ { " \t", 0.0 ## LSUF, 0 }, \
+ { " \t.", 0.0 ## LSUF, 0 }, \
+ { " \t-", 0.0 ## LSUF, 0 }, \
+ { " \t-.", 0.0 ## LSUF, 0 }, \
+ { " \t.e", 0.0 ## LSUF, 0 }, \
+ { " \t-.e", 0.0 ## LSUF, 0 }, \
+ { " \t\f\r\n\v1", 1.0 ## LSUF, 7 }, \
+ { " \t\f\r\n\v-1.5e2", -150.0 ## LSUF, 12 }, \
{ "INFx", INFINITY, 3 }, \
{ "infx", INFINITY, 3 }, \
{ "INFINITx", INFINITY, 3 }, \

View File

@ -0,0 +1,439 @@
commit 94ca2c0894f0e1b62625c369cc598a2b9236622c
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Sep 20 23:25:32 2024 +0000
Make tst-strtod-underflow type-generic
The test tst-strtod-underflow covers various edge cases close to the
underflow threshold for strtod (especially cases where underflow on
architectures with after-rounding tininess detection depends on the
rounding mode). Make it use the type-generic machinery, with
corresponding test inputs for each supported floating-point format, so
that other functions in the strtod family are tested for underflow
edge cases as well.
Tested for x86_64.
diff --git a/stdlib/tst-strtod-underflow.c b/stdlib/tst-strtod-underflow.c
index 294f88de439fb3e7..094a70bbbe53e70b 100644
--- a/stdlib/tst-strtod-underflow.c
+++ b/stdlib/tst-strtod-underflow.c
@@ -17,6 +17,10 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+/* Defining _LIBC_TEST ensures long double math functions are
+ declared in the headers. */
+#define _LIBC_TEST 1
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <errno.h>
#include <fenv.h>
#include <float.h>
@@ -25,6 +29,60 @@
#include <stdlib.h>
#include <tininess.h>
+#include "tst-strtod.h"
+
+/* Logic for selecting between tests for different formats is as in
+ tst-strtod-skeleton.c, but here it is selecting string inputs with
+ different underflow properties, rather than generated test
+ data. */
+
+#define _CONCAT(a, b) a ## b
+#define CONCAT(a, b) _CONCAT (a, b)
+
+#define MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+ const char *s_ ## FSUF;
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+# define CHOOSE_ld(f,d,...) d
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16381
+# define CHOOSE_ld(f,d,ld64i,...) ld64i
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16382
+# define CHOOSE_ld(f,d,ld64i,ld64m,...) ld64m
+#elif LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024
+# define CHOOSE_ld(f,d,ld64i,ld64m,ld106,...) ld106
+#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
+# define CHOOSE_ld(f,d,ld64i,ld64m,ld106,ld113,...) ld113
+#else
+# error "unknown long double format"
+#endif
+
+#define CHOOSE_f(f,...) f
+#define CHOOSE_f32(f,...) f
+#define CHOOSE_d(f,d,...) d
+#define CHOOSE_f64(f,d,...) d
+#define CHOOSE_f32x(f,d,...) d
+#define CHOOSE_f128(f,d,ld64i,ld64m,ld106,ld113,...) ld113
+
+#if __HAVE_FLOAT64X
+# if FLT64X_MANT_DIG == 113 && FLT64X_MAX_EXP == 16384
+# define CHOOSE_f64x(f,d,ld64i,ld64m,ld106,ld113,...) ld113
+# elif (FLT64X_MANT_DIG == 64 \
+ && FLT64X_MAX_EXP == 16384 \
+ && FLT64X_MIN_EXP == -16381)
+# define CHOOSE_f64x(f,d,ld64i,...) ld64i
+# else
+# error "unknown _Float64x format"
+# endif
+#endif
+
+#define _XNTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...) \
+ CHOOSE_ ## FSUF (__VA_ARGS__),
+#define XNTRY(...) \
+ GEN_TEST_STRTOD_FOREACH (_XNTRY, __VA_ARGS__)
+
+#define TEST(f, d, ld64i, ld64m, ld106, ld113, u) \
+ { XNTRY(f, d, ld64i, ld64m, ld106, ld113) u }
+
enum underflow_case
{
/* Result is exact or outside the subnormal range. */
@@ -55,38 +113,194 @@ enum underflow_case
struct test
{
- const char *s;
+ GEN_TEST_STRTOD_FOREACH (MEMBER)
enum underflow_case c;
};
static const struct test tests[] =
{
- { "0x1p-1022", UNDERFLOW_NONE },
- { "-0x1p-1022", UNDERFLOW_NONE },
- { "0x0p-10000000000000000000000000", UNDERFLOW_NONE },
- { "-0x0p-10000000000000000000000000", UNDERFLOW_NONE },
- { "0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS },
- { "-0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS },
- { "0x1.000000000000000000001p-1022", UNDERFLOW_NONE },
- { "-0x1.000000000000000000001p-1022", UNDERFLOW_NONE },
- { "0x1p-1075", UNDERFLOW_ALWAYS },
- { "-0x1p-1075", UNDERFLOW_ALWAYS },
- { "0x1p-1023", UNDERFLOW_NONE },
- { "-0x1p-1023", UNDERFLOW_NONE },
- { "0x1p-1074", UNDERFLOW_NONE },
- { "-0x1p-1074", UNDERFLOW_NONE },
- { "0x1.ffffffffffffep-1023", UNDERFLOW_NONE },
- { "-0x1.ffffffffffffep-1023", UNDERFLOW_NONE },
- { "0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS },
- { "-0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS },
- { "0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_UPWARD },
- { "-0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_DOWNWARD },
- { "0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_UPWARD },
- { "-0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_DOWNWARD },
- { "0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO },
- { "-0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_UPWARD_ZERO },
- { "0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO },
- { "-0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_UPWARD_ZERO },
+ TEST ("0x1p-126",
+ "0x1p-1022",
+ "0x1p-16382",
+ "0x1p-16383",
+ "0x1p-969",
+ "0x1p-16382",
+ UNDERFLOW_NONE),
+ TEST ("-0x1p-126",
+ "-0x1p-1022",
+ "-0x1p-16382",
+ "-0x1p-16383",
+ "-0x1p-969",
+ "-0x1p-16382",
+ UNDERFLOW_NONE),
+ TEST ("0x0p-10000000000000000000000000",
+ "0x0p-10000000000000000000000000",
+ "0x0p-10000000000000000000000000",
+ "0x0p-10000000000000000000000000",
+ "0x0p-10000000000000000000000000",
+ "0x0p-10000000000000000000000000",
+ UNDERFLOW_NONE),
+ TEST ("-0x0p-10000000000000000000000000",
+ "-0x0p-10000000000000000000000000",
+ "-0x0p-10000000000000000000000000",
+ "-0x0p-10000000000000000000000000",
+ "-0x0p-10000000000000000000000000",
+ "-0x0p-10000000000000000000000000",
+ UNDERFLOW_NONE),
+ TEST ("0x1p-10000000000000000000000000",
+ "0x1p-10000000000000000000000000",
+ "0x1p-10000000000000000000000000",
+ "0x1p-10000000000000000000000000",
+ "0x1p-10000000000000000000000000",
+ "0x1p-10000000000000000000000000",
+ UNDERFLOW_ALWAYS),
+ TEST ("-0x1p-10000000000000000000000000",
+ "-0x1p-10000000000000000000000000",
+ "-0x1p-10000000000000000000000000",
+ "-0x1p-10000000000000000000000000",
+ "-0x1p-10000000000000000000000000",
+ "-0x1p-10000000000000000000000000",
+ UNDERFLOW_ALWAYS),
+ TEST ("0x1.000000000000000000001p-126",
+ "0x1.000000000000000000001p-1022",
+ "0x1.000000000000000000001p-16382",
+ "0x1.000000000000000000001p-16383",
+ "0x1.000000000000000000001p-969",
+ "0x1.00000000000000000000000000000000000000001p-16382",
+ UNDERFLOW_NONE),
+ TEST ("-0x1.000000000000000000001p-126",
+ "-0x1.000000000000000000001p-1022",
+ "-0x1.000000000000000000001p-16382",
+ "-0x1.000000000000000000001p-16383",
+ "-0x1.000000000000000000001p-969",
+ "-0x1.00000000000000000000000000000000000000001p-16382",
+ UNDERFLOW_NONE),
+ TEST ("0x1p-150",
+ "0x1p-1075",
+ "0x1p-16446",
+ "0x1p-16447",
+ "0x1p-1075",
+ "0x1p-16495",
+ UNDERFLOW_ALWAYS),
+ TEST ("-0x1p-150",
+ "-0x1p-1075",
+ "-0x1p-16446",
+ "-0x1p-16447",
+ "-0x1p-1075",
+ "-0x1p-16495",
+ UNDERFLOW_ALWAYS),
+ TEST ("0x1p-127",
+ "0x1p-1023",
+ "0x1p-16383",
+ "0x1p-16384",
+ "0x1p-970",
+ "0x1p-16383",
+ UNDERFLOW_NONE),
+ TEST ("-0x1p-127",
+ "-0x1p-1023",
+ "-0x1p-16383",
+ "-0x1p-16384",
+ "-0x1p-970",
+ "-0x1p-16383",
+ UNDERFLOW_NONE),
+ TEST ("0x1p-149",
+ "0x1p-1074",
+ "0x1p-16445",
+ "0x1p-16446",
+ "0x1p-1074",
+ "0x1p-16494",
+ UNDERFLOW_NONE),
+ TEST ("-0x1p-149",
+ "-0x1p-1074",
+ "-0x1p-16445",
+ "-0x1p-16446",
+ "-0x1p-1074",
+ "-0x1p-16494",
+ UNDERFLOW_NONE),
+ TEST ("0x1.fffffcp-127",
+ "0x1.ffffffffffffep-1023",
+ "0x1.fffffffffffffffcp-16383",
+ "0x1.fffffffffffffffcp-16384",
+ "0x1.ffffffffffffffffffffffffffp-970",
+ "0x1.fffffffffffffffffffffffffffep-16383",
+ UNDERFLOW_NONE),
+ TEST ("-0x1.fffffcp-127",
+ "-0x1.ffffffffffffep-1023",
+ "-0x1.fffffffffffffffcp-16383",
+ "-0x1.fffffffffffffffcp-16384",
+ "-0x1.ffffffffffffffffffffffffffp-970",
+ "-0x1.fffffffffffffffffffffffffffep-16383",
+ UNDERFLOW_NONE),
+ TEST ("0x1.fffffep-127",
+ "0x1.fffffffffffffp-1023",
+ "0x1.fffffffffffffffep-16383",
+ "0x1.fffffffffffffffep-16384",
+ "0x1.ffffffffffffffffffffffffff8p-970",
+ "0x1.ffffffffffffffffffffffffffffp-16383",
+ UNDERFLOW_ALWAYS),
+ TEST ("-0x1.fffffep-127",
+ "-0x1.fffffffffffffp-1023",
+ "-0x1.fffffffffffffffep-16383",
+ "-0x1.fffffffffffffffep-16384",
+ "-0x1.ffffffffffffffffffffffffff8p-970",
+ "-0x1.ffffffffffffffffffffffffffffp-16383",
+ UNDERFLOW_ALWAYS),
+ TEST ("0x1.fffffe0001p-127",
+ "0x1.fffffffffffff0001p-1023",
+ "0x1.fffffffffffffffe0001p-16383",
+ "0x1.fffffffffffffffe0001p-16384",
+ "0x1.ffffffffffffffffffffffffff80001p-970",
+ "0x1.ffffffffffffffffffffffffffff0001p-16383",
+ UNDERFLOW_EXCEPT_UPWARD),
+ TEST ("-0x1.fffffe0001p-127",
+ "-0x1.fffffffffffff0001p-1023",
+ "-0x1.fffffffffffffffe0001p-16383",
+ "-0x1.fffffffffffffffe0001p-16384",
+ "-0x1.ffffffffffffffffffffffffff80001p-970",
+ "-0x1.ffffffffffffffffffffffffffff0001p-16383",
+ UNDERFLOW_EXCEPT_DOWNWARD),
+ TEST ("0x1.fffffeffffp-127",
+ "0x1.fffffffffffff7fffp-1023",
+ "0x1.fffffffffffffffeffffp-16383",
+ "0x1.fffffffffffffffeffffp-16384",
+ "0x1.ffffffffffffffffffffffffffbffffp-970",
+ "0x1.ffffffffffffffffffffffffffff7fffp-16383",
+ UNDERFLOW_EXCEPT_UPWARD),
+ TEST ("-0x1.fffffeffffp-127",
+ "-0x1.fffffffffffff7fffp-1023",
+ "-0x1.fffffffffffffffeffffp-16383",
+ "-0x1.fffffffffffffffeffffp-16384",
+ "-0x1.ffffffffffffffffffffffffffbffffp-970",
+ "-0x1.ffffffffffffffffffffffffffff7fffp-16383",
+ UNDERFLOW_EXCEPT_DOWNWARD),
+ TEST ("0x1.ffffffp-127",
+ "0x1.fffffffffffff8p-1023",
+ "0x1.ffffffffffffffffp-16383",
+ "0x1.ffffffffffffffffp-16384",
+ "0x1.ffffffffffffffffffffffffffcp-970",
+ "0x1.ffffffffffffffffffffffffffff8p-16383",
+ UNDERFLOW_ONLY_DOWNWARD_ZERO),
+ TEST ("-0x1.ffffffp-127",
+ "-0x1.fffffffffffff8p-1023",
+ "-0x1.ffffffffffffffffp-16383",
+ "-0x1.ffffffffffffffffp-16384",
+ "-0x1.ffffffffffffffffffffffffffcp-970",
+ "-0x1.ffffffffffffffffffffffffffff8p-16383",
+ UNDERFLOW_ONLY_UPWARD_ZERO),
+ TEST ("0x1.ffffffffffp-127",
+ "0x1.fffffffffffffffffp-1023",
+ "0x1.ffffffffffffffffffffp-16383",
+ "0x1.ffffffffffffffffffffp-16384",
+ "0x1.ffffffffffffffffffffffffffffffp-970",
+ "0x1.ffffffffffffffffffffffffffffffffp-16383",
+ UNDERFLOW_ONLY_DOWNWARD_ZERO),
+ TEST ("-0x1.ffffffffffp-127",
+ "-0x1.fffffffffffffffffp-1023",
+ "-0x1.ffffffffffffffffffffp-16383",
+ "-0x1.ffffffffffffffffffffp-16384",
+ "-0x1.ffffffffffffffffffffffffffffffp-970",
+ "-0x1.ffffffffffffffffffffffffffffffffp-16383",
+ UNDERFLOW_ONLY_UPWARD_ZERO),
};
/* Return whether to expect underflow from a particular testcase, in a
@@ -133,39 +347,62 @@ static bool support_underflow_exception = false;
volatile double d = DBL_MIN;
volatile double dd;
-static int
-test_in_one_mode (const char *s, enum underflow_case c, int rm,
- const char *mode_name)
+static bool
+test_got_fe_underflow (void)
{
- int result = 0;
- feclearexcept (FE_ALL_EXCEPT);
- errno = 0;
- double d = strtod (s, NULL);
- int got_errno = errno;
#ifdef FE_UNDERFLOW
- bool got_fe_underflow = fetestexcept (FE_UNDERFLOW) != 0;
+ return fetestexcept (FE_UNDERFLOW) != 0;
#else
- bool got_fe_underflow = false;
+ return false;
#endif
- printf ("strtod (%s) (%s) returned %a, errno = %d, %sunderflow exception\n",
- s, mode_name, d, got_errno, got_fe_underflow ? "" : "no ");
- bool this_expect_underflow = expect_underflow (c, rm);
- if (got_errno != 0 && got_errno != ERANGE)
- {
- puts ("FAIL: errno neither 0 nor ERANGE");
- result = 1;
- }
- else if (this_expect_underflow != (errno == ERANGE))
- {
- puts ("FAIL: underflow from errno differs from expectations");
- result = 1;
- }
- if (support_underflow_exception && got_fe_underflow != this_expect_underflow)
- {
- puts ("FAIL: underflow from exceptions differs from expectations");
- result = 1;
- }
- return result;
+}
+
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+static int \
+test_strto ## FSUF (int i, int rm, const char *mode_name) \
+{ \
+ const char *s = tests[i].s_ ## FSUF; \
+ enum underflow_case c = tests[i].c; \
+ int result = 0; \
+ feclearexcept (FE_ALL_EXCEPT); \
+ errno = 0; \
+ FTYPE d = strto ## FSUF (s, NULL); \
+ int got_errno = errno; \
+ bool got_fe_underflow = test_got_fe_underflow (); \
+ char buf[FSTRLENMAX]; \
+ FTOSTR (buf, sizeof (buf), "%a", d); \
+ printf ("strto" #FSUF \
+ " (%s) (%s) returned %s, errno = %d, " \
+ "%sunderflow exception\n", \
+ s, mode_name, buf, got_errno, \
+ got_fe_underflow ? "" : "no "); \
+ bool this_expect_underflow = expect_underflow (c, rm); \
+ if (got_errno != 0 && got_errno != ERANGE) \
+ { \
+ puts ("FAIL: errno neither 0 nor ERANGE"); \
+ result = 1; \
+ } \
+ else if (this_expect_underflow != (errno == ERANGE)) \
+ { \
+ puts ("FAIL: underflow from errno differs from expectations"); \
+ result = 1; \
+ } \
+ if (support_underflow_exception \
+ && got_fe_underflow != this_expect_underflow) \
+ { \
+ puts ("FAIL: underflow from exceptions " \
+ "differs from expectations"); \
+ result = 1; \
+ } \
+ return result; \
+}
+
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
+
+static int
+test_in_one_mode (size_t i, int rm, const char *mode_name)
+{
+ return STRTOD_TEST_FOREACH (test_strto, i, rm, mode_name);
}
static int
@@ -191,12 +428,12 @@ do_test (void)
#endif
for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
{
- result |= test_in_one_mode (tests[i].s, tests[i].c, fe_tonearest,
+ result |= test_in_one_mode (i, fe_tonearest,
"default rounding mode");
#ifdef FE_DOWNWARD
if (!fesetround (FE_DOWNWARD))
{
- result |= test_in_one_mode (tests[i].s, tests[i].c, FE_DOWNWARD,
+ result |= test_in_one_mode (i, FE_DOWNWARD,
"FE_DOWNWARD");
fesetround (save_round_mode);
}
@@ -204,7 +441,7 @@ do_test (void)
#ifdef FE_TOWARDZERO
if (!fesetround (FE_TOWARDZERO))
{
- result |= test_in_one_mode (tests[i].s, tests[i].c, FE_TOWARDZERO,
+ result |= test_in_one_mode (i, FE_TOWARDZERO,
"FE_TOWARDZERO");
fesetround (save_round_mode);
}
@@ -212,7 +449,7 @@ do_test (void)
#ifdef FE_UPWARD
if (!fesetround (FE_UPWARD))
{
- result |= test_in_one_mode (tests[i].s, tests[i].c, FE_UPWARD,
+ result |= test_in_one_mode (i, FE_UPWARD,
"FE_UPWARD");
fesetround (save_round_mode);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,445 @@
commit 457622c2fa8f9f7435822d5287a437bc8be8090d
Author: Joseph Myers <josmyers@redhat.com>
Date: Tue Aug 27 12:41:02 2024 +0000
Fix strtod subnormal rounding (bug 30220)
As reported in bug 30220, the implementation of strtod-family
functions has a bug in the following case: the input string would,
with infinite exponent range, take one more bit to represent than is
available in the normal precision of the return type; the value
represented is in the subnormal range; and there are no nonzero bits
in the value, below those that can be represented in subnormal
precision, other than the least significant bit and possibly the
0.5ulp bit. In this case, round_and_return ends up discarding the
least significant bit.
Fix by saving that bit to merge into more_bits (it can't be merged in
at the time it's computed, because more_bits mustn't include this bit
in the case of after-rounding tininess detection checking if the
result is still subnormal when rounded to normal precision, so merging
this bit into more_bits needs to take place after that check).
Tested for x86_64.
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index 5a54d99ae8663641..49b88e9a86be8441 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -223,6 +223,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
mp_size_t shift = MIN_EXP - 1 - exponent;
bool is_tiny = true;
+ bool old_half_bit = (round_limb & (((mp_limb_t) 1) << round_bit)) != 0;
more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
if (shift == MANT_DIG)
@@ -293,6 +294,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
round_bit = shift - 1;
(void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
}
+ more_bits |= old_half_bit;
/* This is a hook for the m68k long double format, where the
exponent bias is the same for normalized and denormalized
numbers. */
diff --git a/stdlib/tst-strtod-round-data b/stdlib/tst-strtod-round-data
index 84ab705709b24b6c..9489fbcc9ce7eee2 100644
--- a/stdlib/tst-strtod-round-data
+++ b/stdlib/tst-strtod-round-data
@@ -265,3 +265,15 @@
1.000000000000000000000000000000000385185988877447170611195588516985463707620329643077639047987759113311767578125
1.0000000000000000000000000000000001925929944387235853055977942584927318538101648215388195239938795566558837890625
1.00000000000000000000000000000000009629649721936179265279889712924636592690508241076940976199693977832794189453125
+0x30000002222225p-1077
+0x0.7fffffffffffeap-1022
+0x0.7fffffffffffe9p-1022
+0x0.7ffffd4p-126
+0x0.7ffffffffffffffd4p-16382
+0x0.7ffffffffffffffd4p-16383
+0x0.7ffffffffffffffffffffffffffeap-16382
+0x0.7000004p-126
+0x0.70000000000002p-1022
+0x0.70000000000000004p-16382
+0x0.70000000000000004p-16383
+0x0.70000000000000000000000000002p-16382
diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h
index 13e62dd2b0588a16..ed50eb2537bc175c 100644
--- a/stdlib/tst-strtod-round-data.h
+++ b/stdlib/tst-strtod-round-data.h
@@ -15437,4 +15437,376 @@ static const struct test tests[] = {
0x1p+0, false, false,
0x1p+0, false, false,
0x1.0000000000000000000000000001p+0, false, false),
+ TEST ("0x30000002222225p-1077",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x1.800000111111p-1024, false, true,
+ 0x1.8000001111114p-1024, false, true,
+ 0x1.800000111111p-1024, false, true,
+ 0x1.8000001111114p-1024, false, true,
+ true,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ true,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ false,
+ 0x1.800000111111p-1024, false, true,
+ 0x1.8000001111114p-1024, false, true,
+ 0x1.800000111111p-1024, false, true,
+ 0x1.8000001111114p-1024, false, true,
+ true,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false,
+ 0x1.80000011111128p-1024, false, false),
+ TEST ("0x0.7fffffffffffeap-1022",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ true,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ true,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ false,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ true,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false,
+ 0x1.ffffffffffffa8p-1024, false, false),
+ TEST ("0x0.7fffffffffffe9p-1022",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ true,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ true,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ false,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ 0x1.ffffffffffff8p-1024, false, true,
+ 0x1.ffffffffffffcp-1024, false, true,
+ true,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false,
+ 0x1.ffffffffffffa4p-1024, false, false),
+ TEST ("0x0.7ffffd4p-126",
+ false,
+ 0x1.fffffp-128, false, true,
+ 0x1.fffff8p-128, false, true,
+ 0x1.fffffp-128, false, true,
+ 0x1.fffff8p-128, false, true,
+ true,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ true,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ true,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ true,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ true,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false,
+ 0x1.fffff5p-128, false, false),
+ TEST ("0x0.7ffffffffffffffd4p-16382",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0x1.fffffffffffffffp-16384, false, true,
+ 0x1.fffffffffffffff8p-16384, false, true,
+ 0x1.fffffffffffffffp-16384, false, true,
+ 0x1.fffffffffffffff8p-16384, false, true,
+ false,
+ 0x1.fffffffffffffff4p-16384, false, true,
+ 0x1.fffffffffffffff4p-16384, false, true,
+ 0x1.fffffffffffffff4p-16384, false, true,
+ 0x1.fffffffffffffff8p-16384, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ true,
+ 0x1.fffffffffffffff5p-16384, false, false,
+ 0x1.fffffffffffffff5p-16384, false, false,
+ 0x1.fffffffffffffff5p-16384, false, false,
+ 0x1.fffffffffffffff5p-16384, false, false),
+ TEST ("0x0.7ffffffffffffffd4p-16383",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0xf.ffffffffffffff8p-16388, false, true,
+ 0xf.ffffffffffffff8p-16388, false, true,
+ 0xf.ffffffffffffff8p-16388, false, true,
+ 0x1p-16384, false, true,
+ false,
+ 0xf.ffffffffffffff8p-16388, false, true,
+ 0xf.ffffffffffffffcp-16388, false, true,
+ 0xf.ffffffffffffff8p-16388, false, true,
+ 0xf.ffffffffffffffcp-16388, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ true,
+ 0xf.ffffffffffffffa8p-16388, false, false,
+ 0xf.ffffffffffffffa8p-16388, false, false,
+ 0xf.ffffffffffffffa8p-16388, false, false,
+ 0xf.ffffffffffffffa8p-16388, false, false),
+ TEST ("0x0.7ffffffffffffffffffffffffffeap-16382",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0x1.fffffffffffffff8p-16384, false, true,
+ 0x2p-16384, false, true,
+ 0x1.fffffffffffffff8p-16384, false, true,
+ 0x2p-16384, false, true,
+ false,
+ 0x1.fffffffffffffffcp-16384, false, true,
+ 0x2p-16384, false, true,
+ 0x1.fffffffffffffffcp-16384, false, true,
+ 0x2p-16384, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0x1.fffffffffffffffffffffffffff8p-16384, false, true,
+ 0x1.fffffffffffffffffffffffffffcp-16384, false, true,
+ 0x1.fffffffffffffffffffffffffff8p-16384, false, true,
+ 0x1.fffffffffffffffffffffffffffcp-16384, false, true),
+ TEST ("0x0.7000004p-126",
+ false,
+ 0x1.cp-128, false, true,
+ 0x1.cp-128, false, true,
+ 0x1.cp-128, false, true,
+ 0x1.c00008p-128, false, true,
+ true,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ true,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ true,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ true,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ true,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false,
+ 0x1.c00001p-128, false, false),
+ TEST ("0x0.70000000000002p-1022",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x1.cp-1024, false, true,
+ 0x1.cp-1024, false, true,
+ 0x1.cp-1024, false, true,
+ 0x1.c000000000004p-1024, false, true,
+ true,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ true,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ false,
+ 0x1.cp-1024, false, true,
+ 0x1.cp-1024, false, true,
+ 0x1.cp-1024, false, true,
+ 0x1.c000000000004p-1024, false, true,
+ true,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false,
+ 0x1.c0000000000008p-1024, false, false),
+ TEST ("0x0.70000000000000004p-16382",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.c000000000000008p-16384, false, true,
+ false,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.c000000000000004p-16384, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ true,
+ 0x1.c000000000000001p-16384, false, false,
+ 0x1.c000000000000001p-16384, false, false,
+ 0x1.c000000000000001p-16384, false, false,
+ 0x1.c000000000000001p-16384, false, false),
+ TEST ("0x0.70000000000000004p-16383",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0xep-16388, false, true,
+ 0xep-16388, false, true,
+ 0xep-16388, false, true,
+ 0xe.000000000000008p-16388, false, true,
+ false,
+ 0xep-16388, false, true,
+ 0xep-16388, false, true,
+ 0xep-16388, false, true,
+ 0xe.000000000000004p-16388, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ true,
+ 0xe.0000000000000008p-16388, false, false,
+ 0xe.0000000000000008p-16388, false, false,
+ 0xe.0000000000000008p-16388, false, false,
+ 0xe.0000000000000008p-16388, false, false),
+ TEST ("0x0.70000000000000000000000000002p-16382",
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x8p-152, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.c000000000000008p-16384, false, true,
+ false,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.c000000000000004p-16384, false, true,
+ false,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x0p+0, false, true,
+ 0x4p-1076, false, true,
+ false,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.cp-16384, false, true,
+ 0x1.c000000000000000000000000004p-16384, false, true),
};

View File

@ -0,0 +1,598 @@
commit 3fc063dee01da4f80920a14b7db637c8501d6fd4
Author: Joseph Myers <josmyers@redhat.com>
Date: Tue Aug 27 20:41:54 2024 +0000
Make __strtod_internal tests type-generic
Some of the strtod tests use type-generic machinery in tst-strtod.h to
test the strto* functions for all floating types, while others only
test double even when the tests are in fact meaningful for all
floating types.
Convert the tests of the internal __strtod_internal interface to cover
all floating types. I haven't tried to convert them to use newer test
interfaces in other ways, just made the changes necessary to use the
type-generic machinery. As an internal interface, there are no
aliases for different types with the same ABI (however,
__strtold_internal is defined even if long double has the same ABI as
double), so macros used by the type-generic testing code are redefined
as needed to avoid expecting such aliases to be present.
Tested for x86_64.
Conflicts:
stdlib/tst-strtod4.c
(69239bd7a216007692470aa9d5f3658024638742 missing downstream)
diff --git a/stdlib/tst-strtod1i.c b/stdlib/tst-strtod1i.c
index 98fc5d527fe1edd9..32fc8b9e1f08ace9 100644
--- a/stdlib/tst-strtod1i.c
+++ b/stdlib/tst-strtod1i.c
@@ -25,60 +25,91 @@
#include <string.h>
#include <math.h>
-/* Perform a few tests in a locale with thousands separators. */
-static int
-do_test (void)
-{
- static const struct
- {
- const char *loc;
- const char *str;
- double exp;
- ptrdiff_t nread;
- } tests[] =
- {
- { "de_DE.UTF-8", "1,5", 1.5, 3 },
- { "de_DE.UTF-8", "1.5", 1.0, 1 },
- { "de_DE.UTF-8", "1.500", 1500.0, 5 },
- { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65, 26 }
- };
-#define ntests (sizeof (tests) / sizeof (tests[0]))
- size_t n;
- int result = 0;
-
- puts ("\nLocale tests");
+#include "tst-strtod.h"
- for (n = 0; n < ntests; ++n)
- {
- double d;
- char *endp;
+/* This tests internal interfaces, which are only defined for types
+ with distinct ABIs, so disable testing for types without distinct
+ ABIs. */
+#undef IF_FLOAT32
+#define IF_FLOAT32(x)
+#undef IF_FLOAT64
+#define IF_FLOAT64(x)
+#undef IF_FLOAT32X
+#define IF_FLOAT32X(x)
+#undef IF_FLOAT64X
+#define IF_FLOAT64X(x)
+#if !__HAVE_DISTINCT_FLOAT128
+# undef IF_FLOAT128
+# define IF_FLOAT128(x)
+#endif
- if (setlocale (LC_ALL, tests[n].loc) == NULL)
- {
- printf ("cannot set locale %s\n", tests[n].loc);
- result = 1;
- continue;
- }
+#define ntests (sizeof (tests) / sizeof (tests[0]))
- d = __strtod_internal (tests[n].str, &endp, 1);
- if (d != tests[n].exp)
- {
- printf ("strtod(\"%s\") returns %g and not %g\n",
- tests[n].str, d, tests[n].exp);
- result = 1;
- }
- else if (endp - tests[n].str != tests[n].nread)
- {
- printf ("strtod(\"%s\") read %td bytes and not %td\n",
- tests[n].str, endp - tests[n].str, tests[n].nread);
- result = 1;
- }
- }
+/* Perform a few tests in a locale with thousands separators. */
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+static int \
+test_strto ## FSUF (void) \
+{ \
+ static const struct \
+ { \
+ const char *loc; \
+ const char *str; \
+ FTYPE exp; \
+ ptrdiff_t nread; \
+ } tests[] = \
+ { \
+ { "de_DE.UTF-8", "1,5", 1.5 ## LSUF, 3 }, \
+ { "de_DE.UTF-8", "1.5", 1.0 ## LSUF, 1 }, \
+ { "de_DE.UTF-8", "1.500", 1500.0 ## LSUF, 5 }, \
+ { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65 ## LSUF, 26 } \
+ }; \
+ size_t n; \
+ int result = 0; \
+ \
+ puts ("\nLocale tests"); \
+ \
+ for (n = 0; n < ntests; ++n) \
+ { \
+ FTYPE d; \
+ char *endp; \
+ \
+ if (setlocale (LC_ALL, tests[n].loc) == NULL) \
+ { \
+ printf ("cannot set locale %s\n", tests[n].loc); \
+ result = 1; \
+ continue; \
+ } \
+ \
+ d = __strto ## FSUF ## _internal (tests[n].str, &endp, 1); \
+ if (d != tests[n].exp) \
+ { \
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
+ FTOSTR (buf1, sizeof (buf1), "%g", d); \
+ FTOSTR (buf2, sizeof (buf2), "%g", tests[n].exp); \
+ printf ("strto" # FSUF "(\"%s\") returns %s and not %s\n", \
+ tests[n].str, buf1, buf2); \
+ result = 1; \
+ } \
+ else if (endp - tests[n].str != tests[n].nread) \
+ { \
+ printf ("strto" # FSUF "(\"%s\") read %td bytes and not %td\n", \
+ tests[n].str, endp - tests[n].str, tests[n].nread); \
+ result = 1; \
+ } \
+ } \
+ \
+ if (result == 0) \
+ puts ("all OK"); \
+ \
+ return result ? EXIT_FAILURE : EXIT_SUCCESS; \
+}
- if (result == 0)
- puts ("all OK");
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
- return result ? EXIT_FAILURE : EXIT_SUCCESS;
+static int
+do_test (void)
+{
+ return STRTOD_TEST_FOREACH (test_strto);
}
#include <support/test-driver.c>
diff --git a/stdlib/tst-strtod3.c b/stdlib/tst-strtod3.c
index 23abec1896896276..0d662d8be83a7525 100644
--- a/stdlib/tst-strtod3.c
+++ b/stdlib/tst-strtod3.c
@@ -3,19 +3,73 @@
#include <stdlib.h>
#include <string.h>
-static const struct
-{
- const char *in;
- const char *out;
- double expected;
-} tests[] =
- {
- { "000,,,e1", ",,,e1", 0.0 },
- { "000e1", "", 0.0 },
- { "000,1e1", ",1e1", 0.0 }
- };
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
+#include "tst-strtod.h"
+
+/* This tests internal interfaces, which are only defined for types
+ with distinct ABIs, so disable testing for types without distinct
+ ABIs. */
+#undef IF_FLOAT32
+#define IF_FLOAT32(x)
+#undef IF_FLOAT64
+#define IF_FLOAT64(x)
+#undef IF_FLOAT32X
+#define IF_FLOAT32X(x)
+#undef IF_FLOAT64X
+#define IF_FLOAT64X(x)
+#if !__HAVE_DISTINCT_FLOAT128
+# undef IF_FLOAT128
+# define IF_FLOAT128(x)
+#endif
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+static const struct \
+{ \
+ const char *in; \
+ const char *out; \
+ FTYPE expected; \
+} tests_strto ## FSUF[] = \
+ { \
+ { "000,,,e1", ",,,e1", 0.0 ## LSUF }, \
+ { "000e1", "", 0.0 ## LSUF }, \
+ { "000,1e1", ",1e1", 0.0 ## LSUF } \
+ }; \
+ \
+static int \
+test_strto ## FSUF (void) \
+{ \
+ int status = 0; \
+ \
+ for (int i = 0; \
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
+ ++i) \
+ { \
+ char *ep; \
+ FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
+ &ep, 1); \
+ \
+ if (strcmp (ep, tests_strto ## FSUF[i].out) != 0) \
+ { \
+ printf ("%d: got rest string \"%s\", expected \"%s\"\n", \
+ i, ep, tests_strto ## FSUF[i].out); \
+ status = 1; \
+ } \
+ \
+ if (r != tests_strto ## FSUF[i].expected) \
+ { \
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
+ FTOSTR (buf2, sizeof (buf2), "%g", \
+ tests_strto ## FSUF[i].expected); \
+ printf ("%d: got wrong results %s, expected %s\n", \
+ i, buf1, buf2); \
+ status = 1; \
+ } \
+ } \
+ \
+ return status; \
+}
+
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
static int
do_test (void)
@@ -26,29 +80,7 @@ do_test (void)
return 1;
}
- int status = 0;
-
- for (int i = 0; i < NTESTS; ++i)
- {
- char *ep;
- double r = __strtod_internal (tests[i].in, &ep, 1);
-
- if (strcmp (ep, tests[i].out) != 0)
- {
- printf ("%d: got rest string \"%s\", expected \"%s\"\n",
- i, ep, tests[i].out);
- status = 1;
- }
-
- if (r != tests[i].expected)
- {
- printf ("%d: got wrong results %g, expected %g\n",
- i, r, tests[i].expected);
- status = 1;
- }
- }
-
- return status;
+ return STRTOD_TEST_FOREACH (test_strto);
}
#define TEST_FUNCTION do_test ()
diff --git a/stdlib/tst-strtod4.c b/stdlib/tst-strtod4.c
index aae9835d82d38b4e..cd86f8c1f13a39e4 100644
--- a/stdlib/tst-strtod4.c
+++ b/stdlib/tst-strtod4.c
@@ -3,20 +3,74 @@
#include <stdlib.h>
#include <string.h>
+#include "tst-strtod.h"
+
+/* This tests internal interfaces, which are only defined for types
+ with distinct ABIs, so disable testing for types without distinct
+ ABIs. */
+#undef IF_FLOAT32
+#define IF_FLOAT32(x)
+#undef IF_FLOAT64
+#define IF_FLOAT64(x)
+#undef IF_FLOAT32X
+#define IF_FLOAT32X(x)
+#undef IF_FLOAT64X
+#define IF_FLOAT64X(x)
+#if !__HAVE_DISTINCT_FLOAT128
+# undef IF_FLOAT128
+# define IF_FLOAT128(x)
+#endif
+
#define NNBSP "\xe2\x80\xaf"
-static const struct
-{
- const char *in;
- const char *out;
- double expected;
-} tests[] =
- {
- { "000"NNBSP"000"NNBSP"000", "", 0.0 },
- { "1"NNBSP"000"NNBSP"000,5x", "x", 1000000.5 }
- };
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+static const struct \
+{ \
+ const char *in; \
+ const char *out; \
+ FTYPE expected; \
+} tests_strto ## FSUF[] = \
+ { \
+ { "000"NNBSP"000"NNBSP"000", "", 0.0 ## LSUF }, \
+ { "1"NNBSP"000"NNBSP"000,5x", "x", 1000000.5 ## LSUF } \
+ }; \
+ \
+static int \
+test_strto ## FSUF (void) \
+{ \
+ int status = 0; \
+ \
+ for (int i = 0; \
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
+ ++i) \
+ { \
+ char *ep; \
+ FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
+ &ep, 1); \
+ \
+ if (strcmp (ep, tests_strto ## FSUF[i].out) != 0) \
+ { \
+ printf ("%d: got rest string \"%s\", expected \"%s\"\n", \
+ i, ep, tests_strto ## FSUF[i].out); \
+ status = 1; \
+ } \
+ \
+ if (r != tests_strto ## FSUF[i].expected) \
+ { \
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
+ FTOSTR (buf2, sizeof (buf2), "%g", \
+ tests_strto ## FSUF[i].expected); \
+ printf ("%d: got wrong results %s, expected %s\n", \
+ i, buf1, buf2); \
+ status = 1; \
+ } \
+ } \
+ \
+ return status; \
+}
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
static int
do_test (void)
@@ -27,29 +81,7 @@ do_test (void)
return 1;
}
- int status = 0;
-
- for (int i = 0; i < NTESTS; ++i)
- {
- char *ep;
- double r = __strtod_internal (tests[i].in, &ep, 1);
-
- if (strcmp (ep, tests[i].out) != 0)
- {
- printf ("%d: got rest string \"%s\", expected \"%s\"\n",
- i, ep, tests[i].out);
- status = 1;
- }
-
- if (r != tests[i].expected)
- {
- printf ("%d: got wrong results %g, expected %g\n",
- i, r, tests[i].expected);
- status = 1;
- }
- }
-
- return status;
+ return STRTOD_TEST_FOREACH (test_strto);
}
#define TEST_FUNCTION do_test ()
diff --git a/stdlib/tst-strtod5i.c b/stdlib/tst-strtod5i.c
index ba3e78d5f2933586..0ddae2b94765de39 100644
--- a/stdlib/tst-strtod5i.c
+++ b/stdlib/tst-strtod5i.c
@@ -16,52 +16,112 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+/* Defining _LIBC_TEST ensures long double math functions are
+ declared in the headers. */
+#define _LIBC_TEST 1
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include "tst-strtod.h"
+
+/* This tests internal interfaces, which are only defined for types
+ with distinct ABIs, so disable testing for types without distinct
+ ABIs. */
+#undef IF_FLOAT32
+#define IF_FLOAT32(x)
+#undef IF_FLOAT64
+#define IF_FLOAT64(x)
+#undef IF_FLOAT32X
+#define IF_FLOAT32X(x)
+#undef IF_FLOAT64X
+#define IF_FLOAT64X(x)
+#if !__HAVE_DISTINCT_FLOAT128
+# undef IF_FLOAT128
+# define IF_FLOAT128(x)
+#endif
+
#define NNBSP "\xe2\x80\xaf"
-static const struct
-{
- const char *in;
- int group;
- double expected;
-} tests[] =
- {
- { "0", 0, 0.0 },
- { "000", 0, 0.0 },
- { "-0", 0, -0.0 },
- { "-000", 0, -0.0 },
- { "0,", 0, 0.0 },
- { "-0,", 0, -0.0 },
- { "0,0", 0, 0.0 },
- { "-0,0", 0, -0.0 },
- { "0e-10", 0, 0.0 },
- { "-0e-10", 0, -0.0 },
- { "0,e-10", 0, 0.0 },
- { "-0,e-10", 0, -0.0 },
- { "0,0e-10", 0, 0.0 },
- { "-0,0e-10", 0, -0.0 },
- { "0e-1000000", 0, 0.0 },
- { "-0e-1000000", 0, -0.0 },
- { "0,0e-1000000", 0, 0.0 },
- { "-0,0e-1000000", 0, -0.0 },
- { "0", 1, 0.0 },
- { "000", 1, 0.0 },
- { "-0", 1, -0.0 },
- { "-000", 1, -0.0 },
- { "0e-10", 1, 0.0 },
- { "-0e-10", 1, -0.0 },
- { "0e-1000000", 1, 0.0 },
- { "-0e-1000000", 1, -0.0 },
- { "000"NNBSP"000"NNBSP"000", 1, 0.0 },
- { "-000"NNBSP"000"NNBSP"000", 1, -0.0 }
- };
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+static const struct \
+{ \
+ const char *in; \
+ int group; \
+ FTYPE expected; \
+} tests_strto ## FSUF[] = \
+ { \
+ { "0", 0, 0.0 ## LSUF }, \
+ { "000", 0, 0.0 ## LSUF }, \
+ { "-0", 0, -0.0 ## LSUF }, \
+ { "-000", 0, -0.0 ## LSUF }, \
+ { "0,", 0, 0.0 ## LSUF }, \
+ { "-0,", 0, -0.0 ## LSUF }, \
+ { "0,0", 0, 0.0 ## LSUF }, \
+ { "-0,0", 0, -0.0 ## LSUF }, \
+ { "0e-10", 0, 0.0 ## LSUF }, \
+ { "-0e-10", 0, -0.0 ## LSUF }, \
+ { "0,e-10", 0, 0.0 ## LSUF }, \
+ { "-0,e-10", 0, -0.0 ## LSUF }, \
+ { "0,0e-10", 0, 0.0 ## LSUF }, \
+ { "-0,0e-10", 0, -0.0 ## LSUF }, \
+ { "0e-1000000", 0, 0.0 ## LSUF }, \
+ { "-0e-1000000", 0, -0.0 ## LSUF }, \
+ { "0,0e-1000000", 0, 0.0 ## LSUF }, \
+ { "-0,0e-1000000", 0, -0.0 ## LSUF }, \
+ { "0", 1, 0.0 ## LSUF }, \
+ { "000", 1, 0.0 ## LSUF }, \
+ { "-0", 1, -0.0 ## LSUF }, \
+ { "-000", 1, -0.0 ## LSUF }, \
+ { "0e-10", 1, 0.0 ## LSUF }, \
+ { "-0e-10", 1, -0.0 ## LSUF }, \
+ { "0e-1000000", 1, 0.0 ## LSUF }, \
+ { "-0e-1000000", 1, -0.0 ## LSUF }, \
+ { "000"NNBSP"000"NNBSP"000", 1, 0.0 ## LSUF }, \
+ { "-000"NNBSP"000"NNBSP"000", 1, -0.0 ## LSUF } \
+ }; \
+ \
+static int \
+test_strto ## FSUF (void) \
+{ \
+ int status = 0; \
+ \
+ for (int i = 0; \
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
+ ++i) \
+ { \
+ char *ep; \
+ FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
+ &ep, \
+ tests_strto ## FSUF[i].group); \
+ \
+ if (*ep != '\0') \
+ { \
+ printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep); \
+ status = 1; \
+ } \
+ \
+ if (r != tests_strto ## FSUF[i].expected \
+ || (copysign ## CSUF (10.0 ## LSUF, r) \
+ != copysign ## CSUF (10.0 ## LSUF, \
+ tests_strto ## FSUF[i].expected))) \
+ { \
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
+ FTOSTR (buf2, sizeof (buf2), "%g", \
+ tests_strto ## FSUF[i].expected); \
+ printf ("%d: got wrong results %s, expected %s\n", \
+ i, buf1, buf2); \
+ status = 1; \
+ } \
+ } \
+ \
+ return status; \
+}
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
static int
do_test (void)
@@ -72,29 +132,7 @@ do_test (void)
return 1;
}
- int status = 0;
-
- for (int i = 0; i < NTESTS; ++i)
- {
- char *ep;
- double r = __strtod_internal (tests[i].in, &ep, tests[i].group);
-
- if (*ep != '\0')
- {
- printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep);
- status = 1;
- }
-
- if (r != tests[i].expected
- || copysign (10.0, r) != copysign (10.0, tests[i].expected))
- {
- printf ("%d: got wrong results %g, expected %g\n",
- i, r, tests[i].expected);
- status = 1;
- }
- }
-
- return status;
+ return STRTOD_TEST_FOREACH (test_strto);
}
#include <support/test-driver.c>

View File

@ -0,0 +1,140 @@
commit be77d5ae417236883c02d3d67c0716e3f669fa41
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Sep 4 13:20:18 2024 +0000
Improve NaN payload testing
There are two separate sets of tests of NaN payloads in glibc:
* libm-test-{get,set}payload* verify that getpayload, setpayload,
setpayloadsig and __builtin_nan functions are consistent in their
payload handling.
* test-nan-payload verifies that strtod-family functions and the
not-built-in nan functions are consistent in their payload handling.
Nothing, however, connects the two sets of functions (i.e., verifies
that strtod / nan are consistent with getpayload / setpayload /
__builtin_nan).
Improve test-nan-payload to check actual payload value with getpayload
rather than just verifying that the strtod and nan functions produce
the same NaN. Also check that the NaNs produced aren't signaling and
extend the tests to cover _FloatN / _FloatNx.
Tested for x86_64.
diff --git a/math/test-nan-payload.c b/math/test-nan-payload.c
index 88fd727e63b2fda2..0ee5432d40a3f997 100644
--- a/math/test-nan-payload.c
+++ b/math/test-nan-payload.c
@@ -16,6 +16,8 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#define _LIBC_TEST 1
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>
#include <math.h>
#include <stdio.h>
@@ -31,7 +33,7 @@
#define CHECK_IS_NAN(TYPE, A) \
do \
{ \
- if (isnan (A)) \
+ if (isnan (A) && !issignaling (A)) \
puts ("PASS: " #TYPE " " #A); \
else \
{ \
@@ -41,6 +43,19 @@
} \
while (0)
+#define CHECK_PAYLOAD(TYPE, FUNC, A, P) \
+ do \
+ { \
+ if (FUNC (&(A)) == (P)) \
+ puts ("PASS: " #TYPE " payload " #A); \
+ else \
+ { \
+ puts ("FAIL: " #TYPE " payload " #A); \
+ result = 1; \
+ } \
+ } \
+ while (0)
+
#define CHECK_SAME_NAN(TYPE, A, B) \
do \
{ \
@@ -71,7 +86,7 @@
bits. */
#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
-#define RUN_TESTS(TYPE, SFUNC, FUNC, MANT_DIG) \
+#define RUN_TESTS(TYPE, SFUNC, FUNC, PLFUNC, MANT_DIG) \
do \
{ \
TYPE n123 = WRAP_NAN (FUNC, "123"); \
@@ -82,6 +97,10 @@
CHECK_IS_NAN (TYPE, n456); \
TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
CHECK_IS_NAN (TYPE, s456); \
+ TYPE nh123 = WRAP_NAN (FUNC, "0x123"); \
+ CHECK_IS_NAN (TYPE, nh123); \
+ TYPE sh123 = WRAP_STRTO (SFUNC, "NAN(0x123)"); \
+ CHECK_IS_NAN (TYPE, sh123); \
TYPE n123x = WRAP_NAN (FUNC, "123)"); \
CHECK_IS_NAN (TYPE, n123x); \
TYPE nemp = WRAP_NAN (FUNC, ""); \
@@ -92,8 +111,16 @@
CHECK_IS_NAN (TYPE, sx); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, n123, s123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, n123, 123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, s123, 123); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, n456, s456); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, n456, 456); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, s456, 456); \
+ if (CAN_TEST_EQ (MANT_DIG)) \
+ CHECK_SAME_NAN (TYPE, nh123, sh123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, nh123, 0x123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, sh123, 0x123); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, nemp, semp); \
if (CAN_TEST_EQ (MANT_DIG)) \
@@ -110,9 +137,31 @@ static int
do_test (void)
{
int result = 0;
- RUN_TESTS (float, strtof, nanf, FLT_MANT_DIG);
- RUN_TESTS (double, strtod, nan, DBL_MANT_DIG);
- RUN_TESTS (long double, strtold, nanl, LDBL_MANT_DIG);
+ RUN_TESTS (float, strtof, nanf, getpayloadf, FLT_MANT_DIG);
+ RUN_TESTS (double, strtod, nan, getpayload, DBL_MANT_DIG);
+ RUN_TESTS (long double, strtold, nanl, getpayloadl, LDBL_MANT_DIG);
+#if __HAVE_FLOAT16
+ RUN_TESTS (_Float16, strtof16, nanf16, getpayloadf16, FLT16_MANT_DIG);
+#endif
+#if __HAVE_FLOAT32
+ RUN_TESTS (_Float32, strtof32, nanf32, getpayloadf32, FLT32_MANT_DIG);
+#endif
+#if __HAVE_FLOAT64
+ RUN_TESTS (_Float64, strtof64, nanf64, getpayloadf64, FLT64_MANT_DIG);
+#endif
+#if __HAVE_FLOAT128
+ RUN_TESTS (_Float128, strtof128, nanf128, getpayloadf128, FLT128_MANT_DIG);
+#endif
+#if __HAVE_FLOAT32X
+ RUN_TESTS (_Float32x, strtof32x, nanf32x, getpayloadf32x, FLT32X_MANT_DIG);
+#endif
+#if __HAVE_FLOAT64X
+ RUN_TESTS (_Float64x, strtof64x, nanf64x, getpayloadf64x, FLT64X_MANT_DIG);
+#endif
+#if __HAVE_FLOAT128X
+ RUN_TESTS (_Float128x, strtof128x, nanf128x, getpayloadf128x,
+ FLT128X_MANT_DIG);
+#endif
return result;
}

View File

@ -0,0 +1,147 @@
commit 64f62c47e9c350f353336f2df6714e1d48ec50d8
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Sep 4 13:21:23 2024 +0000
Do not set errno for overflowing NaN payload in strtod/nan (bug 32045)
As reported in bug 32045, it's incorrect for strtod/nan functions to
set errno based on overflowing payload (strtod should only set errno
for overflow / underflow of its actual result, and potentially if
nothing in the string can be parsed as a number at all; nan should be
a pure function that never sets it). Save and restore errno around
the internal strtoull call and add associated test coverage.
Tested for x86_64.
diff --git a/math/Makefile b/math/Makefile
index 2edb044d9d590de1..a3c44def8acae93b 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -452,6 +452,7 @@ CFLAGS-test-flt-eval-method.c += -fexcess-precision=standard
CFLAGS-test-fe-snans-always-signal.c += -fsignaling-nans
CFLAGS-test-nan-const.c += -fno-builtin
+CFLAGS-test-nan-payload.c += -fno-builtin
include ../Rules
diff --git a/math/test-nan-payload.c b/math/test-nan-payload.c
index 0ee5432d40a3f997..5f54bf26b6163816 100644
--- a/math/test-nan-payload.c
+++ b/math/test-nan-payload.c
@@ -18,6 +18,7 @@
#define _LIBC_TEST 1
#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
@@ -82,6 +83,26 @@
} \
while (0)
+#define CLEAR_ERRNO \
+ do \
+ { \
+ errno = 12345; \
+ } \
+ while (0)
+
+#define CHECK_ERRNO(TYPE, A) \
+ do \
+ { \
+ if (errno == 12345) \
+ puts ("PASS: " #TYPE " " #A " errno"); \
+ else \
+ { \
+ puts ("FAIL: " #TYPE " " #A " errno"); \
+ result = 1; \
+ } \
+ } \
+ while (0)
+
/* Cannot test payloads by memcmp for formats where NaNs have padding
bits. */
#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
@@ -89,26 +110,58 @@
#define RUN_TESTS(TYPE, SFUNC, FUNC, PLFUNC, MANT_DIG) \
do \
{ \
+ CLEAR_ERRNO; \
TYPE n123 = WRAP_NAN (FUNC, "123"); \
+ CHECK_ERRNO (TYPE, n123); \
CHECK_IS_NAN (TYPE, n123); \
+ CLEAR_ERRNO; \
TYPE s123 = WRAP_STRTO (SFUNC, "NAN(123)"); \
+ CHECK_ERRNO (TYPE, s123); \
CHECK_IS_NAN (TYPE, s123); \
+ CLEAR_ERRNO; \
TYPE n456 = WRAP_NAN (FUNC, "456"); \
+ CHECK_ERRNO (TYPE, n456); \
CHECK_IS_NAN (TYPE, n456); \
+ CLEAR_ERRNO; \
TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
+ CHECK_ERRNO (TYPE, s456); \
CHECK_IS_NAN (TYPE, s456); \
+ CLEAR_ERRNO; \
TYPE nh123 = WRAP_NAN (FUNC, "0x123"); \
+ CHECK_ERRNO (TYPE, nh123); \
CHECK_IS_NAN (TYPE, nh123); \
+ CLEAR_ERRNO; \
TYPE sh123 = WRAP_STRTO (SFUNC, "NAN(0x123)"); \
+ CHECK_ERRNO (TYPE, sh123); \
CHECK_IS_NAN (TYPE, sh123); \
+ CLEAR_ERRNO; \
TYPE n123x = WRAP_NAN (FUNC, "123)"); \
+ CHECK_ERRNO (TYPE, n123x); \
CHECK_IS_NAN (TYPE, n123x); \
+ CLEAR_ERRNO; \
TYPE nemp = WRAP_NAN (FUNC, ""); \
+ CHECK_ERRNO (TYPE, nemp); \
CHECK_IS_NAN (TYPE, nemp); \
+ CLEAR_ERRNO; \
TYPE semp = WRAP_STRTO (SFUNC, "NAN()"); \
+ CHECK_ERRNO (TYPE, semp); \
CHECK_IS_NAN (TYPE, semp); \
+ CLEAR_ERRNO; \
TYPE sx = WRAP_STRTO (SFUNC, "NAN"); \
+ CHECK_ERRNO (TYPE, sx); \
CHECK_IS_NAN (TYPE, sx); \
+ CLEAR_ERRNO; \
+ TYPE novf = WRAP_NAN (FUNC, "9999999999" \
+ "99999999999999999999" \
+ "9999999999"); \
+ CHECK_ERRNO (TYPE, novf); \
+ CHECK_IS_NAN (TYPE, novf); \
+ CLEAR_ERRNO; \
+ TYPE sovf = WRAP_STRTO (SFUNC, "NAN(9999999999" \
+ "99999999999999999999" \
+ "9999999999)"); \
+ CHECK_ERRNO (TYPE, sovf); \
+ CHECK_IS_NAN (TYPE, sovf); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, n123, s123); \
CHECK_PAYLOAD (TYPE, PLFUNC, n123, 123); \
diff --git a/stdlib/strtod_nan_main.c b/stdlib/strtod_nan_main.c
index ba81355d1c0dbeda..8d7d43818bdba79a 100644
--- a/stdlib/strtod_nan_main.c
+++ b/stdlib/strtod_nan_main.c
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <errno.h>
#include <ieee754.h>
#include <locale.h>
#include <math.h>
@@ -50,7 +51,9 @@ STRTOD_NAN (const STRING_TYPE *str, STRING_TYPE **endptr, STRING_TYPE endc)
STRING_TYPE *endp;
unsigned long long int mant;
+ int save_errno = errno;
mant = STRTOULL (str, &endp, 0);
+ __set_errno (save_errno);
if (endp == cp)
SET_NAN_PAYLOAD (retval, mant);

View File

@ -0,0 +1,76 @@
commit cc3e743fc09ee6fca45767629df9cbcbe1feba82
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Sep 5 21:18:23 2024 +0200
powerpc64le: Build new strtod tests with long double ABI flags (bug 32145)
This fixes several test failures:
=====FAIL: stdlib/tst-strtod1i.out=====
Locale tests
all OK
Locale tests
all OK
Locale tests
strtold("1,5") returns -6,38643e+367 and not 1,5
strtold("1.5") returns 1,5 and not 1
strtold("1.500") returns 1 and not 1500
strtold("36.893.488.147.419.103.232") returns 1500 and not 3,68935e+19
Locale tests
all OK
=====FAIL: stdlib/tst-strtod3.out=====
0: got wrong results -2.5937e+4826, expected 0
=====FAIL: stdlib/tst-strtod4.out=====
0: got wrong results -6,38643e+367, expected 0
1: got wrong results 0, expected 1e+06
2: got wrong results 1e+06, expected 10
=====FAIL: stdlib/tst-strtod5i.out=====
0: got wrong results -6,38643e+367, expected 0
2: got wrong results 0, expected -0
4: got wrong results -0, expected 0
5: got wrong results 0, expected -0
6: got wrong results -0, expected 0
7: got wrong results 0, expected -0
8: got wrong results -0, expected 0
9: got wrong results 0, expected -0
10: got wrong results -0, expected 0
11: got wrong results 0, expected -0
12: got wrong results -0, expected 0
13: got wrong results 0, expected -0
14: got wrong results -0, expected 0
15: got wrong results 0, expected -0
16: got wrong results -0, expected 0
17: got wrong results 0, expected -0
18: got wrong results -0, expected 0
20: got wrong results 0, expected -0
22: got wrong results -0, expected 0
23: got wrong results 0, expected -0
24: got wrong results -0, expected 0
25: got wrong results 0, expected -0
26: got wrong results -0, expected 0
27: got wrong results 0, expected -0
Fixes commit 3fc063dee01da4f80920a14b7db637c8501d6fd4
("Make __strtod_internal tests type-generic").
Suggested-by: Joseph Myers <josmyers@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/sysdeps/powerpc/powerpc64/le/Makefile b/sysdeps/powerpc/powerpc64/le/Makefile
index 7c036b45fcc0d7f9..8bc71fd18d3f1edc 100644
--- a/sysdeps/powerpc/powerpc64/le/Makefile
+++ b/sysdeps/powerpc/powerpc64/le/Makefile
@@ -128,6 +128,10 @@ CFLAGS-tst-strtod-round.c += $(type-float128-CFLAGS)
CFLAGS-tst-wcstod-round.c += $(type-float128-CFLAGS)
CFLAGS-tst-strtod-nan-locale.c += $(type-float128-CFLAGS)
CFLAGS-tst-wcstod-nan-locale.c += $(type-float128-CFLAGS)
+CFLAGS-tst-strtod1i.c += $(type-float128-CFLAGS)
+CFLAGS-tst-strtod3.c += $(type-float128-CFLAGS)
+CFLAGS-tst-strtod4.c += $(type-float128-CFLAGS)
+CFLAGS-tst-strtod5i.c += $(type-float128-CFLAGS)
CFLAGS-tst-strtod6.c += $(type-float128-CFLAGS)
CFLAGS-tst-strfrom.c += $(type-float128-CFLAGS)
CFLAGS-tst-strfrom-locale.c += $(type-float128-CFLAGS)

View File

@ -0,0 +1,254 @@
commit 8de031bcb9adfa736c0caed2c79d10947b8d8f48
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Sep 20 23:23:13 2024 +0000
Make tst-strtod2 and tst-strtod5 type-generic
Some of the strtod tests use type-generic machinery in tst-strtod.h to
test the strto* functions for all floating types, while others only
test double even when the tests are in fact meaningful for all
floating types.
Convert tst-strtod2 and tst-strtod5 to use the type-generic machinery
so they test all floating types. I haven't tried to convert them to
use newer test interfaces in other ways, just made the changes
necessary to use the type-generic machinery.
Tested for x86_64.
diff --git a/stdlib/tst-strtod2.c b/stdlib/tst-strtod2.c
index a7df82ebbde14c5f..2cb0953fa911efd0 100644
--- a/stdlib/tst-strtod2.c
+++ b/stdlib/tst-strtod2.c
@@ -1,43 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
-struct test
-{
- const char *str;
- double result;
- size_t offset;
-} tests[] =
-{
- { "0xy", 0.0, 1 },
- { "0x.y", 0.0, 1 },
- { "0x0.y", 0.0, 4 },
- { "0x.0y", 0.0, 4 },
- { ".y", 0.0, 0 },
- { "0.y", 0.0, 2 },
- { ".0y", 0.0, 2 }
-};
+#include "tst-strtod.h"
+
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+struct test_strto ## FSUF \
+{ \
+ const char *str; \
+ FTYPE result; \
+ size_t offset; \
+} tests_strto ## FSUF[] = \
+{ \
+ { "0xy", 0.0 ## LSUF, 1 }, \
+ { "0x.y", 0.0 ## LSUF, 1 }, \
+ { "0x0.y", 0.0 ## LSUF, 4 }, \
+ { "0x.0y", 0.0 ## LSUF, 4 }, \
+ { ".y", 0.0 ## LSUF, 0 }, \
+ { "0.y", 0.0 ## LSUF, 2 }, \
+ { ".0y", 0.0 ## LSUF, 2 } \
+}; \
+ \
+static int \
+test_strto ## FSUF (void) \
+{ \
+ int status = 0; \
+ for (size_t i = 0; \
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
+ ++i) \
+ { \
+ char *ep; \
+ FTYPE r = strto ## FSUF (tests_strto ## FSUF[i].str, &ep); \
+ if (r != tests_strto ## FSUF[i].result) \
+ { \
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
+ FTOSTR (buf2, sizeof (buf2), "%g", tests_strto ## FSUF[i].result); \
+ printf ("test %zu r = %s, expect %s\n", i, buf1, buf2); \
+ status = 1; \
+ } \
+ if (ep != tests_strto ## FSUF[i].str + tests_strto ## FSUF[i].offset) \
+ { \
+ printf ("test %zu strto" #FSUF \
+ " parsed %tu characters, expected %zu\n", \
+ i, ep - tests_strto ## FSUF[i].str, \
+ tests_strto ## FSUF[i].offset); \
+ status = 1; \
+ } \
+ } \
+ return status; \
+}
+
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
static int
do_test (void)
{
- int status = 0;
- for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
- {
- char *ep;
- double r = strtod (tests[i].str, &ep);
- if (r != tests[i].result)
- {
- printf ("test %zu r = %g, expect %g\n", i, r, tests[i].result);
- status = 1;
- }
- if (ep != tests[i].str + tests[i].offset)
- {
- printf ("test %zu strtod parsed %tu characters, expected %zu\n",
- i, ep - tests[i].str, tests[i].offset);
- status = 1;
- }
- }
- return status;
+ return STRTOD_TEST_FOREACH (test_strto);
}
#define TEST_FUNCTION do_test ()
diff --git a/stdlib/tst-strtod5.c b/stdlib/tst-strtod5.c
index be091ec1b9f87394..005b3480a76955da 100644
--- a/stdlib/tst-strtod5.c
+++ b/stdlib/tst-strtod5.c
@@ -22,35 +22,75 @@
#include <string.h>
#include <math.h>
+#include "tst-strtod.h"
+
#define NBSP "\xc2\xa0"
-static const struct
-{
- const char *in;
- double expected;
-} tests[] =
- {
- { "0", 0.0 },
- { "000", 0.0 },
- { "-0", -0.0 },
- { "-000", -0.0 },
- { "0,", 0.0 },
- { "-0,", -0.0 },
- { "0,0", 0.0 },
- { "-0,0", -0.0 },
- { "0e-10", 0.0 },
- { "-0e-10", -0.0 },
- { "0,e-10", 0.0 },
- { "-0,e-10", -0.0 },
- { "0,0e-10", 0.0 },
- { "-0,0e-10", -0.0 },
- { "0e-1000000", 0.0 },
- { "-0e-1000000", -0.0 },
- { "0,0e-1000000", 0.0 },
- { "-0,0e-1000000", -0.0 },
- };
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
+static const struct \
+{ \
+ const char *in; \
+ FTYPE expected; \
+} tests_strto ## FSUF[] = \
+ { \
+ { "0", 0.0 ## LSUF }, \
+ { "000", 0.0 ## LSUF }, \
+ { "-0", -0.0 ## LSUF }, \
+ { "-000", -0.0 ## LSUF }, \
+ { "0,", 0.0 ## LSUF }, \
+ { "-0,", -0.0 ## LSUF }, \
+ { "0,0", 0.0 ## LSUF }, \
+ { "-0,0", -0.0 ## LSUF }, \
+ { "0e-10", 0.0 ## LSUF }, \
+ { "-0e-10", -0.0 ## LSUF }, \
+ { "0,e-10", 0.0 ## LSUF }, \
+ { "-0,e-10", -0.0 ## LSUF }, \
+ { "0,0e-10", 0.0 ## LSUF }, \
+ { "-0,0e-10", -0.0 ## LSUF }, \
+ { "0e-1000000", 0.0 ## LSUF }, \
+ { "-0e-1000000", -0.0 ## LSUF }, \
+ { "0,0e-1000000", 0.0 ## LSUF }, \
+ { "-0,0e-1000000", -0.0 ## LSUF }, \
+ }; \
+ \
+ \
+static int \
+test_strto ## FSUF (void) \
+{ \
+ int status = 0; \
+ \
+ for (int i = 0; \
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
+ ++i) \
+ { \
+ char *ep; \
+ FTYPE r = strto ## FSUF (tests_strto ## FSUF[i].in, &ep); \
+ \
+ if (*ep != '\0') \
+ { \
+ printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep); \
+ status = 1; \
+ } \
+ \
+ if (r != tests_strto ## FSUF[i].expected \
+ || (copysign ## CSUF (10.0 ## LSUF, r) \
+ != copysign ## CSUF (10.0 ## LSUF, \
+ tests_strto ## FSUF[i].expected))) \
+ { \
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
+ FTOSTR (buf2, sizeof (buf2), "%g", \
+ tests_strto ## FSUF[i].expected); \
+ printf ("%d: got wrong results %s, expected %s\n", \
+ i, buf1, buf2); \
+ status = 1; \
+ } \
+ } \
+ \
+ return status; \
+}
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
static int
do_test (void)
@@ -61,29 +101,7 @@ do_test (void)
return 1;
}
- int status = 0;
-
- for (int i = 0; i < NTESTS; ++i)
- {
- char *ep;
- double r = strtod (tests[i].in, &ep);
-
- if (*ep != '\0')
- {
- printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep);
- status = 1;
- }
-
- if (r != tests[i].expected
- || copysign (10.0, r) != copysign (10.0, tests[i].expected))
- {
- printf ("%d: got wrong results %g, expected %g\n",
- i, r, tests[i].expected);
- status = 1;
- }
- }
-
- return status;
+ return STRTOD_TEST_FOREACH (test_strto);
}
#include <support/test-driver.c>

View File

@ -0,0 +1,79 @@
commit b5d3737b305525315e0c7c93ca49eadc868eabd5
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Sep 20 23:24:02 2024 +0000
Add more tests of strtod end pointer
Although there are some tests in tst-strtod2 and tst-strtod3 for the
end pointer provided by strtod when it doesn't parse the whole string,
they aren't very thorough. Add tests of more such cases to
tst-strtod2.
Tested for x86_64.
diff --git a/stdlib/tst-strtod2.c b/stdlib/tst-strtod2.c
index 2cb0953fa911efd0..c84bd792c1a3f511 100644
--- a/stdlib/tst-strtod2.c
+++ b/stdlib/tst-strtod2.c
@@ -1,3 +1,4 @@
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@@ -17,10 +18,46 @@ struct test_strto ## FSUF \
{ "0x.0y", 0.0 ## LSUF, 4 }, \
{ ".y", 0.0 ## LSUF, 0 }, \
{ "0.y", 0.0 ## LSUF, 2 }, \
- { ".0y", 0.0 ## LSUF, 2 } \
+ { ".0y", 0.0 ## LSUF, 2 }, \
+ { "1.0e", 1.0 ## LSUF, 3 }, \
+ { "1.0e+", 1.0 ## LSUF, 3 }, \
+ { "1.0e-", 1.0 ## LSUF, 3 }, \
+ { "1.0ex", 1.0 ## LSUF, 3 }, \
+ { "1.0e+x", 1.0 ## LSUF, 3 }, \
+ { "1.0e-x", 1.0 ## LSUF, 3 }, \
+ { "0x1p", 1.0 ## LSUF, 3 }, \
+ { "0x1p+", 1.0 ## LSUF, 3 }, \
+ { "0x1p-", 1.0 ## LSUF, 3 }, \
+ { "0x1px", 1.0 ## LSUF, 3 }, \
+ { "0x1p+x", 1.0 ## LSUF, 3 }, \
+ { "0x1p-x", 1.0 ## LSUF, 3 }, \
+ { "INFx", INFINITY, 3 }, \
+ { "infx", INFINITY, 3 }, \
+ { "INFINITx", INFINITY, 3 }, \
+ { "infinitx", INFINITY, 3 }, \
+ { "INFINITYY", INFINITY, 8 }, \
+ { "infinityy", INFINITY, 8 }, \
+ { "NANx", NAN, 3 }, \
+ { "nanx", NAN, 3 }, \
+ { "NAN(", NAN, 3 }, \
+ { "nan(", NAN, 3 }, \
+ { "NAN(x", NAN, 3 }, \
+ { "nan(x", NAN, 3 }, \
+ { "NAN(x)y", NAN, 6 }, \
+ { "nan(x)y", NAN, 6 }, \
+ { "NAN(*)y", NAN, 3 }, \
+ { "nan(*)y", NAN, 3 } \
}; \
\
static int \
+compare_strto ## FSUF (FTYPE x, FTYPE y) \
+{ \
+ if (isnan (x) && isnan (y)) \
+ return 1; \
+ return x == y; \
+} \
+ \
+static int \
test_strto ## FSUF (void) \
{ \
int status = 0; \
@@ -30,7 +67,7 @@ test_strto ## FSUF (void) \
{ \
char *ep; \
FTYPE r = strto ## FSUF (tests_strto ## FSUF[i].str, &ep); \
- if (r != tests_strto ## FSUF[i].result) \
+ if (!compare_strto ## FSUF (r, tests_strto ## FSUF[i].result)) \
{ \
char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
FTOSTR (buf1, sizeof (buf1), "%g", r); \

View File

@ -0,0 +1,58 @@
commit dcad78507433a9a64b8b548b19e110933f8d939a
Author: DJ Delorie <dj@redhat.com>
Date: Thu Oct 10 17:16:35 2024 -0400
manual: Document stdio.h functions that may be macros
Glibc has two gnu-extension functions that are implemented as
macros but not documented as such: fread_unlocked and
fwrite_unlocked. Document them as such.
Additionally, putc_unlocked and getc_unlocked are documented in
POSIX as possibly being macros. Update the manual to add a warning
about those also, depite glibc not implementing them as macros.
diff --git a/manual/stdio.texi b/manual/stdio.texi
index 98da13de32f49c7c..01fa2d0ffdbd6f5f 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -929,6 +929,9 @@ Therefore, @var{stream} should never be an expression with side-effects.
@safety{@prelim{}@mtsafe{@mtsrace{:stream}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
The @code{putc_unlocked} function is equivalent to the @code{putc}
function except that it does not implicitly lock the stream.
+Like @code{putc}, it may be implemented as a macro and may evaluate
+the @var{stream} argument more than once. Therefore, @var{stream}
+should not be an expression with side-effects.
@end deftypefun
@deftypefun wint_t putwc_unlocked (wchar_t @var{wc}, FILE *@var{stream})
@@ -1132,6 +1135,9 @@ Therefore, @var{stream} should never be an expression with side-effects.
@safety{@prelim{}@mtsafe{@mtsrace{:stream}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
The @code{getc_unlocked} function is equivalent to the @code{getc}
function except that it does not implicitly lock the stream.
+Like @code{getc}, it may be implemented as a macro and may evaluate
+the @var{stream} argument more than once. Therefore, @var{stream}
+should not be an expression with side-effects.
@end deftypefun
@deftypefun wint_t getwc_unlocked (FILE *@var{stream})
@@ -1571,6 +1577,9 @@ The @code{fread_unlocked} function is equivalent to the @code{fread}
function except that it does not implicitly lock the stream.
This function is a GNU extension.
+This function may be implemented as a macro and may evaluate
+@var{stream} more than once. Therefore, @var{stream} should not be an
+expression with side-effects.
@end deftypefun
@deftypefun size_t fwrite (const void *@var{data}, size_t @var{size}, size_t @var{count}, FILE *@var{stream})
@@ -1589,6 +1598,9 @@ The @code{fwrite_unlocked} function is equivalent to the @code{fwrite}
function except that it does not implicitly lock the stream.
This function is a GNU extension.
+This function may be implemented as a macro and may evaluate
+@var{stream} more than once. Therefore, @var{stream} should not be an
+expression with side-effects.
@end deftypefun
@node Formatted Output

View File

@ -0,0 +1,76 @@
commit ca6466e8be32369a658035d69542d47603e58a99
Author: Andreas Schwab <schwab@suse.de>
Date: Mon Aug 29 15:05:40 2022 +0200
Add test for bug 29530
This tests for a bug that was introduced in commit edc1686af0 ("vfprintf:
Reuse work_buffer in group_number") and fixed as a side effect of commit
6caddd34bd ("Remove most vfprintf width/precision-dependent allocations
(bug 14231, bug 26211).").
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 826823a68dd36a8a..e3939b112ca2037f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -221,6 +221,7 @@ tests := \
tst-getline-enomem \
tst-gets \
tst-grouping \
+ tst-grouping2 \
tst-long-dbl-fphex \
tst-obprintf \
tst-perror \
@@ -369,6 +370,7 @@ $(objpfx)bug14.out: $(gen-locales)
$(objpfx)scanf13.out: $(gen-locales)
$(objpfx)test-vfprintf.out: $(gen-locales)
$(objpfx)tst-grouping.out: $(gen-locales)
+$(objpfx)tst-grouping2.out: $(gen-locales)
$(objpfx)tst-sprintf.out: $(gen-locales)
$(objpfx)tst-sscanf.out: $(gen-locales)
$(objpfx)tst-swprintf.out: $(gen-locales)
diff --git a/stdio-common/tst-grouping2.c b/stdio-common/tst-grouping2.c
new file mode 100644
index 0000000000000000..3024c942a60e51bf
--- /dev/null
+++ b/stdio-common/tst-grouping2.c
@@ -0,0 +1,39 @@
+/* Test printf with grouping and large width (bug 29530)
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+do_test (void)
+{
+ const int field_width = 1000;
+ char buf[field_width + 1];
+
+ xsetlocale (LC_NUMERIC, "de_DE.UTF-8");
+
+ /* This used to crash in group_number. */
+ TEST_COMPARE (sprintf (buf, "%'*d", field_width, 1000), field_width);
+ TEST_COMPARE_STRING (buf + field_width - 6, " 1.000");
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,183 @@
Backport of the test case from this commit:
commit 0d50f477f47ba637b54fb03ac48d769ec4543e8d
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jan 25 08:01:00 2023 +0100
stdio-common: Handle -1 buffer size in __sprintf_chk & co (bug 30039)
This shows up as an assertion failure when sprintf is called with
a specifier like "%.8g" and libquadmath is linked in:
Fatal glibc error: printf_buffer_as_file.c:31
(__printf_buffer_as_file_commit): assertion failed:
file->stream._IO_write_ptr <= file->next->write_end
Fix this by detecting pointer wraparound in __vsprintf_internal
and saturate the addition to the end of the address space instead.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
debug/Makefile
(missing time64 tests downstream)
include/printf_buffer.h
libio/iovsprintf.c
(not included in test-only backport)
diff --git a/debug/Makefile b/debug/Makefile
index ddae3817aef9afad..563e6249121e8bc9 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -187,6 +187,10 @@ LDFLAGS-tst-backtrace6 = -rdynamic
CFLAGS-tst-ssp-1.c += -fstack-protector-all
+# Disable compiler optimizations around vsprintf (the function under test).
+CFLAGS-tst-sprintf-fortify-unchecked.c = \
+ -fno-builtin-vsprintf -fno-builtin-__vsprintf_chk
+
tests = backtrace-tst \
tst-longjmp_chk \
test-strcpy_chk \
@@ -199,6 +203,7 @@ tests = backtrace-tst \
tst-backtrace5 \
tst-backtrace6 \
tst-realpath-chk \
+ tst-sprintf-fortify-unchecked \
$(tests-all-chk) \
ifeq ($(have-ssp),yes)
diff --git a/debug/tst-sprintf-fortify-unchecked.c b/debug/tst-sprintf-fortify-unchecked.c
new file mode 100644
index 0000000000000000..7c7bd1b5e4fe12e8
--- /dev/null
+++ b/debug/tst-sprintf-fortify-unchecked.c
@@ -0,0 +1,126 @@
+/* Tests for fortified sprintf with unknown buffer bounds (bug 30039).
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <printf.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+
+/* This test is not built with _FORTIFY_SOURCE. Instead it calls the
+ appropriate implementation directly. The fortify mode is specified
+ in this variable. */
+static int fortify_mode;
+
+/* This does not handle long-double redirects etc., but we test only
+ format strings that stay within the confines of the base
+ implementation. */
+int __vsprintf_chk (char *s, int flag, size_t slen, const char *format,
+ va_list ap);
+
+/* Invoke vsprintf or __vsprintf_chk according to fortify_mode. */
+static int
+my_vsprintf (char *buf, const char *format, va_list ap)
+{
+ int result;
+ if (fortify_mode == 0)
+ result = vsprintf (buf, format, ap);
+ else
+ /* Call the fortified version with an unspecified length. */
+ result = __vsprintf_chk (buf, fortify_mode - 1, -1, format, ap);
+ return result;
+}
+
+/* Run one test, with the specified expected output. */
+static void __attribute ((format (printf, 2, 3)))
+do_check (const char *expected, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+
+ char buf_expected[24];
+ memset (buf_expected, '@', sizeof (buf_expected));
+ TEST_VERIFY (strlen (expected) < sizeof (buf_expected));
+ strcpy (buf_expected, expected);
+
+ char buf[sizeof (buf_expected)];
+ memset (buf, '@', sizeof (buf));
+
+ int ret = my_vsprintf (buf, format, ap);
+ TEST_COMPARE_BLOB (buf_expected, sizeof (buf_expected), buf, sizeof (buf));
+ TEST_COMPARE (ret, strlen (expected));
+
+ va_end (ap);
+}
+
+/* Run the tests in all fortify modes. */
+static void
+do_tests (void)
+{
+ for (fortify_mode = 0; fortify_mode <= 3; ++fortify_mode)
+ {
+ do_check ("0", "%d", 0);
+ do_check ("-2147483648", "%d", -2147483647 - 1);
+ do_check ("-9223372036854775808", "%lld", -9223372036854775807LL - 1);
+ do_check ("", "%s", "");
+ do_check (" ", "%22s", "");
+ do_check ("XXXXXXXXXXXXXXXXXXXXXX", "%s", "XXXXXXXXXXXXXXXXXXXXXX");
+ do_check ("1.125000", "%f", 1.125);
+ do_check ("1.125", "%g", 1.125);
+ do_check ("1.125", "%.8g", 1.125);
+ }
+}
+
+/* printf callback that falls back to the glibc-supplied
+ implementation. */
+static int
+dummy_printf_function (FILE *__stream,
+ const struct printf_info *__info,
+ const void *const *__args)
+{
+ return -2; /* Request fallback. */
+}
+
+/* Likewise for the type information. */
+static int
+dummy_arginfo_function (const struct printf_info *info,
+ size_t n, int *argtypes, int *size)
+{
+ return -1; /* Request fallback. */
+}
+
+static int
+do_test (void)
+{
+ do_tests ();
+
+ /* Activate __printf_function_invoke mode. */
+ register_printf_specifier ('d', dummy_printf_function,
+ dummy_arginfo_function);
+ register_printf_specifier ('g', dummy_printf_function,
+ dummy_arginfo_function);
+ register_printf_specifier ('s', dummy_printf_function,
+ dummy_arginfo_function);
+
+ /* Rerun the tests with callback functions. */
+ do_tests ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,102 @@
Backport of the test case from the upstream commit. Note
that the test fails in the version included here.
commit c980549cc6a1c03c23cc2fe3e7b0fe626a0364b0
Author: Carlos O'Donell <carlos@redhat.com>
Date: Thu Jan 19 12:50:20 2023 +0100
Account for grouping in printf width (bug 30068)
This is a partial fix for mishandling of grouping when formatting
integers. It properly computes the width in the presence of grouping
characters when the width is larger than the number of significant
digits. The precision related issue is documented in bug 23432.
Co-authored-by: Andreas Schwab <schwab@suse.de>
Conflicts:
stdio-common/Makefile
(missing tests downstream)
stdio-common/vfprintf-process-arg.c
(not included in backport)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index e3939b112ca2037f..74e0edff73a9e468 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -222,6 +222,7 @@ tests := \
tst-gets \
tst-grouping \
tst-grouping2 \
+ tst-grouping3 \
tst-long-dbl-fphex \
tst-obprintf \
tst-perror \
@@ -375,6 +376,7 @@ $(objpfx)tst-sprintf.out: $(gen-locales)
$(objpfx)tst-sscanf.out: $(gen-locales)
$(objpfx)tst-swprintf.out: $(gen-locales)
$(objpfx)tst-vfprintf-mbs-prec.out: $(gen-locales)
+$(objpfx)tst-grouping3.out: $(gen-locales)
endif
tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
diff --git a/stdio-common/tst-grouping3.c b/stdio-common/tst-grouping3.c
new file mode 100644
index 0000000000000000..e9e39218e25a2720
--- /dev/null
+++ b/stdio-common/tst-grouping3.c
@@ -0,0 +1,54 @@
+/* Test printf with grouping and padding (bug 30068)
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <locale.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+do_test (void)
+{
+ char buf[80];
+
+ xsetlocale (LC_NUMERIC, "de_DE.UTF-8");
+
+ /* The format string has the following conversion specifier:
+ ' - Use thousands grouping.
+ + - The result of a signed conversion shall begin with a sign.
+ - - Left justified.
+ 13 - Minimum 13 bytes of width.
+ 9 - Minimum 9 digits of precision.
+
+ In bug 30068 the grouping characters were not accounted for in
+ the width, and were added after the fact resulting in a 15-byte
+ output instead of a 13-byte output. The two additional bytes
+ come from the locale-specific thousands separator. This increase
+ in size could result in a buffer overflow if a reasonable caller
+ calculated the size of the expected buffer using nl_langinfo to
+ determine the sie of THOUSEP in bytes.
+
+ This bug is distinct from bug 23432 which has to do with the
+ minimum precision calculation (digit based). */
+ sprintf (buf, "%+-'13.9d", 1234567);
+ TEST_COMPARE_STRING (buf, "+001.234.567 ");
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,17 @@
Adjust the test expectation for stdio-common/tst-grouping3 to match
the state of the RHEL 9 printf implementation, which does not add
zero padding when grouping integers.
diff --git a/stdio-common/tst-grouping3.c b/stdio-common/tst-grouping3.c
index e9e39218e25a2720..5a247cfe3fb8564f 100644
--- a/stdio-common/tst-grouping3.c
+++ b/stdio-common/tst-grouping3.c
@@ -46,7 +46,7 @@ do_test (void)
This bug is distinct from bug 23432 which has to do with the
minimum precision calculation (digit based). */
sprintf (buf, "%+-'13.9d", 1234567);
- TEST_COMPARE_STRING (buf, "+001.234.567 ");
+ TEST_COMPARE_STRING (buf, "+1.234.567 ");
return 0;
}

View File

@ -0,0 +1,120 @@
commit be7a5468d4f694ee8d052b537141f51af43ca7f2
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Tue Oct 3 15:09:36 2023 -0300
debug: Add regression tests for BZ 30932
Checked on x86_64-linux-gnu.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflicts:
debug/Makefile (fixup context)
diff --git a/debug/Makefile b/debug/Makefile
index 563e6249121e8bc9..ab49346698116fc6 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -110,6 +110,7 @@ CPPFLAGS-tst-longjmp_chk2.c += -D_FORTIFY_SOURCE=1
CFLAGS-tst-longjmp_chk3.c += -fexceptions -fasynchronous-unwind-tables
CPPFLAGS-tst-longjmp_chk3.c += -D_FORTIFY_SOURCE=1
CPPFLAGS-tst-realpath-chk.c += -D_FORTIFY_SOURCE=2
+CFLAGS-tst-sprintf-fortify-rdonly.c += -D_FORTIFY_SOURCE=2
# _FORTIFY_SOURCE tests.
# Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
@@ -203,6 +204,7 @@ tests = backtrace-tst \
tst-backtrace5 \
tst-backtrace6 \
tst-realpath-chk \
+ tst-sprintf-fortify-rdonly \
tst-sprintf-fortify-unchecked \
$(tests-all-chk) \
diff --git a/debug/tst-sprintf-fortify-rdonly.c b/debug/tst-sprintf-fortify-rdonly.c
new file mode 100644
index 0000000000000000..78dece9102d7dfd3
--- /dev/null
+++ b/debug/tst-sprintf-fortify-rdonly.c
@@ -0,0 +1,82 @@
+/* Testcase for BZ 30932.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+
+jmp_buf chk_fail_buf;
+bool chk_fail_ok;
+
+const char *str2 = "F";
+char buf2[10] = "%s";
+
+static int
+do_test (void)
+{
+ struct rlimit rl;
+ int max_fd = 24;
+
+ if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+
+ max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
+ rl.rlim_cur = max_fd;
+
+ if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+
+ /* Exhaust the file descriptor limit with temporary files. */
+ int nfiles = 0;
+ for (; nfiles < max_fd; nfiles++)
+ {
+ int fd = create_temp_file ("tst-sprintf-fortify-rdonly-.", NULL);
+ if (fd == -1)
+ {
+ if (errno != EMFILE)
+ FAIL_EXIT1 ("create_temp_file: %m");
+ break;
+ }
+ }
+ TEST_VERIFY_EXIT (nfiles != 0);
+
+ /* When the format string is writable and contains %n,
+ with -D_FORTIFY_SOURCE=2 it causes __chk_fail. However, if libc can not
+ open procfs to check if the input format string in within a writable
+ memory segment, the fortify version can not perform the check. */
+ char buf[128];
+ int n1;
+ int n2;
+
+ strcpy (buf2 + 2, "%n%s%n");
+ if (sprintf (buf, buf2, str2, &n1, str2, &n2) != 2
+ || n1 != 1 || n2 != 2)
+ FAIL_EXIT1 ("sprintf failed: %s %d %d", buf, n1, n2);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,111 @@
This reverts glibc-RHEL-46761-5.patch, thus dropping the associated test
case.
diff --git a/debug/Makefile b/debug/Makefile
index cb93ed80da57f2cc..563e6249121e8bc9 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -110,7 +110,6 @@ CPPFLAGS-tst-longjmp_chk2.c += -D_FORTIFY_SOURCE=1
CFLAGS-tst-longjmp_chk3.c += -fexceptions -fasynchronous-unwind-tables
CPPFLAGS-tst-longjmp_chk3.c += -D_FORTIFY_SOURCE=1
CPPFLAGS-tst-realpath-chk.c += -D_FORTIFY_SOURCE=2
-CFLAGS-tst-sprintf-fortify-rdonly.c += -D_FORTIFY_SOURCE=2
# _FORTIFY_SOURCE tests.
# Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
@@ -204,7 +203,6 @@ tests = backtrace-tst \
tst-backtrace5 \
tst-backtrace6 \
tst-realpath-chk \
- tst-sprintf-fortify-rdonly \
tst-sprintf-fortify-unchecked \
$(tests-all-chk) \
diff --git a/debug/tst-sprintf-fortify-rdonly.c b/debug/tst-sprintf-fortify-rdonly.c
deleted file mode 100644
index 78dece9102d7dfd3..0000000000000000
--- a/debug/tst-sprintf-fortify-rdonly.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Testcase for BZ 30932.
- Copyright (C) 2023 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- 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.
-
- The GNU C Library 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 the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-#include <errno.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <unistd.h>
-
-#include <support/check.h>
-#include <support/support.h>
-#include <support/temp_file.h>
-
-jmp_buf chk_fail_buf;
-bool chk_fail_ok;
-
-const char *str2 = "F";
-char buf2[10] = "%s";
-
-static int
-do_test (void)
-{
- struct rlimit rl;
- int max_fd = 24;
-
- if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
- FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
-
- max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
- rl.rlim_cur = max_fd;
-
- if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
- FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
-
- /* Exhaust the file descriptor limit with temporary files. */
- int nfiles = 0;
- for (; nfiles < max_fd; nfiles++)
- {
- int fd = create_temp_file ("tst-sprintf-fortify-rdonly-.", NULL);
- if (fd == -1)
- {
- if (errno != EMFILE)
- FAIL_EXIT1 ("create_temp_file: %m");
- break;
- }
- }
- TEST_VERIFY_EXIT (nfiles != 0);
-
- /* When the format string is writable and contains %n,
- with -D_FORTIFY_SOURCE=2 it causes __chk_fail. However, if libc can not
- open procfs to check if the input format string in within a writable
- memory segment, the fortify version can not perform the check. */
- char buf[128];
- int n1;
- int n2;
-
- strcpy (buf2 + 2, "%n%s%n");
- if (sprintf (buf, buf2, str2, &n1, str2, &n2) != 2
- || n1 != 1 || n2 != 2)
- FAIL_EXIT1 ("sprintf failed: %s %d %d", buf, n1, n2);
-
- return 0;
-}
-
-#include <support/test-driver.c>

View File

@ -0,0 +1,146 @@
commit b7d4de086ce7fcc531cdd67a61dc27b5b3eff482
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Aug 5 16:01:12 2024 +0200
manual: Describe struct link_map, support link maps with dlinfo
This does not describe how to use RTLD_DI_ORIGIN and l_name
to reconstruct a full path for the an object. The reason
is that I think we should not recommend further use of
RTLD_DI_ORIGIN due to its buffer overflow potential (bug 24298).
This should be covered by another dlinfo extension. It would
also obsolete the need for the dladdr approach to obtain
the file name for the main executable.
Obtaining the lowest address from load segments in program
headers is quite clumsy and should be provided directly
via dlinfo.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
index 39d0a4c4b908e87b..d59dca2b7a916889 100644
--- a/manual/dynlink.texi
+++ b/manual/dynlink.texi
@@ -351,16 +351,119 @@ support the XGETBV instruction.
@node Dynamic Linker Introspection
@section Dynamic Linker Introspection
-@Theglibc{} provides various functions for querying information from the
+@Theglibc{} provides various facilities for querying information from the
dynamic linker.
+@deftp {Data Type} {struct link_map}
+
+@cindex link map
+A @dfn{link map} is associated with the main executable and each shared
+object. Some fields of the link map are accessible to applications and
+exposed through the @code{struct link_map}. Applications must not modify
+the link map directly.
+
+Pointers to link maps can be obtained from the @code{_r_debug} variable,
+from the @code{RTLD_DI_LINKMAP} request for @code{dlinfo}, and from the
+@code{_dl_find_object} function. See below for details.
+
+@table @code
+@item l_addr
+@cindex load address
+This field contains the @dfn{load address} of the object. This is the
+offset that needs to be applied to unrelocated addresses in the object
+image (as stored on disk) to form an address that can be used at run
+time for accessing data or running code. For position-dependent
+executables, the load address is typically zero, and no adjustment is
+required. For position-independent objects, the @code{l_addr} field
+usually contains the address of the object's ELF header in the process
+image. However, this correspondence is not guaranteed because the ELF
+header might not be mapped at all, and the ELF file as stored on disk
+might use zero as the lowest virtual address. Due to the second
+variable, values of the @code{l_addr} field do not necessarily uniquely
+identify a shared object.
+
+On Linux, to obtain the lowest loaded address of the main program, use
+@code{getauxval} to obtain the @code{AT_PHDR} and @code{AT_PHNUM} values
+for the current process. Alternatively, call
+@samp{dlinfo (_r_debug.r_map, &@var{phdr})}
+to obtain the number of program headers, and the address of the program
+header array will be stored in @var{phdr}
+(of type @code{const ElfW(Phdr) *}, as explained below).
+These values allow processing the array of program headers and the
+address information in the @code{PT_LOAD} entries among them.
+This works even when the program was started with an explicit loader
+invocation.
+
+@item l_name
+For a shared object, this field contains the file name that the
+@theglibc{} dynamic loader used when opening the object. This can be
+a relative path (relative to the current directory at process start,
+or if the object was loaded later, via @code{dlopen} or
+@code{dlmopen}). Symbolic links are not necessarily resolved.
+
+For the main executable, @code{l_name} is @samp{""} (the empty string).
+(The main executable is not loaded by @theglibc{}, so its file name is
+not available.) On Linux, the main executable is available as
+@file{/proc/self/exe} (unless an explicit loader invocation was used to
+start the program). The file name @file{/proc/self/exe} continues to
+resolve to the same file even if it is moved within or deleted from the
+file system. Its current location can be read using @code{readlink}.
+@xref{Symbolic Links}. (Although @file{/proc/self/exe} is not actually
+a symbol link, it is only presented as one.) Note that @file{/proc} may
+not be mounted, in which case @file{/proc/self/exe} is not available.
+
+If an explicit loader invocation is used (such as @samp{ld.so
+/usr/bin/emacs}), the @file{/proc/self/exe} approach does not work
+because the file name refers to the dynamic linker @code{ld.so}, and not
+the @code{/usr/bin/emacs} program. An approximation to the executable
+path is still available in the @code{@var{info}.dli_fname} member after
+calling @samp{dladdr (_r_debug.r_map->l_ld, &@var{info})}. Note that
+this could be a relative path, and it is supplied by the process that
+created the current process, not the kernel, so it could be inaccurate.
+
+@item l_ld
+This is a pointer to the ELF dynamic segment, an array of tag/value
+pairs that provide various pieces of information that the dynamic
+linking process uses. On most architectures, addresses in the dynamic
+segment are relocated at run time, but on some architectures and in some
+run-time configurations, it is necessary to add the @code{l_addr} field
+value to obtain a proper address.
+
+@item l_prev
+@itemx l_next
+These fields are used to maintain a double-linked linked list of all
+link maps within one @code{dlmopen} namespace. Note that there is
+currently no thread-safe way to iterate over this list. The
+callback-based @code{dl_iterate_phdr} interface can be used instead.
+@end table
+@end deftp
+
+@strong{Portability note:} It is not possible to create a @code{struct
+link_map} object and pass a pointer to a function that expects a
+@code{struct link_map *} argument. Only link map pointers initially
+supplied by @theglibc{} are permitted as arguments. In current versions
+of @theglibc{}, handles returned by @code{dlopen} and @code{dlmopen} are
+pointers to link maps. However, this is not a portable assumption, and
+may even change in future versions of @theglibc{}. To obtain the link
+map associated with a handle, see @code{dlinfo} and
+@code{RTLD_DI_LINKMAP} below. If a function accepts both
+@code{dlopen}/@code{dlmopen} handles and @code{struct link_map} pointers
+in its @code{void *} argument, that is documented explicitly.
+
+@subsection Querying information for loaded objects
+
+The @code{dlinfo} function provides access to internal information
+associated with @code{dlopen}/@code{dlmopen} handles and link maps.
+
@deftypefun {int} dlinfo (void *@var{handle}, int @var{request}, void *@var{arg})
@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
@standards{GNU, dlfcn.h}
This function returns information about @var{handle} in the memory
location @var{arg}, based on @var{request}. The @var{handle} argument
must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must
-not have been closed by @code{dlclose}.
+not have been closed by @code{dlclose}. Alternatively, @var{handle}
+can be a @code{struct link_map *} value for a link map of an object
+that has not been closed.
On success, @code{dlinfo} returns 0 for most request types; exceptions
are noted below. If there is an error, the function returns @math{-1},

View File

@ -0,0 +1,121 @@
From 3bfdc4e2bceb601b90c81a9baa73c1904db58b2f Mon Sep 17 00:00:00 2001
From: Andreas Schwab <schwab@suse.de>
Date: Tue, 28 Feb 2023 10:37:18 -0300
Subject: [PATCH] support: use 64-bit time_t (bug 30111)
Content-type: text/plain; charset=UTF-8
Ensure to use 64-bit time_t in the test infrastructure.
---
support/Makefile | 18 ++++++++++++++++++
support/shell-container.c | 2 --
support/support_can_chroot.c | 4 ++--
support/support_copy_file.c | 2 +-
support/support_descriptor_supports_holes.c | 2 +-
support/test-container.c | 2 --
6 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/support/Makefile b/support/Makefile
index b29b7eb505..a304c5cdc0 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -239,6 +239,24 @@ CFLAGS-support_paths.c = \
CFLAGS-timespec.c += -fexcess-precision=standard
CFLAGS-timespec-time64.c += -fexcess-precision=standard
+# Ensure that general support files use 64-bit time_t
+CFLAGS-delayed_exit.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-shell-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_can_chroot.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_copy_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_copy_file_range.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_descriptor_supports_holes.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_descriptors.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_process_state.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_stat_nanoseconds.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_subprocess.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_test_main.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-test-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-xmkdirp.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+# This is required to get an mkstemp which can create large files on some
+# 32-bit platforms.
+CFLAGS-temp_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+
ifeq (,$(CXX))
LINKS_DSO_PROGRAM = links-dso-program-c
else
diff --git a/support/shell-container.c b/support/shell-container.c
index e9ac9b6d04..ffa3378b5e 100644
--- a/support/shell-container.c
+++ b/support/shell-container.c
@@ -16,8 +16,6 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#define _FILE_OFFSET_BITS 64
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
index 7d9f91205d..7b4f491b53 100644
--- a/support/support_can_chroot.c
+++ b/support/support_can_chroot.c
@@ -29,14 +29,14 @@ static void
callback (void *closure)
{
int *result = closure;
- struct stat64 before;
+ struct stat before;
xstat ("/dev", &before);
if (chroot ("/dev") != 0)
{
*result = errno;
return;
}
- struct stat64 after;
+ struct stat after;
xstat ("/", &after);
TEST_VERIFY (before.st_dev == after.st_dev);
TEST_VERIFY (before.st_ino == after.st_ino);
diff --git a/support/support_copy_file.c b/support/support_copy_file.c
index 50ff87b9f1..f3e0a2d1b7 100644
--- a/support/support_copy_file.c
+++ b/support/support_copy_file.c
@@ -24,7 +24,7 @@
void
support_copy_file (const char *from, const char *to)
{
- struct stat64 st;
+ struct stat st;
xstat (from, &st);
int fd_from = xopen (from, O_RDONLY, 0);
mode_t mode = st.st_mode & 0777;
diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c
index 7af5934808..91db216bf0 100644
--- a/support/support_descriptor_supports_holes.c
+++ b/support/support_descriptor_supports_holes.c
@@ -40,7 +40,7 @@ support_descriptor_supports_holes (int fd)
block_headroom = 32,
};
- struct stat64 st;
+ struct stat st;
xfstat (fd, &st);
if (!S_ISREG (st.st_mode))
FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd);
diff --git a/support/test-container.c b/support/test-container.c
index f1a68b224a..e68f16eecf 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -16,8 +16,6 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#define _FILE_OFFSET_BITS 64
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
--
2.43.5

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,501 @@
From e3db0a699c639e97deddcb15939fd9c162801c77 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Sat, 21 Sep 2024 19:25:35 +0200
Subject: [PATCH] misc: FUSE-based tests for mkstemp
Content-type: text/plain; charset=UTF-8
The tests check that O_EXCL is used properly, that 0600 is used
as the mode, that the characters used are as expected, and that
the distribution of names generated is reasonably random.
The tests run very slowly on some kernel versions, so make them
xtests.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts
misc/Makefile
context
---
misc/Makefile | 6 +
misc/tst-mkstemp-fuse-parallel.c | 219 +++++++++++++++++++++++++++++++
misc/tst-mkstemp-fuse.c | 197 +++++++++++++++++++++++++++
3 files changed, 422 insertions(+)
create mode 100644 misc/tst-mkstemp-fuse-parallel.c
create mode 100644 misc/tst-mkstemp-fuse.c
diff --git a/misc/Makefile b/misc/Makefile
index 7b7f8351bf..1422c95317 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -109,6 +109,12 @@ tests-static := tst-empty
tests-internal += tst-fd_to_filename
tests-static += tst-fd_to_filename
+# Tests with long run times.
+xtests += \
+ tst-mkstemp-fuse \
+ tst-mkstemp-fuse-parallel \
+ # xtests
+
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-error1-mem.out \
$(objpfx)tst-allocate_once-mem.out
diff --git a/misc/tst-mkstemp-fuse-parallel.c b/misc/tst-mkstemp-fuse-parallel.c
new file mode 100644
index 0000000000..219f26cb3b
--- /dev/null
+++ b/misc/tst-mkstemp-fuse-parallel.c
@@ -0,0 +1,246 @@
+/* FUSE-based test for mkstemp. Parallel collision statistics.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+#include <array_length.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/fuse.h>
+#include <support/support.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+
+/* The number of subprocesses that call mkstemp. */
+static pid_t processes[4];
+
+/* Enough space to record the expected number of replies (62**3) for
+ each process. */
+enum { results_allocated = array_length (processes) * 62 * 62 * 62 };
+
+/* The thread will store the results there. */
+static uint64_t *results;
+
+/* Currently used part of the results array. */
+static size_t results_used;
+
+
+/* Copied from upstream's string/strlcpy.c . */
+static size_t
+strlcpy (char *__restrict dest, const char *__restrict src, size_t size)
+{
+ size_t src_length = strlen (src);
+
+ if (__glibc_unlikely (src_length >= size))
+ {
+ if (size > 0)
+ {
+ /* Copy the leading portion of the string. The last
+ character is subsequently overwritten with the NUL
+ terminator, but the destination size is usually a
+ multiple of a small power of two, so writing it twice
+ should be more efficient than copying an odd number of
+ bytes. */
+ memcpy (dest, src, size);
+ dest[size - 1] = '\0';
+ }
+ }
+ else
+ /* Copy the string and its terminating NUL character. */
+ memcpy (dest, src, src_length + 1);
+ return src_length;
+}
+
+/* Fail with EEXIST (so that mkstemp tries again). Record observed
+ names for later statistical analysis. */
+static void
+fuse_thread (struct support_fuse *f, void *closure)
+{
+ struct fuse_in_header *inh;
+ while ((inh = support_fuse_next (f)) != NULL)
+ {
+ if (support_fuse_handle_mountpoint (f)
+ || (inh->nodeid == 1 && support_fuse_handle_directory (f)))
+ continue;
+ if (inh->opcode != FUSE_LOOKUP || results_used >= results_allocated)
+ {
+ support_fuse_reply_error (f, EIO);
+ continue;
+ }
+
+ char *name = support_fuse_cast (LOOKUP, inh);
+ TEST_COMPARE_BLOB (name, 3, "new", 3);
+ TEST_COMPARE (strlen (name), 9);
+ /* Extract 8 bytes of the name: 'w', the X replacements, and the
+ null terminator. Treat it as an uint64_t for easy sorting
+ below. Endianess does not matter because the relative order
+ of the entries is not important; sorting is only used to find
+ duplicates. */
+ TEST_VERIFY_EXIT (results_used < results_allocated);
+ memcpy (&results[results_used], name + 2, 8);
+ ++results_used;
+ struct fuse_entry_out *out = support_fuse_prepare_entry (f, 2);
+ out->attr.mode = S_IFREG | 0600;
+ support_fuse_reply_prepared (f);
+ }
+}
+
+/* Used to sort the results array, to find duplicates. */
+static int
+results_sort (const void *a1, const void *b1)
+{
+ const uint64_t *a = a1;
+ const uint64_t *b = b1;
+ if (*a < *b)
+ return -1;
+ if (*a == *b)
+ return 0;
+ return 1;
+}
+
+/* Number of occurrences of certain streak lengths. */
+static size_t streak_lengths[6];
+
+/* Called for every encountered streak. */
+static inline void
+report_streak (uint64_t current, size_t length)
+{
+ if (length > 1)
+ {
+ printf ("info: name \"ne%.8s\" repeats: %zu\n",
+ (char *) &current, length);
+ TEST_VERIFY_EXIT (length < array_length (streak_lengths));
+ }
+ TEST_VERIFY_EXIT (length < array_length (streak_lengths));
+ ++streak_lengths[length];
+}
+
+static int
+do_test (void)
+{
+ support_fuse_init ();
+
+ results = xmalloc (results_allocated * sizeof (*results));
+
+ struct shared
+ {
+ /* Used to synchronize the start of all subprocesses, to make it
+ more likely to expose concurrency-related bugs. */
+ pthread_barrier_t barrier1;
+ pthread_barrier_t barrier2;
+
+ /* Filled in after fork. */
+ char mountpoint[4096];
+ };
+
+ /* Used to synchronize the start of all subprocesses, to make it
+ more likely to expose concurrency-related bugs. */
+ struct shared *pshared = support_shared_allocate (sizeof (*pshared));
+ {
+ pthread_barrierattr_t attr;
+ xpthread_barrierattr_init (&attr);
+ xpthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
+ xpthread_barrierattr_destroy (&attr);
+ xpthread_barrier_init (&pshared->barrier1, &attr,
+ array_length (processes) + 1);
+ xpthread_barrier_init (&pshared->barrier2, &attr,
+ array_length (processes) + 1);
+ xpthread_barrierattr_destroy (&attr);
+ }
+
+ for (int i = 0; i < array_length (processes); ++i)
+ {
+ processes[i] = xfork ();
+ if (processes[i] == 0)
+ {
+ /* Wait for mountpoint initialization. */
+ xpthread_barrier_wait (&pshared->barrier1);
+ char *path = xasprintf ("%s/newXXXXXX", pshared->mountpoint);
+
+ /* Park this process until all processes have started. */
+ xpthread_barrier_wait (&pshared->barrier2);
+ errno = 0;
+ TEST_COMPARE (mkstemp (path), -1);
+ TEST_COMPARE (errno, EEXIST);
+ free (path);
+ _exit (0);
+ }
+ }
+
+ /* Do this after the forking, to minimize initialization inteference. */
+ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL);
+ TEST_VERIFY (strlcpy (pshared->mountpoint, support_fuse_mountpoint (f),
+ sizeof (pshared->mountpoint))
+ < sizeof (pshared->mountpoint));
+ xpthread_barrier_wait (&pshared->barrier1);
+
+ puts ("info: performing mkstemp calls");
+ xpthread_barrier_wait (&pshared->barrier2);
+
+ for (int i = 0; i < array_length (processes); ++i)
+ {
+ int status;
+ xwaitpid (processes[i], &status, 0);
+ TEST_COMPARE (status, 0);
+ }
+
+ support_fuse_unmount (f);
+ xpthread_barrier_destroy (&pshared->barrier2);
+ xpthread_barrier_destroy (&pshared->barrier1);
+
+ printf ("info: checking results (count %zu)\n", results_used);
+ qsort (results, results_used, sizeof (*results), results_sort);
+
+ uint64_t current = -1;
+ size_t streak = 0;
+ for (size_t i = 0; i < results_used; ++i)
+ if (results[i] == current)
+ ++streak;
+ else
+ {
+ report_streak (current, streak);
+ current = results[i];
+ streak = 1;
+ }
+ report_streak (current, streak);
+
+ puts ("info: repetition count distribution:");
+ for (int i = 1; i < array_length (streak_lengths); ++i)
+ printf (" length %d: %zu\n", i, streak_lengths[i]);
+ /* Some arbitrary threshold, hopefully unlikely enough. In over
+ 260,000 runs of a simulation of this test, at most 26 pairs were
+ observed, and only one three-way collisions. */
+ if (streak_lengths[2] > 30)
+ FAIL ("unexpected repetition count 2: %zu", streak_lengths[2]);
+ if (streak_lengths[3] > 2)
+ FAIL ("unexpected repetition count 3: %zu", streak_lengths[3]);
+ for (int i = 4; i < array_length (streak_lengths); ++i)
+ if (streak_lengths[i] > 0)
+ FAIL ("too many repeats of count %d: %zu", i, streak_lengths[i]);
+
+ free (results);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-mkstemp-fuse.c b/misc/tst-mkstemp-fuse.c
new file mode 100644
index 0000000000..5ac6a6872a
--- /dev/null
+++ b/misc/tst-mkstemp-fuse.c
@@ -0,0 +1,197 @@
+/* FUSE-based test for mkstemp.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/fuse.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+/* Set to true in do_test to cause the first FUSE_CREATE attempt to fail. */
+static _Atomic bool simulate_creat_race;
+
+/* Basic tests with eventually successful creation. */
+static void
+fuse_thread_basic (struct support_fuse *f, void *closure)
+{
+ char *previous_name = NULL;
+ int state = 0;
+ struct fuse_in_header *inh;
+ while ((inh = support_fuse_next (f)) != NULL)
+ {
+ if (support_fuse_handle_mountpoint (f)
+ || (inh->nodeid == 1 && support_fuse_handle_directory (f)))
+ continue;
+
+ switch (inh->opcode)
+ {
+ case FUSE_LOOKUP:
+ /* File does not exist initially. */
+ TEST_COMPARE (inh->nodeid, 1);
+ if (simulate_creat_race)
+ {
+ if (state < 3)
+ ++state;
+ else
+ FAIL ("invalid state: %d", state);
+ }
+ else
+ {
+ TEST_COMPARE (state, 0);
+ state = 3;
+ }
+ support_fuse_reply_error (f, ENOENT);
+ break;
+ case FUSE_CREATE:
+ {
+ TEST_COMPARE (inh->nodeid, 1);
+ char *name;
+ struct fuse_create_in *p
+ = support_fuse_cast_name (CREATE, inh, &name);
+ /* Name follows after struct fuse_create_in. */
+ TEST_COMPARE (p->flags & O_ACCMODE, O_RDWR);
+ TEST_VERIFY (p->flags & O_EXCL);
+ TEST_VERIFY (p->flags & O_CREAT);
+ TEST_COMPARE (p->mode & 07777, 0600);
+ TEST_VERIFY (S_ISREG (p->mode));
+ TEST_COMPARE_BLOB (name, 3, "new", 3);
+
+ if (state != 3 && simulate_creat_race)
+ {
+ ++state;
+ support_fuse_reply_error (f, EEXIST);
+ }
+ else
+ {
+ if (previous_name != NULL)
+ /* This test has a very small probability of failure
+ due to a harmless collision (one in 62**6 tests). */
+ TEST_VERIFY (strcmp (name, previous_name) != 0);
+ TEST_COMPARE (state, 3);
+ ++state;
+ struct fuse_entry_out *entry;
+ struct fuse_open_out *open;
+ support_fuse_prepare_create (f, 2, &entry, &open);
+ entry->attr.mode = S_IFREG | 0600;
+ support_fuse_reply_prepared (f);
+ }
+ free (previous_name);
+ previous_name = xstrdup (name);
+ }
+ break;
+ case FUSE_FLUSH:
+ case FUSE_RELEASE:
+ TEST_COMPARE (state, 4);
+ TEST_COMPARE (inh->nodeid, 2);
+ support_fuse_reply_empty (f);
+ break;
+ default:
+ support_fuse_reply_error (f, EIO);
+ }
+ }
+ free (previous_name);
+}
+
+/* Reply that all files exist. */
+static void
+fuse_thread_eexist (struct support_fuse *f, void *closure)
+{
+ uint64_t counter = 0;
+ struct fuse_in_header *inh;
+ while ((inh = support_fuse_next (f)) != NULL)
+ {
+ if (support_fuse_handle_mountpoint (f)
+ || (inh->nodeid == 1 && support_fuse_handle_directory (f)))
+ continue;
+
+ switch (inh->opcode)
+ {
+ case FUSE_LOOKUP:
+ ++counter;
+ TEST_COMPARE (inh->nodeid, 1);
+ char *name = support_fuse_cast (LOOKUP, inh);
+ TEST_COMPARE_BLOB (name, 3, "new", 3);
+ TEST_COMPARE (strlen (name), 9);
+ for (int i = 3; i <= 8; ++i)
+ {
+ /* The glibc implementation uses letters and digits only. */
+ char ch = name[i];
+ TEST_VERIFY (('0' <= ch && ch <= '9')
+ || ('a' <= ch && ch <= 'z')
+ || ('A' <= ch && ch <= 'Z'));
+ }
+ struct fuse_entry_out out =
+ {
+ .nodeid = 2,
+ .attr = {
+ .mode = S_IFREG | 0600,
+ .ino = 2,
+ },
+ };
+ support_fuse_reply (f, &out, sizeof (out));
+ break;
+ default:
+ support_fuse_reply_error (f, EIO);
+ }
+ }
+ /* Verify that mkstemp has retried a lot. The current
+ implementation tries 62 * 62 * 62 times until it goves up. */
+ TEST_VERIFY (counter >= 200000);
+}
+
+static int
+do_test (void)
+{
+ support_fuse_init ();
+
+ for (int do_simulate_creat_race = 0; do_simulate_creat_race < 2;
+ ++do_simulate_creat_race)
+ {
+ simulate_creat_race = do_simulate_creat_race;
+ printf ("info: testing with simulate_creat_race == %d\n",
+ (int) simulate_creat_race);
+ struct support_fuse *f = support_fuse_mount (fuse_thread_basic, NULL);
+ char *path = xasprintf ("%s/newXXXXXX", support_fuse_mountpoint (f));
+ int fd = mkstemp (path);
+ TEST_VERIFY (fd > 2);
+ xclose (fd);
+ free (path);
+ support_fuse_unmount (f);
+ }
+
+ puts ("info: testing EEXIST failure case for mkstemp");
+ {
+ struct support_fuse *f = support_fuse_mount (fuse_thread_eexist, NULL);
+ char *path = xasprintf ("%s/newXXXXXX", support_fuse_mountpoint (f));
+ errno = 0;
+ TEST_COMPARE (mkstemp (path), -1);
+ TEST_COMPARE (errno, EEXIST);
+ free (path);
+ support_fuse_unmount (f);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--
2.43.5

View File

@ -0,0 +1,40 @@
From 455c7622835d16c79e49fe75b8d3a1ae59a3d0ee Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Sat, 21 Sep 2024 19:25:35 +0200
Subject: [PATCH] support: Fix memory leaks in FUSE tests
Content-type: text/plain; charset=UTF-8
The internal read buffer (used by all FUSE tests) was not freed.
The support/tst-support_fuse test missed a deallocation.
---
support/support_fuse.c | 1 +
support/tst-support_fuse.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/support/support_fuse.c b/support/support_fuse.c
index 135dbf1198..f6c063b549 100644
--- a/support/support_fuse.c
+++ b/support/support_fuse.c
@@ -659,6 +659,7 @@ support_fuse_unmount (struct support_fuse *f)
if (rmdir (f->mountpoint) != 0)
FAIL ("FUSE: rmdir (\"%s\"): %m", f->mountpoint);
xclose (f->fd);
+ free (f->buffer_start);
free (f->mountpoint);
free (f->readdir_buffer);
free (f);
diff --git a/support/tst-support_fuse.c b/support/tst-support_fuse.c
index c4075a6608..9ee637cbab 100644
--- a/support/tst-support_fuse.c
+++ b/support/tst-support_fuse.c
@@ -331,6 +331,7 @@ do_test (void)
{
char *subdir_path = xasprintf ("%s/subdir", support_fuse_mountpoint (f));
xmkdir (subdir_path, 01234);
+ free (subdir_path);
}
{
--
2.43.5

View File

@ -0,0 +1,32 @@
From 366cce74d2aa2e5753d8787d415b745fd57fda04 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Sat, 21 Sep 2024 19:29:13 +0200
Subject: [PATCH] support: Add valgrind instructions to <support/fuse.h>
Content-type: text/plain; charset=UTF-8
Replacing an outdated comment (namespace setup is now handled by
support_fuse_init).
---
support/fuse.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/support/fuse.h b/support/fuse.h
index 4c365fbc0c..1c862bedbe 100644
--- a/support/fuse.h
+++ b/support/fuse.h
@@ -16,8 +16,10 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-/* Before using this functionality, use support_enter_mount_namespace
- to ensure that mounts do not impact the overall system. */
+/* To run FUSE tests under valgrind, pass the
+ --sim-hints=fuse-compatible option to valgrind. This option tells
+ valgrind that additional system calls effectively call back into
+ the current program. */
#ifndef SUPPORT_FUSE_H
#define SUPPORT_FUSE_H
--
2.43.5

View File

@ -0,0 +1,24 @@
From 3ef26b708725b528a1c69ab3eb523036c50b89d6 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Tue, 24 Sep 2024 13:05:48 +0200
Subject: [PATCH] misc: Link tst-mkstemp-fuse-parallel with
$(shared-thread-library)
Content-type: text/plain; charset=UTF-8
The barrier functions require this on Hurd.
---
misc/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/misc/Makefile b/misc/Makefile
index 1422c95317..a932b1aab4 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -178,3 +178,4 @@ $(objpfx)tst-select: $(librt)
$(objpfx)tst-select-time64: $(librt)
$(objpfx)tst-pselect: $(librt)
$(objpfx)tst-pselect-time64: $(librt)
+$(objpfx)tst-mkstemp-fuse-parallel: $(shared-thread-library)
--
2.43.5

View File

@ -0,0 +1,785 @@
From 026a84a54d3b6c23b999b793e2a6f8ecd211e3b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20B=C3=A9rat?= <fberat@redhat.com>
Date: Thu, 1 Jun 2023 12:40:05 -0400
Subject: [PATCH] tests: replace write by xwrite
Content-type: text/plain; charset=UTF-8
Using write without cheks leads to warn unused result when __wur is
enabled.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
dirent/tst-fdopendir.c | 4 +++-
io/tst-faccessat.c | 3 ++-
io/tst-fchmodat.c | 3 ++-
io/tst-fchownat.c | 3 ++-
io/tst-fstatat.c | 3 ++-
io/tst-futimesat.c | 3 ++-
io/tst-linkat.c | 3 ++-
io/tst-openat.c | 3 ++-
io/tst-renameat.c | 3 ++-
io/tst-symlinkat.c | 3 ++-
io/tst-unlinkat.c | 3 ++-
libio/bug-ungetc.c | 4 +++-
libio/bug-ungetc3.c | 4 +++-
libio/bug-ungetc4.c | 4 +++-
libio/bug-wfflush.c | 4 +++-
libio/bug-wsetpos.c | 4 +++-
nptl/tst-stackguard1.c | 4 +++-
nptl/tst-tls3.c | 2 ++
nptl/tst-tls3mod.c | 5 +++--
rt/tst-cpuclock2.c | 4 +++-
rt/tst-cputimer1.c | 4 +++-
rt/tst-cputimer2.c | 4 +++-
rt/tst-cputimer3.c | 4 +++-
support/test-container.c | 8 ++++----
sysdeps/pthread/tst-cond18.c | 4 +++-
sysdeps/pthread/tst-flock1.c | 3 ++-
sysdeps/pthread/tst-flock2.c | 3 ++-
sysdeps/pthread/tst-key1.c | 11 ++++++-----
sysdeps/pthread/tst-signal1.c | 3 ++-
sysdeps/pthread/tst-signal2.c | 3 ++-
sysdeps/pthread/tst-timer.c | 3 ++-
time/tst-cpuclock1.c | 4 +++-
32 files changed, 84 insertions(+), 39 deletions(-)
diff --git a/dirent/tst-fdopendir.c b/dirent/tst-fdopendir.c
index 6321af1daa..2c9520574d 100644
--- a/dirent/tst-fdopendir.c
+++ b/dirent/tst-fdopendir.c
@@ -7,6 +7,8 @@
#include <string.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
+
#ifndef O_NOATIME
# define O_NOATIME 0
#endif
@@ -22,7 +24,7 @@ do_test (void)
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
close (fd);
struct stat64 st;
diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c
index 7bdeed008c..b90954e318 100644
--- a/io/tst-faccessat.c
+++ b/io/tst-faccessat.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -96,7 +97,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
/* Before closing the file, try using this file descriptor to open
diff --git a/io/tst-fchmodat.c b/io/tst-fchmodat.c
index 7d4a8717ff..83003e2f21 100644
--- a/io/tst-fchmodat.c
+++ b/io/tst-fchmodat.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -98,7 +99,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct stat64 st1;
diff --git a/io/tst-fchownat.c b/io/tst-fchownat.c
index e8adf6229f..c0b87cda8f 100644
--- a/io/tst-fchownat.c
+++ b/io/tst-fchownat.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -106,7 +107,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct stat64 st1;
diff --git a/io/tst-fstatat.c b/io/tst-fstatat.c
index 4766bb2e71..6a60024b63 100644
--- a/io/tst-fstatat.c
+++ b/io/tst-fstatat.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -94,7 +95,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct stat64 st1;
diff --git a/io/tst-futimesat.c b/io/tst-futimesat.c
index 3d41721f42..b7ef386e06 100644
--- a/io/tst-futimesat.c
+++ b/io/tst-futimesat.c
@@ -28,6 +28,7 @@
#include <support/test-driver.h>
#include <support/temp_file.h>
+#include <support/xunistd.h>
#ifndef struct_stat
# define struct_stat struct stat64
@@ -114,7 +115,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct_stat st1;
diff --git a/io/tst-linkat.c b/io/tst-linkat.c
index 97445b7954..6b22a01c88 100644
--- a/io/tst-linkat.c
+++ b/io/tst-linkat.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -94,7 +95,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct stat64 st1;
diff --git a/io/tst-openat.c b/io/tst-openat.c
index 741b8d0ad2..2ce89e3db1 100644
--- a/io/tst-openat.c
+++ b/io/tst-openat.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <unistd.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -94,7 +95,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
/* Before closing the file, try using this file descriptor to open
another file. This must fail. */
diff --git a/io/tst-renameat.c b/io/tst-renameat.c
index 435302b52b..0b9da5fd6d 100644
--- a/io/tst-renameat.c
+++ b/io/tst-renameat.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -94,7 +95,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct stat64 st1;
diff --git a/io/tst-symlinkat.c b/io/tst-symlinkat.c
index 214a8e348e..4a34994df7 100644
--- a/io/tst-symlinkat.c
+++ b/io/tst-symlinkat.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <sys/stat.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -94,7 +95,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
puts ("file created");
struct stat64 st1;
diff --git a/io/tst-unlinkat.c b/io/tst-unlinkat.c
index e21d56f9f7..21a2dbaf57 100644
--- a/io/tst-unlinkat.c
+++ b/io/tst-unlinkat.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <unistd.h>
+#include <support/xunistd.h>
static void prepare (void);
#define PREPARE(argc, argv) prepare ()
@@ -94,7 +95,7 @@ do_test (void)
puts ("file creation failed");
return 1;
}
- write (fd, "hello", 5);
+ xwrite (fd, "hello", 5);
close (fd);
puts ("file created");
diff --git a/libio/bug-ungetc.c b/libio/bug-ungetc.c
index 51940b68f5..4ea2d14ed6 100644
--- a/libio/bug-ungetc.c
+++ b/libio/bug-ungetc.c
@@ -2,6 +2,8 @@
#include <stdio.h>
+#include <support/xunistd.h>
+
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
@@ -20,7 +22,7 @@ do_prepare (void)
printf ("cannot create temporary file: %m\n");
exit (1);
}
- write (fd, pattern, sizeof (pattern));
+ xwrite (fd, pattern, sizeof (pattern));
close (fd);
}
diff --git a/libio/bug-ungetc3.c b/libio/bug-ungetc3.c
index 0c83c1161e..6100d7a936 100644
--- a/libio/bug-ungetc3.c
+++ b/libio/bug-ungetc3.c
@@ -2,6 +2,8 @@
#include <stdio.h>
+#include <support/xunistd.h>
+
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
@@ -20,7 +22,7 @@ do_prepare (void)
printf ("cannot create temporary file: %m\n");
exit (1);
}
- write (fd, pattern, sizeof (pattern));
+ xwrite (fd, pattern, sizeof (pattern));
close (fd);
}
diff --git a/libio/bug-ungetc4.c b/libio/bug-ungetc4.c
index 0bd02a570d..8a05def686 100644
--- a/libio/bug-ungetc4.c
+++ b/libio/bug-ungetc4.c
@@ -19,6 +19,8 @@
#include <stdio.h>
+#include <support/xunistd.h>
+
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
@@ -37,7 +39,7 @@ do_prepare (void)
printf ("cannot create temporary file: %m\n");
exit (1);
}
- write (fd, pattern, sizeof (pattern) - 1);
+ xwrite (fd, pattern, sizeof (pattern) - 1);
close (fd);
}
diff --git a/libio/bug-wfflush.c b/libio/bug-wfflush.c
index a8fd61e997..d1b9d8e9de 100644
--- a/libio/bug-wfflush.c
+++ b/libio/bug-wfflush.c
@@ -3,6 +3,8 @@
#include <stdio.h>
#include <wchar.h>
+#include <support/xunistd.h>
+
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
@@ -20,7 +22,7 @@ do_prepare (void)
printf ("cannot create temporary file: %m\n");
exit (1);
}
- write (fd, "1!", 2);
+ xwrite (fd, "1!", 2);
close (fd);
}
diff --git a/libio/bug-wsetpos.c b/libio/bug-wsetpos.c
index ccb22a4b62..0fc373ba49 100644
--- a/libio/bug-wsetpos.c
+++ b/libio/bug-wsetpos.c
@@ -4,6 +4,8 @@
#include <stdio.h>
#include <wchar.h>
+#include <support/xunistd.h>
+
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
@@ -22,7 +24,7 @@ do_prepare (void)
printf ("cannot create temporary file: %m\n");
exit (1);
}
- write (fd, pattern, sizeof (pattern));
+ xwrite (fd, pattern, sizeof (pattern));
close (fd);
}
diff --git a/nptl/tst-stackguard1.c b/nptl/tst-stackguard1.c
index b9cf6844de..4ac57157e9 100644
--- a/nptl/tst-stackguard1.c
+++ b/nptl/tst-stackguard1.c
@@ -28,6 +28,8 @@
#include <tls.h>
#include <unistd.h>
+#include <support/xunistd.h>
+
static const char *command;
static bool child;
static uintptr_t stack_chk_guard_copy;
@@ -97,7 +99,7 @@ do_test (void)
else if (ret != NULL)
return 1;
- write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
+ xwrite (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
return 0;
}
diff --git a/nptl/tst-tls3.c b/nptl/tst-tls3.c
index b1a40c624a..33d94c8cc5 100644
--- a/nptl/tst-tls3.c
+++ b/nptl/tst-tls3.c
@@ -27,6 +27,8 @@
#include <unistd.h>
#include <pthreaddef.h>
+#include <support/xunistd.h>
+
#define THE_SIG SIGUSR1
/* The stack size can be overriden. With a sufficiently large stack
diff --git a/nptl/tst-tls3mod.c b/nptl/tst-tls3mod.c
index c6e8910b1e..345a48e1c7 100644
--- a/nptl/tst-tls3mod.c
+++ b/nptl/tst-tls3mod.c
@@ -26,6 +26,7 @@
#include <pthreaddef.h>
#include <descr.h>
+#include <support/xunistd.h>
extern pthread_barrier_t b;
@@ -44,7 +45,7 @@ handler (int sig)
{
if (sig != THE_SIG)
{
- write (STDOUT_FILENO, "wrong signal\n", 13);
+ xwrite (STDOUT_FILENO, "wrong signal\n", 13);
_exit (1);
}
@@ -52,7 +53,7 @@ handler (int sig)
if (sem_post (&s) != 0)
{
- write (STDOUT_FILENO, "sem_post failed\n", 16);
+ xwrite (STDOUT_FILENO, "sem_post failed\n", 16);
_exit (1);
}
}
diff --git a/rt/tst-cpuclock2.c b/rt/tst-cpuclock2.c
index e4584d8791..8afd34ed9c 100644
--- a/rt/tst-cpuclock2.c
+++ b/rt/tst-cpuclock2.c
@@ -37,6 +37,8 @@ do_test ()
#include <errno.h>
#include <pthread.h>
+#include <support/xunistd.h>
+
static pthread_barrier_t barrier;
/* This function is intended to rack up both user and system time. */
@@ -55,7 +57,7 @@ chew_cpu (void *arg)
for (int i = 0; i < 100; ++i)
for (size_t j = 0; j < sizeof buf; ++j)
buf[j] = 0xbb;
- write (nullfd, (char *) buf, sizeof buf);
+ xwrite (nullfd, (char *) buf, sizeof buf);
close (nullfd);
}
diff --git a/rt/tst-cputimer1.c b/rt/tst-cputimer1.c
index 8f5dd76cf2..18d8b195a2 100644
--- a/rt/tst-cputimer1.c
+++ b/rt/tst-cputimer1.c
@@ -11,6 +11,8 @@
#include <time.h>
#include <pthread.h>
+#include <support/xunistd.h>
+
#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID
#define TEST_CLOCK_MISSING(clock) \
(setup_test () ? "process CPU clock timer support" : NULL)
@@ -29,7 +31,7 @@ chew_cpu (void *arg)
for (int i = 0; i < 100; ++i)
for (size_t j = 0; j < sizeof buf; ++j)
buf[j] = 0xbb;
- write (nullfd, (char *) buf, sizeof buf);
+ xwrite (nullfd, (char *) buf, sizeof buf);
close (nullfd);
}
diff --git a/rt/tst-cputimer2.c b/rt/tst-cputimer2.c
index 397d7998c0..a5700d4bac 100644
--- a/rt/tst-cputimer2.c
+++ b/rt/tst-cputimer2.c
@@ -12,6 +12,8 @@
#include <time.h>
#include <pthread.h>
+#include <support/xunistd.h>
+
static clockid_t worker_thread_clock;
#define TEST_CLOCK worker_thread_clock
@@ -32,7 +34,7 @@ chew_cpu (void *arg)
for (int i = 0; i < 100; ++i)
for (size_t j = 0; j < sizeof buf; ++j)
buf[j] = 0xbb;
- write (nullfd, (char *) buf, sizeof buf);
+ xwrite (nullfd, (char *) buf, sizeof buf);
close (nullfd);
}
diff --git a/rt/tst-cputimer3.c b/rt/tst-cputimer3.c
index 056766a377..786de93a02 100644
--- a/rt/tst-cputimer3.c
+++ b/rt/tst-cputimer3.c
@@ -13,6 +13,8 @@
#include <signal.h>
#include <sys/wait.h>
+#include <support/xunistd.h>
+
static clockid_t child_clock;
#define TEST_CLOCK child_clock
@@ -33,7 +35,7 @@ chew_cpu (void)
for (int i = 0; i < 100; ++i)
for (size_t j = 0; j < sizeof buf; ++j)
buf[j] = 0xbb;
- write (nullfd, (char *) buf, sizeof buf);
+ xwrite (nullfd, (char *) buf, sizeof buf);
close (nullfd);
if (getppid () == 1)
_exit (2);
diff --git a/support/test-container.c b/support/test-container.c
index e68f16eecf..d4ca41fe7c 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -1177,7 +1177,7 @@ main (int argc, char **argv)
int status;
/* Send the child's "outside" pid to it. */
- write (pipes[1], &child, sizeof(child));
+ xwrite (pipes[1], &child, sizeof(child));
close (pipes[0]);
close (pipes[1]);
@@ -1246,7 +1246,7 @@ main (int argc, char **argv)
sprintf (tmp, "%lld %lld 1\n",
(long long) (be_su ? 0 : original_uid), (long long) original_uid);
- write (UMAP, tmp, strlen (tmp));
+ xwrite (UMAP, tmp, strlen (tmp));
xclose (UMAP);
/* We must disable setgroups () before we can map our groups, else we
@@ -1255,7 +1255,7 @@ main (int argc, char **argv)
if (GMAP >= 0)
{
/* We support kernels old enough to not have this. */
- write (GMAP, "deny\n", 5);
+ xwrite (GMAP, "deny\n", 5);
xclose (GMAP);
}
@@ -1267,7 +1267,7 @@ main (int argc, char **argv)
sprintf (tmp, "%lld %lld 1\n",
(long long) (be_su ? 0 : original_gid), (long long) original_gid);
- write (GMAP, tmp, strlen (tmp));
+ xwrite (GMAP, tmp, strlen (tmp));
xclose (GMAP);
}
diff --git a/sysdeps/pthread/tst-cond18.c b/sysdeps/pthread/tst-cond18.c
index edac4fa4ff..ffae356c04 100644
--- a/sysdeps/pthread/tst-cond18.c
+++ b/sysdeps/pthread/tst-cond18.c
@@ -25,6 +25,8 @@
#include <stdio.h>
#include <unistd.h>
+#include <support/xunistd.h>
+
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
bool exiting;
@@ -41,7 +43,7 @@ tf (void *id)
while (!exiting)
{
if ((spins++ % 1000) == 0)
- write (fd, ".", 1);
+ xwrite (fd, ".", 1);
pthread_mutex_unlock (&lock);
pthread_mutex_lock (&lock);
diff --git a/sysdeps/pthread/tst-flock1.c b/sysdeps/pthread/tst-flock1.c
index 7eef9070ab..9de148afd3 100644
--- a/sysdeps/pthread/tst-flock1.c
+++ b/sysdeps/pthread/tst-flock1.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <sys/file.h>
+#include <support/xunistd.h>
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
@@ -57,7 +58,7 @@ do_test (void)
unlink (tmp);
- write (fd, "foobar xyzzy", 12);
+ xwrite (fd, "foobar xyzzy", 12);
if (flock (fd, LOCK_EX | LOCK_NB) != 0)
{
diff --git a/sysdeps/pthread/tst-flock2.c b/sysdeps/pthread/tst-flock2.c
index 8762e93b52..952b79e5db 100644
--- a/sysdeps/pthread/tst-flock2.c
+++ b/sysdeps/pthread/tst-flock2.c
@@ -25,6 +25,7 @@
#include <sys/mman.h>
#include <sys/wait.h>
+#include <support/xunistd.h>
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
@@ -71,7 +72,7 @@ do_test (void)
int i;
for (i = 0; i < 20; ++i)
- write (fd, "foobar xyzzy", 12);
+ xwrite (fd, "foobar xyzzy", 12);
pthread_barrier_t *b;
b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
diff --git a/sysdeps/pthread/tst-key1.c b/sysdeps/pthread/tst-key1.c
index 933edafef8..60245c4e47 100644
--- a/sysdeps/pthread/tst-key1.c
+++ b/sysdeps/pthread/tst-key1.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include <support/xunistd.h>
static int do_test (void);
@@ -52,7 +53,7 @@ do_test (void)
if (pthread_setspecific (keys[i], (const void *) (i + 100l)) != 0)
{
- write (2, "setspecific failed\n", 19);
+ xwrite (2, "setspecific failed\n", 19);
_exit (1);
}
}
@@ -61,13 +62,13 @@ do_test (void)
{
if (pthread_getspecific (keys[i]) != (void *) (i + 100l))
{
- write (2, "getspecific failed\n", 19);
+ xwrite (2, "getspecific failed\n", 19);
_exit (1);
}
if (pthread_key_delete (keys[i]) != 0)
{
- write (2, "key_delete failed\n", 18);
+ xwrite (2, "key_delete failed\n", 18);
_exit (1);
}
}
@@ -75,13 +76,13 @@ do_test (void)
/* Now it must be once again possible to allocate keys. */
if (pthread_key_create (&keys[0], NULL) != 0)
{
- write (2, "2nd key_create failed\n", 22);
+ xwrite (2, "2nd key_create failed\n", 22);
_exit (1);
}
if (pthread_key_delete (keys[0]) != 0)
{
- write (2, "2nd key_delete failed\n", 22);
+ xwrite (2, "2nd key_delete failed\n", 22);
_exit (1);
}
diff --git a/sysdeps/pthread/tst-signal1.c b/sysdeps/pthread/tst-signal1.c
index d1073e8459..d1082027ca 100644
--- a/sysdeps/pthread/tst-signal1.c
+++ b/sysdeps/pthread/tst-signal1.c
@@ -26,6 +26,7 @@
#include <sys/mman.h>
#include <sys/wait.h>
+#include <support/xunistd.h>
static sigset_t ss;
static pthread_barrier_t *b;
@@ -106,7 +107,7 @@ do_test (void)
int i;
for (i = 0; i < 20; ++i)
- write (fd, "foobar xyzzy", 12);
+ xwrite (fd, "foobar xyzzy", 12);
b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
diff --git a/sysdeps/pthread/tst-signal2.c b/sysdeps/pthread/tst-signal2.c
index dfe7d9f64a..15b7747877 100644
--- a/sysdeps/pthread/tst-signal2.c
+++ b/sysdeps/pthread/tst-signal2.c
@@ -26,6 +26,7 @@
#include <sys/wait.h>
#include <string.h>
+#include <support/xunistd.h>
static sigset_t ss;
static pthread_barrier_t *b;
@@ -112,7 +113,7 @@ do_test (void)
int i;
for (i = 0; i < 20; ++i)
- write (fd, "foobar xyzzy", 12);
+ xwrite (fd, "foobar xyzzy", 12);
b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
diff --git a/sysdeps/pthread/tst-timer.c b/sysdeps/pthread/tst-timer.c
index 47472ab8e1..4cfe0b67dc 100644
--- a/sysdeps/pthread/tst-timer.c
+++ b/sysdeps/pthread/tst-timer.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <stdint.h>
+#include <support/xunistd.h>
static void
notify_func1 (union sigval sigval)
@@ -45,7 +46,7 @@ signal_func (int sig)
{
static const char text[] = "signal_func\n";
signal (sig, signal_func);
- write (STDOUT_FILENO, text, sizeof text - 1);
+ xwrite (STDOUT_FILENO, text, sizeof text - 1);
}
static void
diff --git a/time/tst-cpuclock1.c b/time/tst-cpuclock1.c
index 6f2e70a58a..6a793e06df 100644
--- a/time/tst-cpuclock1.c
+++ b/time/tst-cpuclock1.c
@@ -27,6 +27,8 @@
#include <stdint.h>
#include <sys/wait.h>
+#include <support/xunistd.h>
+
/* This function is intended to rack up both user and system time. */
static void
chew_cpu (void)
@@ -41,7 +43,7 @@ chew_cpu (void)
for (int i = 0; i < 100; ++i)
for (size_t j = 0; j < sizeof buf; ++j)
buf[j] = 0xbb;
- write (nullfd, (char *) buf, sizeof buf);
+ xwrite (nullfd, (char *) buf, sizeof buf);
close (nullfd);
if (getppid () == 1)
_exit (2);
--
2.43.5

View File

@ -0,0 +1,30 @@
From 34bb581e7713589d38c797c214f4c6bf2b14b702 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 16 Aug 2024 16:05:19 +0200
Subject: [PATCH] support: Include <string.h> for strcmp in
support_format_addrinfo.c
Content-type: text/plain; charset=UTF-8
This is currently implied by the internal headers, but it makes
sense not to rely on this.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
---
support/support_format_addrinfo.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c
index cbc72910a9..77f4db345c 100644
--- a/support/support_format_addrinfo.c
+++ b/support/support_format_addrinfo.c
@@ -22,6 +22,7 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <support/support.h>
#include <support/xmemstream.h>
--
2.43.5

View File

@ -0,0 +1,91 @@
From 921690512946d73bf66a8c495baff31316e4489f Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 16 Aug 2024 16:05:19 +0200
Subject: [PATCH] support: Add the xstatx function
Content-type: text/plain; charset=UTF-8
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflict:
support/Makefile
context
---
support/Makefile | 1 +
support/xstatx.c | 32 ++++++++++++++++++++++++++++++++
support/xunistd.h | 2 ++
3 files changed, 35 insertions(+)
create mode 100644 support/xstatx.c
diff --git a/support/Makefile b/support/Makefile
index aa57207bdc..5b1c96a49e 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -200,6 +200,7 @@ libsupport-routines = \
xsignal \
xsigstack \
xsocket \
+ xstatx \
xposix_spawn \
xposix_spawn_file_actions_addclose \
xposix_spawn_file_actions_adddup2 \
diff --git a/support/xstatx.c b/support/xstatx.c
new file mode 100644
index 0000000000..621f2440f8
--- /dev/null
+++ b/support/xstatx.c
@@ -0,0 +1,32 @@
+/* Error-checking wrapper for statx.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xunistd.h>
+
+#include <fcntl.h>
+#include <support/check.h>
+#include <sys/stat.h>
+
+void
+xstatx (int fd, const char *path, int flags, unsigned int mask,
+ struct statx *stx)
+{
+ if (statx (fd, path, flags, mask, stx) != 0)
+ FAIL_EXIT1 ("statx (AT_FDCWD, \"%s\", 0x%x, 0x%x): %m",
+ path, (unsigned int) flags, mask);
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index 13be9a46a3..cc74c4fad0 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -30,6 +30,7 @@
__BEGIN_DECLS
struct stat64;
+struct statx;
pid_t xfork (void);
pid_t xwaitpid (pid_t, int *status, int flags);
@@ -51,6 +52,7 @@ void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64);
void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64);
void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64);
#endif
+void xstatx (int, const char *, int, unsigned int, struct statx *);
void xmkdir (const char *path, mode_t);
void xchroot (const char *path);
void xunlink (const char *path);
--
2.43.5

View File

@ -0,0 +1,410 @@
From bf2927484152e12996af60ea439cf94b66fcd81d Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 16 Aug 2024 16:05:20 +0200
Subject: [PATCH] io: Use struct statx and xstatx in tests
Content-type: text/plain; charset=UTF-8
This avoids the need to define struct_statx to an appropriate
struct stat type variant because struct statx does not change
based on time/file offset flags.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
---
io/tst-futimens-time64.c | 1 -
io/tst-futimens.c | 13 +++++--------
io/tst-futimes-time64.c | 1 -
io/tst-futimes.c | 13 +++++--------
io/tst-futimesat-time64.c | 3 ---
io/tst-futimesat.c | 30 ++++++++----------------------
io/tst-lutimes-time64.c | 1 -
io/tst-lutimes.c | 26 ++++++++++++--------------
io/tst-utime-time64.c | 1 -
io/tst-utime.c | 13 +++++--------
io/tst-utimensat-time64.c | 1 -
io/tst-utimensat.c | 35 +++++++++++++++++------------------
io/tst-utimes-time64.c | 1 -
io/tst-utimes.c | 13 +++++--------
14 files changed, 57 insertions(+), 95 deletions(-)
diff --git a/io/tst-futimens-time64.c b/io/tst-futimens-time64.c
index 88fcb38489..71204a6166 100644
--- a/io/tst-futimens-time64.c
+++ b/io/tst-futimens-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-futimens.c"
diff --git a/io/tst-futimens.c b/io/tst-futimens.c
index 6204befedd..075ca42b93 100644
--- a/io/tst-futimens.c
+++ b/io/tst-futimens.c
@@ -18,26 +18,23 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_futimens_helper (const char *file, int fd, const struct timespec *ts)
{
int result = futimens (fd, ts);
TEST_VERIFY_EXIT (result == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, ts[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, ts[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec);
return 0;
}
diff --git a/io/tst-futimes-time64.c b/io/tst-futimes-time64.c
index d489c265d1..eeb4bed7c4 100644
--- a/io/tst-futimes-time64.c
+++ b/io/tst-futimes-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-futimes.c"
diff --git a/io/tst-futimes.c b/io/tst-futimes.c
index d21acf6a24..612fe460cf 100644
--- a/io/tst-futimes.c
+++ b/io/tst-futimes.c
@@ -18,27 +18,24 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_futimens_helper (const char *file, int fd, const struct timeval *tv)
{
int r = futimes (fd, tv);
TEST_VERIFY_EXIT (r == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, tv[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, tv[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec);
return 0;
}
diff --git a/io/tst-futimesat-time64.c b/io/tst-futimesat-time64.c
index f6c0500eef..1585317579 100644
--- a/io/tst-futimesat-time64.c
+++ b/io/tst-futimesat-time64.c
@@ -1,4 +1 @@
-#define struct_stat struct stat
-#define fstat fstat
-#define fstatat fstatat
#include "io/tst-futimesat.c"
diff --git a/io/tst-futimesat.c b/io/tst-futimesat.c
index 67a8551beb..feae4e7aa7 100644
--- a/io/tst-futimesat.c
+++ b/io/tst-futimesat.c
@@ -30,12 +30,6 @@
#include <support/temp_file.h>
#include <support/xunistd.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-# define fstat fstat64
-# define fstatat fstatat64
-#endif
-
static int dir_fd;
static void
@@ -118,19 +112,15 @@ do_test (void)
xwrite (fd, "hello", 5);
puts ("file created");
- struct_stat st1;
- if (fstat (fd, &st1) != 0)
- {
- puts ("fstat64 failed");
- return 1;
- }
+ struct statx st1;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st1);
close (fd);
struct timeval tv[2];
- tv[0].tv_sec = st1.st_atime + 1;
+ tv[0].tv_sec = st1.stx_atime.tv_sec + 1;
tv[0].tv_usec = 0;
- tv[1].tv_sec = st1.st_mtime + 1;
+ tv[1].tv_sec = st1.stx_mtime.tv_sec + 1;
tv[1].tv_usec = 0;
if (futimesat (dir_fd, "some-file", tv) != 0)
{
@@ -138,16 +128,12 @@ do_test (void)
return 1;
}
- struct_stat st2;
- if (fstatat (dir_fd, "some-file", &st2, 0) != 0)
- {
- puts ("fstatat64 failed");
- return 1;
- }
+ struct statx st2;
+ xstatx (dir_fd, "some-file", 0, STATX_BASIC_STATS, &st2);
- if (st2.st_mtime != tv[1].tv_sec
+ if (st2.stx_mtime.tv_sec != tv[1].tv_sec
#ifdef _STATBUF_ST_NSEC
- || st2.st_mtim.tv_nsec != 0
+ || st2.stx_mtime.tv_nsec != 0
#endif
)
{
diff --git a/io/tst-lutimes-time64.c b/io/tst-lutimes-time64.c
index 06caec0a91..c5bea965da 100644
--- a/io/tst-lutimes-time64.c
+++ b/io/tst-lutimes-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-lutimes.c"
diff --git a/io/tst-lutimes.c b/io/tst-lutimes.c
index edef5ab90e..78bcc58291 100644
--- a/io/tst-lutimes.c
+++ b/io/tst-lutimes.c
@@ -18,34 +18,32 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_lutimes_helper (const char *testfile, int fd, const char *testlink,
const struct timeval *tv)
{
- struct_stat stfile_orig;
- xlstat (testfile, &stfile_orig);
+ struct statx stfile_orig;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stfile_orig);
TEST_VERIFY_EXIT (lutimes (testlink, tv) == 0);
- struct_stat stlink;
- xlstat (testlink, &stlink);
+ struct statx stlink;
+ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stlink);
- TEST_COMPARE (stlink.st_atime, tv[0].tv_sec);
- TEST_COMPARE (stlink.st_mtime, tv[1].tv_sec);
+ TEST_COMPARE (stlink.stx_atime.tv_sec, tv[0].tv_sec);
+ TEST_COMPARE (stlink.stx_mtime.tv_sec, tv[1].tv_sec);
/* Check if the timestamp from original file is not changed. */
- struct_stat stfile;
- xlstat (testfile, &stfile);
+ struct statx stfile;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stfile);
- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime);
- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime);
+ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec);
+ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec);
return 0;
}
diff --git a/io/tst-utime-time64.c b/io/tst-utime-time64.c
index eb62f59126..8894592a15 100644
--- a/io/tst-utime-time64.c
+++ b/io/tst-utime-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-utime.c"
diff --git a/io/tst-utime.c b/io/tst-utime.c
index e2e6dcd04c..f329358289 100644
--- a/io/tst-utime.c
+++ b/io/tst-utime.c
@@ -19,26 +19,23 @@
#include <utime.h>
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_utime_helper (const char *file, int fd, const struct utimbuf *ut)
{
int result = utime (file, ut);
TEST_VERIFY_EXIT (result == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for actime match */
- TEST_COMPARE (st.st_atime, ut->actime);
+ TEST_COMPARE (st.stx_atime.tv_sec, ut->actime);
/* Check if seconds for modtime match */
- TEST_COMPARE (st.st_mtime, ut->modtime);
+ TEST_COMPARE (st.stx_mtime.tv_sec, ut->modtime);
return 0;
}
diff --git a/io/tst-utimensat-time64.c b/io/tst-utimensat-time64.c
index 7ac7d8df1d..5d60fce881 100644
--- a/io/tst-utimensat-time64.c
+++ b/io/tst-utimensat-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-utimensat.c"
diff --git a/io/tst-utimensat.c b/io/tst-utimensat.c
index 3d9a72c471..2a756d7b07 100644
--- a/io/tst-utimensat.c
+++ b/io/tst-utimensat.c
@@ -22,10 +22,6 @@
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_utimesat_helper (const char *testfile, int fd, const char *testlink,
const struct timespec *ts)
@@ -33,35 +29,38 @@ test_utimesat_helper (const char *testfile, int fd, const char *testlink,
{
TEST_VERIFY_EXIT (utimensat (fd, testfile, ts, 0) == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, ts[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, ts[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec);
}
{
- struct_stat stfile_orig;
- xlstat (testfile, &stfile_orig);
+ struct statx stfile_orig;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stfile_orig);
TEST_VERIFY_EXIT (utimensat (0 /* ignored */, testlink, ts,
AT_SYMLINK_NOFOLLOW)
== 0);
- struct_stat stlink;
- xlstat (testlink, &stlink);
+ struct statx stlink;
+ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stlink);
- TEST_COMPARE (stlink.st_atime, ts[0].tv_sec);
- TEST_COMPARE (stlink.st_mtime, ts[1].tv_sec);
+ TEST_COMPARE (stlink.stx_atime.tv_sec, ts[0].tv_sec);
+ TEST_COMPARE (stlink.stx_mtime.tv_sec, ts[1].tv_sec);
/* Check if the timestamp from original file is not changed. */
- struct_stat stfile;
- xlstat (testfile, &stfile);
+ struct statx stfile;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stfile);
- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime);
- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime);
+ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec);
+ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec);
}
return 0;
diff --git a/io/tst-utimes-time64.c b/io/tst-utimes-time64.c
index 234ec02541..026ef5f78d 100644
--- a/io/tst-utimes-time64.c
+++ b/io/tst-utimes-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-utimes.c"
diff --git a/io/tst-utimes.c b/io/tst-utimes.c
index 8edcfabebf..6cd436c5a0 100644
--- a/io/tst-utimes.c
+++ b/io/tst-utimes.c
@@ -18,28 +18,25 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_utimes_helper (const char *file, int fd, const struct timeval *tv)
{
int result = utimes (file, tv);
TEST_VERIFY_EXIT (result == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, tv[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, tv[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec);
return 0;
}
--
2.43.5

View File

@ -0,0 +1,452 @@
From e7c14e542d8d858b824b5df4f4e3dc93695e6171 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 16 Aug 2024 16:05:20 +0200
Subject: [PATCH] support: Use macros for *stat wrappers
Content-type: text/plain; charset=UTF-8
Macros will automatically use the correct types, without
having to fiddle with internal glibc macros. It's also
impossible to get the types wrong due to aliasing because
support_check_stat_fd and support_check_stat_path do not
depend on the struct stat* types.
The changes reveal some inconsistencies in tests.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts
locale/tst-localedef-path-norm.c
context
support/Makefile
context
support/xunistd.h
context
all
copyright years
---
elf/tst-ldconfig-bad-aux-cache.c | 2 +-
io/tst-copy_file_range.c | 2 +-
io/tst-statx.c | 4 +--
locale/tst-localedef-path-norm.c | 2 +-
localedata/tst-localedef-hardlinks.c | 2 +-
posix/tst-execveat.c | 2 +-
stdio-common/tst-renameat2.c | 2 +-
stdlib/tst-system.c | 2 +-
support/Makefile | 8 ++---
support/support-xfstat-time64.c | 32 -------------------
support/support-xstat-time64.c | 32 -------------------
support/support-xstat.c | 30 -----------------
support/{xlstat.c => support_check_stat_fd.c} | 11 +++----
...ort-xfstat.c => support_check_stat_path.c} | 9 +++---
support/xlstat-time64.c | 32 -------------------
support/xunistd.h | 30 ++++++++---------
16 files changed, 34 insertions(+), 168 deletions(-)
delete mode 100644 support/support-xfstat-time64.c
delete mode 100644 support/support-xstat-time64.c
delete mode 100644 support/support-xstat.c
rename support/{xlstat.c => support_check_stat_fd.c} (76%)
rename support/{support-xfstat.c => support_check_stat_path.c} (81%)
delete mode 100644 support/xlstat-time64.c
diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
index 7f1fbb5252..8c2e62ecc2 100644
--- a/elf/tst-ldconfig-bad-aux-cache.c
+++ b/elf/tst-ldconfig-bad-aux-cache.c
@@ -85,7 +85,7 @@ do_test (void)
support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
support_capture_subprocess_free (&result);
- xstat (path, &fs);
+ xstat64 (path, &fs);
size = fs.st_size;
/* Run 3 tests, each truncating aux-cache shorter and shorter. */
diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c
index 9837b7c339..3d7b0aa901 100644
--- a/io/tst-copy_file_range.c
+++ b/io/tst-copy_file_range.c
@@ -117,7 +117,7 @@ simple_file_copy (void)
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 6 + length);
struct stat64 st;
- xfstat (outfd, &st);
+ xfstat64 (outfd, &st);
if (length > 0)
TEST_COMPARE (st.st_size, out_skipped + length);
else
diff --git a/io/tst-statx.c b/io/tst-statx.c
index d84568859e..685924ae76 100644
--- a/io/tst-statx.c
+++ b/io/tst-statx.c
@@ -78,7 +78,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd)
struct statx stx = { 0, };
TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0);
struct stat64 st;
- xfstat (fd, &st);
+ xfstat64 (fd, &st);
TEST_COMPARE (stx.stx_mode, st.st_mode);
TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
@@ -88,7 +88,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd)
TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx),
0);
struct stat64 st;
- xstat ("/dev/null", &st);
+ xstat64 ("/dev/null", &st);
TEST_COMPARE (stx.stx_mode, st.st_mode);
TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c
index ffe8cbd467..f592b9a960 100644
--- a/locale/tst-localedef-path-norm.c
+++ b/locale/tst-localedef-path-norm.c
@@ -81,7 +81,7 @@ run_test (struct test_closure data)
support_capture_subprocess_free (&result);
/* Verify path is present and is a directory. */
- xstat (path, &fs);
+ xstat64 (path, &fs);
TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode));
printf ("info: Directory '%s' exists.\n", path);
}
diff --git a/localedata/tst-localedef-hardlinks.c b/localedata/tst-localedef-hardlinks.c
index e88215a150..23927b462f 100644
--- a/localedata/tst-localedef-hardlinks.c
+++ b/localedata/tst-localedef-hardlinks.c
@@ -62,7 +62,7 @@ check_link (struct test_data step)
char *output;
output = xasprintf ("%s/%s", support_complocaledir_prefix, step.output);
- xstat (output, &locale);
+ xstat64 (output, &locale);
free (output);
TEST_COMPARE (locale.st_nlink, step.st_nlink);
}
diff --git a/posix/tst-execveat.c b/posix/tst-execveat.c
index 4565d6b19f..dde034a9f1 100644
--- a/posix/tst-execveat.c
+++ b/posix/tst-execveat.c
@@ -155,7 +155,7 @@ do_test (void)
tmp_sh = xasprintf ("%s/tmp_sh", tmp_dir);
add_temp_file (tmp_sh);
fd_out = xopen (symlink_name, O_CREAT | O_WRONLY, 0);
- xstat ("/bin/sh", &st);
+ xstat64 ("/bin/sh", &st);
fd = xopen ("/bin/sh", O_RDONLY, 0);
xcopy_file_range (fd, 0, fd_out, 0, st.st_size, 0);
xfchmod (fd_out, 0700);
diff --git a/stdio-common/tst-renameat2.c b/stdio-common/tst-renameat2.c
index b65afed75e..7f4345f716 100644
--- a/stdio-common/tst-renameat2.c
+++ b/stdio-common/tst-renameat2.c
@@ -82,7 +82,7 @@ static void
check_size (const char *path, off64_t expected_size)
{
struct stat64 st;
- xstat (path, &st);
+ xstat64 (path, &st);
if (st.st_size != expected_size)
FAIL_EXIT1 ("file \"%s\": expected size %lld, actual size %lld",
path, (unsigned long long int) expected_size,
diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c
index 47c742f963..b5b630a41b 100644
--- a/stdlib/tst-system.c
+++ b/stdlib/tst-system.c
@@ -156,7 +156,7 @@ do_test (void)
{
struct stat64 st;
- xstat (_PATH_BSHELL, &st);
+ xstat64 (_PATH_BSHELL, &st);
mode_t mode = st.st_mode;
xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH));
diff --git a/support/Makefile b/support/Makefile
index 5b1c96a49e..6e3c55394f 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -42,14 +42,12 @@ libsupport-routines = \
resolv_test \
set_fortify_handler \
support_stack_alloc \
- support-xfstat \
- support-xfstat-time64 \
- support-xstat \
- support-xstat-time64 \
support_become_root \
support_can_chroot \
support_capture_subprocess \
support_capture_subprocess_check \
+ support_check_stat_fd \
+ support_check_stat_path \
support_chroot \
support_copy_file \
support_copy_file_range \
@@ -130,8 +128,6 @@ libsupport-routines = \
xgetsockname \
xlisten \
xlseek \
- xlstat \
- xlstat-time64 \
xmalloc \
xmemstream \
xmkdir \
diff --git a/support/support-xfstat-time64.c b/support/support-xfstat-time64.c
deleted file mode 100644
index 589a69bb3e..0000000000
--- a/support/support-xfstat-time64.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 64-bit time_t stat with error checking.
- Copyright (C) 2021 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- 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.
-
- The GNU C Library 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 the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-#if __TIMESIZE != 64
-void
-xfstat_time64 (int fd, struct __stat64_t64 *result)
-{
- if (__fstat64_time64 (fd, result) != 0)
- FAIL_EXIT1 ("__fstat64_time64 (%d): %m", fd);
-}
-#endif
diff --git a/support/support-xstat-time64.c b/support/support-xstat-time64.c
deleted file mode 100644
index 451948734a..0000000000
--- a/support/support-xstat-time64.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 64-bit time_t stat with error checking.
- Copyright (C) 2021 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- 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.
-
- The GNU C Library 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 the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-#if __TIMESIZE != 64
-void
-xstat_time64 (const char *path, struct __stat64_t64 *result)
-{
- if (__stat64_time64 (path, result) != 0)
- FAIL_EXIT1 ("__stat64_time64 (\"%s\"): %m", path);
-}
-#endif
diff --git a/support/support-xstat.c b/support/support-xstat.c
deleted file mode 100644
index ce866f74d2..0000000000
--- a/support/support-xstat.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* stat64 with error checking.
- Copyright (C) 2017-2021 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- 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.
-
- The GNU C Library 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 the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-void
-xstat (const char *path, struct stat64 *result)
-{
- if (stat64 (path, result) != 0)
- FAIL_EXIT1 ("stat64 (\"%s\"): %m", path);
-}
diff --git a/support/xlstat.c b/support/support_check_stat_fd.c
similarity index 76%
rename from support/xlstat.c
rename to support/support_check_stat_fd.c
index 87df988879..4c12adf6b7 100644
--- a/support/xlstat.c
+++ b/support/support_check_stat_fd.c
@@ -1,5 +1,5 @@
-/* lstat64 with error checking.
- Copyright (C) 2017-2021 Free Software Foundation, Inc.
+/* Error checking for descriptor-based stat functions.
+ Copyright (C) 2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -18,11 +18,10 @@
#include <support/check.h>
#include <support/xunistd.h>
-#include <sys/stat.h>
void
-xlstat (const char *path, struct stat64 *result)
+support_check_stat_fd (const char *name, int fd, int result)
{
- if (lstat64 (path, result) != 0)
- FAIL_EXIT1 ("lstat64 (\"%s\"): %m", path);
+ if (result != 0)
+ FAIL_EXIT1 ("%s (%d): %m", name, fd);
}
diff --git a/support/support-xfstat.c b/support/support_check_stat_path.c
similarity index 81%
rename from support/support-xfstat.c
rename to support/support_check_stat_path.c
index ab4b01c97d..3cf72afe59 100644
--- a/support/support-xfstat.c
+++ b/support/support_check_stat_path.c
@@ -1,4 +1,4 @@
-/* fstat64 with error checking.
+/* Error checking for path-based stat functions.
Copyright (C) 2017-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,11 +18,10 @@
#include <support/check.h>
#include <support/xunistd.h>
-#include <sys/stat.h>
void
-xfstat (int fd, struct stat64 *result)
+support_check_stat_path (const char *name, const char *path, int result)
{
- if (fstat64 (fd, result) != 0)
- FAIL_EXIT1 ("fstat64 (%d): %m", fd);
+ if (result != 0)
+ FAIL_EXIT1 ("%s (\"%s\"): %m", name, path);
}
diff --git a/support/xlstat-time64.c b/support/xlstat-time64.c
deleted file mode 100644
index 2bc3ca6593..0000000000
--- a/support/xlstat-time64.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 64-bit time_t stat with error checking.
- Copyright (C) 2021 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- 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.
-
- The GNU C Library 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 the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-#if __TIMESIZE != 64
-void
-xlstat_time64 (const char *path, struct __stat64_t64 *result)
-{
- if (__lstat64_time64 (path, result) != 0)
- FAIL_EXIT1 ("__lstat64_time64 (\"%s\"): %m", path);
-}
-#endif
diff --git a/support/xunistd.h b/support/xunistd.h
index cc74c4fad0..204951bce7 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -29,7 +29,6 @@
__BEGIN_DECLS
-struct stat64;
struct statx;
pid_t xfork (void);
@@ -37,21 +36,20 @@ pid_t xwaitpid (pid_t, int *status, int
void xpipe (int[2]);
void xdup2 (int, int);
int xopen (const char *path, int flags, mode_t);
-#ifndef __USE_TIME_BITS64
-# ifdef __USE_FILE_OFFSET64
-void xstat (const char *path, struct stat *);
-void xlstat (const char *path, struct stat *);
-void xfstat (int fd, struct stat *);
-# else
-void xstat (const char *path, struct stat64 *);
-void xlstat (const char *path, struct stat64 *);
-void xfstat (int fd, struct stat64 *);
-# endif
-#else
-void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64);
-void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64);
-void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64);
-#endif
+void support_check_stat_fd (const char *name, int fd, int result);
+void support_check_stat_path (const char *name, const char *path, int result);
+#define xstat(path, st) \
+ (support_check_stat_path ("stat", (path), stat ((path), (st))))
+#define xfstat(fd, st) \
+ (support_check_stat_fd ("fstat", (fd), fstat ((fd), (st))))
+#define xlstat(path, st) \
+ (support_check_stat_path ("lstat", (path), lstat ((path), (st))))
+#define xstat64(path, st) \
+ (support_check_stat_path ("stat64", (path), stat64 ((path), (st))))
+#define xfstat64(fd, st) \
+ (support_check_stat_fd ("fstat64", (fd), fstat64 ((fd), (st))))
+#define xlstat64(path, st) \
+ (support_check_stat_path ("lstat64", (path), lstat64 ((path), (st))))
void xstatx (int, const char *, int, unsigned int, struct statx *);
void xmkdir (const char *path, mode_t);
void xchroot (const char *path);
--
2.43.5

View File

@ -0,0 +1,47 @@
From 34e52acd55d69964d14fb3188c5538442b8b32be Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 22 Aug 2024 16:14:17 +0200
Subject: [PATCH] support: Report errno constants in TEST_COMPARE failures
Content-type: text/plain; charset=UTF-8
If the expression is errno, decode it as an errno constant
using strerrorname_np.
Reviewed-by: Arjun Shankar <arjun@redhat.com>
---
support/support_test_compare_failure.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/support/support_test_compare_failure.c b/support/support_test_compare_failure.c
index ae73d200cd..dba79e413f 100644
--- a/support/support_test_compare_failure.c
+++ b/support/support_test_compare_failure.c
@@ -17,7 +17,9 @@
<https://www.gnu.org/licenses/>. */
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
+#include <string.h>
#include <support/check.h>
static void
@@ -31,7 +33,14 @@ report (const char *which, const char *expr, long long value, int positive,
printf ("%lld", value);
unsigned long long mask
= (~0ULL) >> (8 * (sizeof (unsigned long long) - size));
- printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr);
+ const char *errno_constant = NULL;
+ if (strcmp (expr, "errno") == 0
+ && positive && (unsigned long long int) value <= INT_MAX)
+ errno_constant = strerrorname_np (value);
+ printf (" (0x%llx", (unsigned long long) value & mask);
+ if (errno_constant != NULL)
+ printf (", %s", errno_constant);
+ printf ("); from: %s\n", expr);
}
void
--
2.43.5

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,438 @@
From 3b1d32177635023e37bec7fbfd77c3cfb2659eb1 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 30 Aug 2024 21:52:10 +0200
Subject: [PATCH] support: Add <support/xdirent.h>
Content-type: text/plain; charset=UTF-8
Use static functions for readdir/readdir_r, so that
-D_FILE_OFFSET_BITS=64 does not improperly redirect calls to the wrong
implementation.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts
support/Makefile
context
---
support/Makefile | 6 +++
support/support_readdir_check.c | 30 +++++++++++
support/support_readdir_r_check.c | 35 +++++++++++++
support/tst-xdirent.c | 76 +++++++++++++++++++++++++++
support/xclosedir.c | 28 ++++++++++
support/xdirent.h | 86 +++++++++++++++++++++++++++++++
support/xfdopendir.c | 30 +++++++++++
support/xopendir.c | 30 +++++++++++
8 files changed, 321 insertions(+)
create mode 100644 support/support_readdir_check.c
create mode 100644 support/support_readdir_r_check.c
create mode 100644 support/tst-xdirent.c
create mode 100644 support/xclosedir.c
create mode 100644 support/xdirent.h
create mode 100644 support/xfdopendir.c
create mode 100644 support/xopendir.c
diff --git a/support/Makefile b/support/Makefile
index 26bd3d38e4..8fb4d2c500 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -73,6 +73,8 @@ libsupport-routines = \
support_quote_blob \
support_quote_blob_wide \
support_quote_string \
+ support_readdir_check \
+ support_readdir_r_check \
support_record_failure \
support_run_diff \
support_select_modifies_timeout \
@@ -112,6 +114,7 @@ libsupport-routines = \
xclock_settime_time64 \
xclone \
xclose \
+ xclosedir \
xchmod \
xconnect \
xcopy_file_range \
@@ -120,6 +123,7 @@ libsupport-routines = \
xdup2 \
xfchmod \
xfclose \
+ xfdopendir \
xfopen \
xfork \
xftruncate \
@@ -137,6 +141,7 @@ libsupport-routines = \
xmunmap \
xnewlocale \
xopen \
+ xopendir \
xpipe \
xpoll \
xposix_memalign \
@@ -306,6 +311,7 @@ tests = \
tst-test_compare_string \
tst-test_compare_string_wide \
tst-timespec \
+ tst-xdirent \
tst-xreadlink \
tst-xsigstack \
diff --git a/support/support_readdir_check.c b/support/support_readdir_check.c
new file mode 100644
index 0000000000..5687004276
--- /dev/null
+++ b/support/support_readdir_check.c
@@ -0,0 +1,30 @@
+/* Error-checking helper for xreaddir, xreaddir64.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdirent.h>
+
+#include <support/check.h>
+
+void *
+support_readdir_check (const char *name, void *result, int saved_errno)
+{
+ if (result == NULL && errno != 0)
+ FAIL_EXIT1 ("%s: %m", name);
+ errno = saved_errno;
+ return result;
+}
diff --git a/support/support_readdir_r_check.c b/support/support_readdir_r_check.c
new file mode 100644
index 0000000000..6bbb0d0b32
--- /dev/null
+++ b/support/support_readdir_r_check.c
@@ -0,0 +1,35 @@
+/* Error-checking helper for xreaddir_r, xreaddir64_r.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdirent.h>
+
+#include <support/check.h>
+
+int
+support_readdir_r_check (const char *name, int result, void *buf, void *ptr)
+{
+ if (result != 0)
+ {
+ errno = result;
+ FAIL_EXIT1 ("%s: %m", name);
+ }
+ if (buf != ptr)
+ FAIL_EXIT1 ("%s: buffer pointer and returned pointer differ: %p != %p",
+ name, buf, ptr);
+ return result;
+}
diff --git a/support/tst-xdirent.c b/support/tst-xdirent.c
new file mode 100644
index 0000000000..642483165a
--- /dev/null
+++ b/support/tst-xdirent.c
@@ -0,0 +1,76 @@
+/* Compile test for error-checking wrappers for <dirent.h>
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdirent.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ {
+ DIR *d = xopendir (".");
+ struct dirent *e = xreaddir (d);
+ /* Assume that the "." special entry always comes first. */
+ TEST_COMPARE_STRING (e->d_name, ".");
+ while (xreaddir (d) != NULL)
+ ;
+ xclosedir (d);
+ }
+
+ {
+ DIR *d = xopendir (".");
+ struct dirent64 *e = xreaddir64 (d);
+ TEST_COMPARE_STRING (e->d_name, ".");
+ while (xreaddir64 (d) != NULL)
+ ;
+ xclosedir (d);
+ }
+
+ /* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */
+ DIAG_PUSH_NEEDS_COMMENT;
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
+
+ {
+ DIR *d = xopendir (".");
+ struct dirent buf = { 0, };
+ TEST_VERIFY (xreaddir_r (d, &buf));
+ TEST_COMPARE_STRING (buf.d_name, ".");
+ while (xreaddir_r (d, &buf))
+ ;
+ xclosedir (d);
+ }
+
+ {
+ DIR *d = xopendir (".");
+ struct dirent64 buf = { 0, };
+ TEST_VERIFY (xreaddir64_r (d, &buf));
+ TEST_COMPARE_STRING (buf.d_name, ".");
+ while (xreaddir64_r (d, &buf))
+ ;
+ xclosedir (d);
+ }
+
+ DIAG_POP_NEEDS_COMMENT;
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/xclosedir.c b/support/xclosedir.c
new file mode 100644
index 0000000000..b490df5598
--- /dev/null
+++ b/support/xclosedir.c
@@ -0,0 +1,28 @@
+/* Error-checking wrapper for closedir.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdirent.h>
+
+#include <support/check.h>
+
+void
+xclosedir (DIR *dir)
+{
+ if (closedir (dir) != 0)
+ FAIL_EXIT1 ("closedir: %m");
+}
diff --git a/support/xdirent.h b/support/xdirent.h
new file mode 100644
index 0000000000..8465d70ec1
--- /dev/null
+++ b/support/xdirent.h
@@ -0,0 +1,86 @@
+/* Error-checking wrappers for <dirent.h>
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_XDIRENT_H
+#define SUPPORT_XDIRENT_H
+
+#include <dirent.h>
+#include <errno.h>
+#include <libc-diag.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+DIR *xopendir (const char *path);
+DIR *xfdopendir (int fd);
+void xclosedir (DIR *);
+
+void *support_readdir_check (const char *, void *, int);
+
+static __attribute__ ((unused)) struct dirent *
+xreaddir (DIR *stream)
+{
+ int saved_errno = errno;
+ errno = 0;
+ struct dirent *result = readdir (stream);
+ return support_readdir_check ("readdir", result, saved_errno);
+}
+
+static __attribute__ ((unused)) struct dirent64 *
+xreaddir64 (DIR *stream)
+{
+ int saved_errno = errno;
+ errno = 0;
+ struct dirent64 *result = readdir64 (stream);
+ return support_readdir_check ("readdir64", result, saved_errno);
+}
+
+/* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */
+DIAG_PUSH_NEEDS_COMMENT;
+DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
+
+int support_readdir_r_check (const char *, int, void *, void *);
+
+static __attribute__ ((unused)) bool
+xreaddir_r (DIR *stream, struct dirent *buf)
+{
+ struct dirent *ptr;
+ int ret = readdir_r (stream, buf, &ptr);
+ if (ret == 0 && ptr == NULL)
+ return false;
+ support_readdir_r_check ("readdir_r", ret, buf, ptr);
+ return true;
+}
+
+static __attribute__ ((unused)) bool
+xreaddir64_r (DIR *stream, struct dirent64 *buf)
+{
+ struct dirent64 *ptr;
+ int ret = readdir64_r (stream, buf, &ptr);
+ if (ret == 0 && ptr == NULL)
+ return false;
+ support_readdir_r_check ("readdir64_r", ret, buf, ptr);
+ return true;
+}
+
+DIAG_POP_NEEDS_COMMENT;
+
+__END_DECLS
+
+#endif /* SUPPORT_XDIRENT_H */
diff --git a/support/xfdopendir.c b/support/xfdopendir.c
new file mode 100644
index 0000000000..d881d28c73
--- /dev/null
+++ b/support/xfdopendir.c
@@ -0,0 +1,30 @@
+/* Error-checking wrapper for fdopendir.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdirent.h>
+
+#include <support/check.h>
+
+DIR *
+xfdopendir (int fd)
+{
+ DIR *result = fdopendir (fd);
+ if (result == NULL)
+ FAIL_EXIT1 ("fdopendir (%d): %m", fd);
+ return result;
+}
diff --git a/support/xopendir.c b/support/xopendir.c
new file mode 100644
index 0000000000..e4aee07fee
--- /dev/null
+++ b/support/xopendir.c
@@ -0,0 +1,30 @@
+/* Error-checking wrapper for opendir.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdirent.h>
+
+#include <support/check.h>
+
+DIR *
+xopendir (const char *path)
+{
+ DIR *result = opendir (path);
+ if (result == NULL)
+ FAIL_EXIT1 ("opendir (\"%s\"): %m", path);
+ return result;
+}
--
2.43.5

View File

@ -0,0 +1,94 @@
commit 424d97be50488beb6196c0ff0bc3dfeb87b4281c
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 30 20:37:18 2024 +0200
io: Add error tests for fchmod
On Linux most descriptors that do not correspond to file system
entities (such as anonymous pipes and sockets) have file permissions
that can be changed. While it is possible to create a custom file
system that returns (say) EINVAL for an fchmod attempt, testing this
does not appear to be useful.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
io/Makefile
(usual tests conflict)
diff --git a/io/Makefile b/io/Makefile
index 5284a1282dd07e3d..30dd48b8acf9dcb9 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -79,7 +79,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
tst-futimens \
tst-utimensat \
tst-closefrom \
- tst-ftw-bz28126
+ tst-ftw-bz28126 \
+ tst-fchmod-errors
tests-time64 := \
tst-fcntl-time64 \
diff --git a/io/tst-fchmod-errors.c b/io/tst-fchmod-errors.c
new file mode 100644
index 0000000000000000..ee15300fc3edf6f0
--- /dev/null
+++ b/io/tst-fchmod-errors.c
@@ -0,0 +1,56 @@
+/* Test various fchmod error cases.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+static int
+do_test (void)
+{
+ {
+ /* Permissions on /dev/null (the opened descriptor) cannot be changed. */
+ int fd = xopen ("/dev/null", O_RDWR, 0);
+ errno = 0;
+ TEST_COMPARE (fchmod (fd, 0), -1);
+ TEST_COMPARE (errno, EPERM);
+ xclose (fd);
+
+ /* Now testing an invalid file descriptor. */
+ errno = 0;
+ TEST_COMPARE (fchmod (fd, 0600), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+
+ errno = 0;
+ TEST_COMPARE (fchmod (-1, 0600), -1);
+ TEST_COMPARE (errno, EBADF);
+
+ errno = 0;
+ TEST_COMPARE (fchmod (AT_FDCWD, 0600), -1);
+ TEST_COMPARE (errno, EBADF);
+
+ /* Linux supports fchmod on pretty much all file descriptors, so
+ there is no check for failure on specific types of descriptors
+ here. */
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,44 @@
commit 3844cdc33093dbe1e33ddb831eada9bdb4a482b9
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 30 22:07:12 2024 +0200
io: Fix destructive nature of tst-fchmod-errors
We must not change the permissions of /dev/null if running
as root.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/io/tst-fchmod-errors.c b/io/tst-fchmod-errors.c
index ee15300fc3edf6f0..bf2a4c568e33aeaa 100644
--- a/io/tst-fchmod-errors.c
+++ b/io/tst-fchmod-errors.c
@@ -18,8 +18,10 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
#include <support/check.h>
#include <support/xunistd.h>
+#include <unistd.h>
static int
do_test (void)
@@ -27,9 +29,14 @@ do_test (void)
{
/* Permissions on /dev/null (the opened descriptor) cannot be changed. */
int fd = xopen ("/dev/null", O_RDWR, 0);
- errno = 0;
- TEST_COMPARE (fchmod (fd, 0), -1);
- TEST_COMPARE (errno, EPERM);
+ if (getuid () == 0)
+ puts ("info: /dev/null fchmod test skipped because of root privileges");
+ else
+ {
+ errno = 0;
+ TEST_COMPARE (fchmod (fd, 0), -1);
+ TEST_COMPARE (errno, EPERM);
+ }
xclose (fd);
/* Now testing an invalid file descriptor. */

View File

@ -0,0 +1,149 @@
commit 43669fcf7315f494bbbc2c040cedeb0fa8416a5f
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Aug 22 11:02:51 2024 +0200
io: Add FUSE-based test for fchmod
Test all mode arguments, and that extra bits are ignored
as required by POSIX.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts:
io/Makefile
(usual tests conflict)
diff --git a/io/Makefile b/io/Makefile
index 30dd48b8acf9dcb9..cc78a438a8898ae3 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -80,7 +80,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
tst-utimensat \
tst-closefrom \
tst-ftw-bz28126 \
- tst-fchmod-errors
+ tst-fchmod-errors \
+ tst-fchmod-fuse
tests-time64 := \
tst-fcntl-time64 \
diff --git a/io/tst-fchmod-fuse.c b/io/tst-fchmod-fuse.c
new file mode 100644
index 0000000000000000..fbd3309963491105
--- /dev/null
+++ b/io/tst-fchmod-fuse.c
@@ -0,0 +1,114 @@
+/* FUSE-based test for fchmod.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/fuse.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+/* Set from do_test to indicate the expected incoming mode change request. */
+static _Atomic int expected_mode;
+
+static void
+fuse_thread (struct support_fuse *f, void *closure)
+{
+ struct fuse_in_header *inh;
+ while ((inh = support_fuse_next (f)) != NULL)
+ {
+ if (support_fuse_handle_mountpoint (f)
+ || (inh->nodeid == 1 && support_fuse_handle_directory (f)))
+ continue;
+ switch (inh->opcode)
+ {
+ case FUSE_LOOKUP:
+ {
+ char *name = support_fuse_cast (LOOKUP, inh);
+ TEST_COMPARE_STRING (name, "file");
+ struct fuse_entry_out *out
+ = support_fuse_prepare_entry (f, 2);
+ out->attr.mode = S_IFREG | 0600;
+ support_fuse_reply_prepared (f);
+ }
+ break;
+ case FUSE_OPEN:
+ {
+ TEST_COMPARE (inh->nodeid, 2);
+ struct fuse_open_in *p = support_fuse_cast (OPEN, inh);
+ TEST_COMPARE (p->flags & O_ACCMODE, O_RDWR);
+ struct fuse_open_out out = { 0, };
+ support_fuse_reply (f, &out, sizeof (out));
+ }
+ break;
+ case FUSE_SETATTR:
+ {
+ TEST_COMPARE (inh->nodeid, 2);
+ struct fuse_setattr_in *p = support_fuse_cast (SETATTR, inh);
+ TEST_COMPARE (p->valid , FATTR_MODE);
+ TEST_COMPARE (p->mode, S_IFREG | expected_mode);
+ struct fuse_attr_out *out = support_fuse_prepare_attr (f);
+ out->attr.mode = S_IFREG | p->mode;
+ support_fuse_reply_prepared (f);
+ }
+ break;
+ case FUSE_FLUSH:
+ support_fuse_reply_empty (f);
+ break;
+ default:
+ support_fuse_reply_error (f, EIO);
+ }
+ }
+}
+
+/* Test all mode values with the specified extra bits. */
+static void
+test_with_bits (int fd, unsigned int extra_bits)
+{
+ for (int do_mode = 0; do_mode <= 07777; ++do_mode)
+ {
+ expected_mode = do_mode;
+ TEST_COMPARE (fchmod (fd, extra_bits | do_mode), 0);
+ }
+}
+
+static int
+do_test (void)
+{
+ support_fuse_init ();
+
+ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL);
+ char *path = xasprintf ("%s/file", support_fuse_mountpoint (f));
+ int fd = xopen (path, O_RDWR, 0600);
+ free (path);
+
+ test_with_bits (fd, 0);
+ /* POSIX requires that the extra bits are ignored. */
+ test_with_bits (fd, S_IFREG);
+ test_with_bits (fd, S_IFDIR);
+ test_with_bits (fd, ~07777);
+
+ xclose (fd);
+ support_fuse_unmount (f);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,89 @@
commit 70d083630563831e7069ad412cd3ab0b33638e92
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Dec 19 20:56:44 2024 +0100
Linux: Accept null arguments for utimensat pathname
This matches kernel behavior. With this change, it is possible
to use utimensat as a replacement for the futimens interface,
similar to what glibc does internally.
Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
diff --git a/io/sys/stat.h b/io/sys/stat.h
index f7874ec5baa60022..93cf8e02744f29a6 100644
--- a/io/sys/stat.h
+++ b/io/sys/stat.h
@@ -433,13 +433,13 @@ extern int mkfifoat (int __fd, const char *__path, __mode_t __mode)
extern int utimensat (int __fd, const char *__path,
const struct timespec __times[2],
int __flags)
- __THROW __nonnull ((2));
+ __THROW;
# else
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (utimensat, (int fd, const char *__path,
const struct timespec __times[2],
int flags),
- __utimensat64) __nonnull ((2));
+ __utimensat64);
# else
# define utimensat __utimensat64
# endif
diff --git a/io/tst-utimensat.c b/io/tst-utimensat.c
index 425cc9c58b1d218c..17dfa2c96251493d 100644
--- a/io/tst-utimensat.c
+++ b/io/tst-utimensat.c
@@ -39,6 +39,38 @@ test_utimesat_helper (const char *testfile, int fd, const char *testlink,
TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec);
}
+ /* Alter the timestamp using a NULL path. */
+ {
+ struct timespec ts1[2] = {ts[0], ts[1]};
+ ts1[0].tv_sec ^= 1;
+ ts1[1].tv_sec ^= 1;
+
+ TEST_VERIFY_EXIT (utimensat (fd, NULL, ts1, 0) == 0);
+
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
+
+ /* Check if seconds for atime match */
+ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec ^ 1);
+
+ /* Check if seconds for mtime match */
+ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec ^ 1);
+ }
+
+ /* And switch it back using a NULL path. */
+ {
+ TEST_VERIFY_EXIT (utimensat (fd, NULL, ts, 0) == 0);
+
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
+
+ /* Check if seconds for atime match */
+ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec);
+
+ /* Check if seconds for mtime match */
+ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec);
+ }
+
{
struct statx stfile_orig;
xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
diff --git a/sysdeps/unix/sysv/linux/utimensat.c b/sysdeps/unix/sysv/linux/utimensat.c
index e9061d23239212ad..c173c73ac0699529 100644
--- a/sysdeps/unix/sysv/linux/utimensat.c
+++ b/sysdeps/unix/sysv/linux/utimensat.c
@@ -75,9 +75,6 @@ int
__utimensat64 (int fd, const char *file, const struct __timespec64 tsp64[2],
int flags)
{
- if (file == NULL)
- return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
-
return __utimensat64_helper (fd, file, &tsp64[0], flags);
}

View File

@ -0,0 +1,58 @@
commit 868ab8923a2ec977faafec97ecafac0c3159c1b2
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Jun 13 18:56:30 2024 +0200
resolv: Track single-request fallback via _res._flags (bug 31476)
This avoids changing _res.options, which inteferes with change
detection as part of automatic reloading of /etc/resolv.conf.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff -Nrup a/resolv/res_send.c b/resolv/res_send.c
--- a/resolv/res_send.c 2024-10-20 19:06:22.807194569 -0400
+++ b/resolv/res_send.c 2024-10-20 19:05:56.917074062 -0400
@@ -947,9 +947,11 @@ send_dg(res_state statp,
seconds /= statp->nscount;
if (seconds <= 0)
seconds = 1;
- bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
- bool single_request = (((statp->options & RES_SNGLKUP) != 0)
- | single_request_reopen);
+ bool single_request_reopen = ((statp->options & RES_SNGLKUPREOP)
+ || (statp->_flags & RES_F_SNGLKUPREOP));
+ bool single_request = ((statp->options & RES_SNGLKUP)
+ || (statp->_flags & RES_F_SNGLKUP)
+ || single_request_reopen);
int save_gotsomewhere = *gotsomewhere;
int retval;
@@ -1006,14 +1008,14 @@ send_dg(res_state statp,
have received the first answer. */
if (!single_request)
{
- statp->options |= RES_SNGLKUP;
+ statp->_flags |= RES_F_SNGLKUP;
single_request = true;
*gotsomewhere = save_gotsomewhere;
goto retry;
}
else if (!single_request_reopen)
{
- statp->options |= RES_SNGLKUPREOP;
+ statp->_flags |= RES_F_SNGLKUPREOP;
single_request_reopen = true;
*gotsomewhere = save_gotsomewhere;
__res_iclose (statp, false);
diff -Nrup a/resolv/resolv-internal.h b/resolv/resolv-internal.h
--- a/resolv/resolv-internal.h 2024-10-20 19:06:22.807194569 -0400
+++ b/resolv/resolv-internal.h 2024-10-20 19:07:31.700515224 -0400
@@ -26,6 +26,8 @@
#define RES_F_VC 0x00000001 /* Socket is TCP. */
#define RES_F_CONN 0x00000002 /* Socket is connected. */
#define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors. */
+#define RES_F_SNGLKUP 0x00200000 /* Private version of RES_SNGLKUP. */
+#define RES_F_SNGLKUPREOP 0x00400000 /* Private version of RES_SNGLKUPREOP. */
/* Legacy function. This needs to be removed once all NSS modules
have been adjusted. */

View File

@ -0,0 +1,200 @@
commit 691a3b2e9bfaba842e46a5ccb7f5e6ea144c3ade
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jul 24 12:06:47 2024 +0200
resolv: Allow short error responses to match any query (bug 31890)
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/resolv/Makefile b/resolv/Makefile
index 5f44f5896b..d927e337d9 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -106,6 +106,7 @@ tests += \
tst-resolv-nondecimal \
tst-resolv-res_init-multi \
tst-resolv-search \
+ tst-resolv-short-response \
tst-resolv-trailing \
# This test calls __res_context_send directly, which is not exported
@@ -299,6 +300,8 @@ $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \
+ $(shared-thread-library)
$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-threads: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \
diff --git a/resolv/res_send.c b/resolv/res_send.c
index ea7cf192b2..572e72c32f 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -1199,19 +1199,30 @@ send_dg(res_state statp,
}
/* Check for the correct header layout and a matching
- question. */
+ question. Some recursive resolvers send REFUSED
+ without copying back the question section
+ (producing a response that is only HFIXEDSZ bytes
+ long). Skip query matching in this case. */
+ bool thisansp_error = (anhp->rcode == SERVFAIL ||
+ anhp->rcode == NOTIMP ||
+ anhp->rcode == REFUSED);
+ bool skip_query_match = (*thisresplenp == HFIXEDSZ
+ && ntohs (anhp->qdcount) == 0
+ && thisansp_error);
int matching_query = 0; /* Default to no matching query. */
if (!recvresp1
&& anhp->id == hp->id
- && __libc_res_queriesmatch (buf, buf + buflen,
- *thisansp,
- *thisansp + *thisanssizp))
+ && (skip_query_match
+ || __libc_res_queriesmatch (buf, buf + buflen,
+ *thisansp,
+ *thisansp + *thisanssizp)))
matching_query = 1;
if (!recvresp2
&& anhp->id == hp2->id
- && __libc_res_queriesmatch (buf2, buf2 + buflen2,
- *thisansp,
- *thisansp + *thisanssizp))
+ && (skip_query_match
+ || __libc_res_queriesmatch (buf2, buf2 + buflen2,
+ *thisansp,
+ *thisansp + *thisanssizp)))
matching_query = 2;
if (matching_query == 0)
/* Spurious UDP packet. Drop it and continue
@@ -1221,9 +1232,7 @@ send_dg(res_state statp,
goto wait;
}
- if (anhp->rcode == SERVFAIL ||
- anhp->rcode == NOTIMP ||
- anhp->rcode == REFUSED) {
+ if (thisansp_error) {
next_ns:
if (recvresp1 || (buf2 != NULL && recvresp2)) {
*resplen2 = 0;
diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c
new file mode 100644
index 0000000000..cf1e39876f
--- /dev/null
+++ b/resolv/tst-resolv-short-response.c
@@ -0,0 +1,112 @@
+/* Test for spurious timeouts with short 12-byte responses (bug 31890).
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <resolv.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/check_nss.h>
+
+/* The rcode in the initial response. */
+static volatile int rcode;
+
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ switch (ctx->server_index)
+ {
+ case 0:
+ /* First server times out. */
+ struct resolv_response_flags flags = {.rcode = rcode};
+ resolv_response_init (b, flags);
+ break;
+ case 1:
+ /* Second server sends reply. */
+ resolv_response_init (b, (struct resolv_response_flags) {});
+ resolv_response_add_question (b, qname, qclass, qtype);
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, qtype, 0);
+ switch (qtype)
+ {
+ case T_A:
+ {
+ char ipv4[4] = {192, 0, 2, 17};
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+ }
+ break;
+ case T_AAAA:
+ {
+ char ipv6[16]
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+ }
+ break;
+ default:
+ FAIL_EXIT1 ("unexpected TYPE%d query", qtype);
+ }
+ resolv_response_close_record (b);
+ break;
+ default:
+ FAIL_EXIT1 ("unexpected query to server %d", ctx->server_index);
+ }
+}
+
+static void
+check_one (void)
+{
+
+ /* The buggy 1-second query timeout results in 30 seconds of delay,
+ which triggers a test timeout failure. */
+ for (int i = 0; i < 10; ++i)
+ {
+ check_hostent ("www.example", gethostbyname ("www.example"),
+ "name: www.example\n"
+ "address: 192.0.2.17\n");
+ check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6),
+ "name: www.example\n"
+ "address: 2001:db8::1\n");
+ }
+}
+
+static int
+do_test (void)
+{
+ struct resolv_test *aux = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response,
+ });
+
+ _res.options |= RES_SNGLKUP;
+
+ rcode = 2; /* SERVFAIL. */
+ check_one ();
+
+ rcode = 4; /* NOTIMP. */
+ check_one ();
+
+ rcode = 5; /* REFUSED. */
+ check_one ();
+
+ resolv_test_end (aux);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

Some files were not shown because too many files have changed in this diff Show More