diff --git a/.gitignore b/.gitignore index bef079e..930f2f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ SOURCES/glibc-2.34.tar.xz -SOURCES/glibc-upstream-2.34-373.patch diff --git a/.glibc.metadata b/.glibc.metadata index 676c0f1..8570979 100644 --- a/.glibc.metadata +++ b/.glibc.metadata @@ -1,2 +1 @@ 7c3b8890a6346793b6334cc5f2fea5d437d307b8 SOURCES/glibc-2.34.tar.xz -6022f103e5596ad229f22bc966327d71208f7016 SOURCES/glibc-upstream-2.34-373.patch diff --git a/SOURCES/glibc-RHEL-1915-1.patch b/SOURCES/glibc-RHEL-1915-1.patch new file mode 100644 index 0000000..8a5b994 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-1.patch @@ -0,0 +1,337 @@ +commit f58a8c1c15d8b5d8a08e8553f82867202b88a5cc +Author: Paul Pluzhnikov +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 + +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. diff --git a/SOURCES/glibc-RHEL-1915-2.patch b/SOURCES/glibc-RHEL-1915-2.patch new file mode 100644 index 0000000..1b24e63 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-2.patch @@ -0,0 +1,218 @@ +commit 422ed8ede312f786369e4850e47b8d32beaae4e4 +Author: Florian Weimer +Date: Fri Sep 20 13:10:54 2024 +0200 + + iconv: Base tests for buffer management + + Reviewed-by: DJ Delorie + 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 ++# . ++ ++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 >"$tmp/out" ++expect_files out-template ++ ++cp "$tmp/out-template" "$tmp/out" ++run_iconv - >"$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 diff --git a/SOURCES/glibc-RHEL-1915-3.patch b/SOURCES/glibc-RHEL-1915-3.patch new file mode 100644 index 0000000..db6e942 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-3.patch @@ -0,0 +1,91 @@ +commit 0cb64617a6f691b611406427c8e24b7f04c4983f +Author: Florian Weimer +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 + +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 + #include + #include +-#ifdef _POSIX_MAPPED_FILES +-# include +-#endif + #include + #include + #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) diff --git a/SOURCES/glibc-RHEL-1915-4.patch b/SOURCES/glibc-RHEL-1915-4.patch new file mode 100644 index 0000000..711b6db --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-4.patch @@ -0,0 +1,62 @@ +commit 00ba299787c2ea9e5c4986301e2f4965dffbfded +Author: Florian Weimer +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 + +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.} */ diff --git a/SOURCES/glibc-RHEL-1915-5.patch b/SOURCES/glibc-RHEL-1915-5.patch new file mode 100644 index 0000000..ee6b9e0 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-5.patch @@ -0,0 +1,1064 @@ +commit 6cbf845fcdc76131d0e674cee454fe738b69c69d +Author: Florian Weimer +Date: Fri Sep 20 13:10:54 2024 +0200 + + iconv: Preserve iconv -c error exit on invalid inputs (bug 32046) + + In several converters, a __GCONV_ILLEGAL_INPUT result gets overwritten + with __GCONV_FULL_OUTPUT. As a result, iconv (the function) returns + E2BIG instead of EILSEQ. The iconv program does not see the original + EILSEQ failure, does not recognize the invalid input, and may + incorrectly exit successfully. + + To address this, a new __flags bit is used to indicate a sticky input + error state. All __GCONV_ILLEGAL_INPUT results are replaced with a + function call that sets this new __GCONV_ENCOUNTERED_ILLEGAL_INPUT and + returns __GCONV_ILLEGAL_INPUT. The iconv program checks for + __GCONV_ENCOUNTERED_ILLEGAL_INPUT and overrides the exit status. + + The converter changes introducing __gconv_mark_illegal_input are + mostly mechanical, except for the res variable initialization in + iconvdata/iso-2022-jp.c: this error gets overwritten with __GCONV_OK + and other results in the following code. If res == + __GCONV_ILLEGAL_INPUT afterwards, STANDARD_TO_LOOP_ERR_HANDLER below + will handle it. + + The __gconv_mark_illegal_input changes do not alter the errno value + set by the iconv function. This is simpler to implement than + reviewing each __GCONV_FULL_OUTPUT result and adjust it not to + override a previous __GCONV_ILLEGAL_INPUT result. Doing it that way + would also change some E2BIG errors in to EILSEQ errors, so it had to + be done conditionally (under a flag set by the iconv program only), to + avoid confusing buffer management in other applications. + + Reviewed-by: DJ Delorie + +diff -Nrup a/iconv/Makefile b/iconv/Makefile +--- a/iconv/Makefile 2024-11-20 10:56:00.793668915 -0500 ++++ b/iconv/Makefile 2024-11-20 11:21:08.986113631 -0500 +@@ -57,6 +57,10 @@ tests = \ + tst-iconv-opt \ + # tests + ++tests-internal = \ ++ tst-iconv-sticky-input-error \ ++ # tests-internal ++ + others = iconv_prog iconvconfig + install-others-programs = $(inst_bindir)/iconv + install-sbin = iconvconfig +diff -Nrup a/iconv/gconv_int.h b/iconv/gconv_int.h +--- a/iconv/gconv_int.h 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconv/gconv_int.h 2024-11-20 11:11:29.577105363 -0500 +@@ -304,4 +304,34 @@ extern wint_t __gconv_btwoc_ascii (struc + + __END_DECLS + ++/* Internal extensions for . */ ++ ++/* Internal flags for __flags in struct __gconv_step_data. Overlaps ++ with flags for __gconv_open. */ ++enum ++ { ++ /* The conversion encountered an illegal input character at one ++ point. */ ++ __GCONV_ENCOUNTERED_ILLEGAL_INPUT = 1U << 30, ++ }; ++ ++/* Mark *STEP_DATA as having seen illegal input, and return ++ __GCONV_ILLEGAL_INPUT. */ ++static inline int ++__gconv_mark_illegal_input (struct __gconv_step_data *step_data) ++{ ++ step_data->__flags |= __GCONV_ENCOUNTERED_ILLEGAL_INPUT; ++ return __GCONV_ILLEGAL_INPUT; ++} ++ ++/* Returns true if any of the conversion steps encountered illegal input. */ ++static _Bool __attribute__ ((unused)) ++__gconv_has_illegal_input (__gconv_t cd) ++{ ++ for (size_t i = 0; i < cd->__nsteps; ++i) ++ if (cd->__data[i].__flags & __GCONV_ENCOUNTERED_ILLEGAL_INPUT) ++ return true; ++ return false; ++} ++ + #endif /* gconv_int.h */ +diff -Nrup a/iconv/gconv_simple.c b/iconv/gconv_simple.c +--- a/iconv/gconv_simple.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconv/gconv_simple.c 2024-11-20 11:18:28.273006314 -0500 +@@ -259,7 +259,7 @@ ucs4_internal_loop (struct __gconv_step + UCS4 does not allow such values. */ + if (irreversible == NULL) + /* We are transliterating, don't try to correct anything. */ +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + + if (flags & __GCONV_IGNORE_ERRORS) + { +@@ -270,7 +270,7 @@ ucs4_internal_loop (struct __gconv_step + + *inptrp = inptr; + *outptrp = outptr; +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + } + + *((uint32_t *) outptr) = inval; +@@ -397,7 +397,7 @@ ucs4_internal_loop_single (struct __gcon + if (!(flags & __GCONV_IGNORE_ERRORS)) + { + *inptrp -= cnt - (state->__count & 7); +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + } + } + else +@@ -629,7 +629,7 @@ ucs4le_internal_loop (struct __gconv_ste + UCS4 does not allow such values. */ + if (irreversible == NULL) + /* We are transliterating, don't try to correct anything. */ +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + + if (flags & __GCONV_IGNORE_ERRORS) + { +@@ -640,7 +640,7 @@ ucs4le_internal_loop (struct __gconv_ste + + *inptrp = inptr; + *outptrp = outptr; +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + } + + *((uint32_t *) outptr) = inval; +@@ -772,7 +772,7 @@ ucs4le_internal_loop_single (struct __gc + represent the result. This is a genuine bug in the input since + UCS4 does not allow such values. */ + if (!(flags & __GCONV_IGNORE_ERRORS)) +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + } + else + { +@@ -1218,7 +1218,7 @@ ucs4le_internal_loop_single (struct __gc + surrogates pass through, attackers could make a security \ + hole exploit by synthesizing any desired plane 1-16 \ + character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + inptr += 4; \ +@@ -1261,7 +1261,7 @@ ucs4le_internal_loop_single (struct __gc + them. (Catching this here is not security relevant.) */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + inptr += 2; \ +@@ -1310,7 +1310,7 @@ ucs4le_internal_loop_single (struct __gc + character. */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + inptr += 4; \ +diff -Nrup a/iconv/gconv_trans.c b/iconv/gconv_trans.c +--- a/iconv/gconv_trans.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconv/gconv_trans.c 2024-11-20 11:11:29.578105370 -0500 +@@ -234,6 +234,6 @@ __gconv_transliterate (struct __gconv_st + } + + /* Haven't found a match. */ +- return __GCONV_ILLEGAL_INPUT; ++ return __gconv_mark_illegal_input (step_data); + } + libc_hidden_def (__gconv_transliterate) +diff -Nrup a/iconv/iconv_prog.c b/iconv/iconv_prog.c +--- a/iconv/iconv_prog.c 2024-11-20 10:56:00.795668928 -0500 ++++ b/iconv/iconv_prog.c 2024-11-20 11:11:29.578105370 -0500 +@@ -292,6 +292,11 @@ conversions from `%s' and to `%s' are no + } + while (++remaining < argc); + ++ /* Ensure that iconv -c still exits with failure if iconv (the ++ function) has failed with E2BIG instead of EILSEQ. */ ++ if (__gconv_has_illegal_input (cd)) ++ status = EXIT_FAILURE; ++ + /* Close the output file now. */ + if (output != NULL && fclose (output)) + error (EXIT_FAILURE, errno, _("error while closing output file")); +diff -Nrup a/iconv/loop.c b/iconv/loop.c +--- a/iconv/loop.c 2024-11-20 10:56:00.242665095 -0500 ++++ b/iconv/loop.c 2024-11-20 11:11:29.578105370 -0500 +@@ -194,8 +194,7 @@ + `continue' must reach certain points. */ + #define STANDARD_FROM_LOOP_ERR_HANDLER(Incr) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ +- \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + \ +@@ -213,7 +212,7 @@ + points. */ + #define STANDARD_TO_LOOP_ERR_HANDLER(Incr) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + \ + if (irreversible == NULL) \ + /* This means we are in call from __gconv_transliterate. In this \ +diff -Nrup a/iconv/tst-iconv-sticky-input-error.c b/iconv/tst-iconv-sticky-input-error.c +--- a/iconv/tst-iconv-sticky-input-error.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/iconv/tst-iconv-sticky-input-error.c 2024-11-20 11:11:29.578105370 -0500 +@@ -0,0 +1,135 @@ ++/* Test __GCONV_ENCOUNTERED_ILLEGAL_INPUT, as used by iconv -c (bug 32046). ++ 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 ++ . */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* FROM is the input character set, TO the output character set. If ++ IGNORE is true, the iconv descriptor is set up in the same way as ++ iconv -c would. INPUT is the input string, EXPECTED_OUTPUT the ++ output. OUTPUT_LIMIT is a byte count, specifying how many input ++ bytes are passed to the iconv function on each invocation. */ ++static void ++one_direction (const char *from, const char *to, bool ignore, ++ const char *input, const char *expected_output, ++ size_t output_limit) ++{ ++ if (test_verbose) ++ { ++ char *quoted_input = support_quote_string (input); ++ char *quoted_output = support_quote_string (expected_output); ++ printf ("info: testing from=\"%s\" to=\"%s\" ignore=%d input=\"%s\"" ++ " expected_output=\"%s\" output_limit=%zu\n", ++ from, to, (int) ignore, quoted_input, ++ quoted_output, output_limit); ++ free (quoted_output); ++ free (quoted_input); ++ } ++ ++ __gconv_t cd; ++ if (ignore) ++ { ++ struct gconv_spec conv_spec; ++ TEST_VERIFY_EXIT (__gconv_create_spec (&conv_spec, from, to) ++ == &conv_spec); ++ conv_spec.ignore = true; ++ cd = (iconv_t) -1; ++ TEST_COMPARE (__gconv_open (&conv_spec, &cd, 0), __GCONV_OK); ++ __gconv_destroy_spec (&conv_spec); ++ } ++ else ++ cd = iconv_open (to, from); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ char *input_ptr = (char *) input; ++ size_t input_len = strlen (input); ++ char output_buf[20]; ++ char *output_ptr = output_buf; ++ size_t output_len; ++ do ++ { ++ output_len = array_end (output_buf) - output_ptr; ++ if (output_len > output_limit) ++ /* Limit the buffer size as requested by the caller. */ ++ output_len = output_limit; ++ TEST_VERIFY_EXIT (output_len > 0); ++ if (input_len == 0) ++ /* Trigger final flush. */ ++ input_ptr = NULL; ++ char *old_input_ptr = input_ptr; ++ size_t ret = iconv (cd, &input_ptr, &input_len, ++ &output_ptr, &output_len); ++ if (ret == (size_t) -1) ++ { ++ if (errno != EILSEQ) ++ TEST_COMPARE (errno, E2BIG); ++ } ++ ++ if (input_ptr == old_input_ptr) ++ /* Avoid endless loop if stuck on an invalid input character. */ ++ break; ++ } ++ while (input_ptr != NULL); ++ ++ /* Test the sticky illegal input bit. */ ++ TEST_VERIFY (__gconv_has_illegal_input (cd)); ++ ++ TEST_COMPARE_BLOB (expected_output, strlen (expected_output), ++ output_buf, output_ptr - output_buf); ++ ++ TEST_COMPARE (iconv_close (cd), 0); ++} ++ ++static int ++do_test (void) ++{ ++ static const char charsets[][14] = ++ { ++ "ASCII", ++ "ASCII//IGNORE", ++ "UTF-8", ++ "UTF-8//IGNORE", ++ }; ++ ++ for (size_t from_idx = 0; from_idx < array_length (charsets); ++from_idx) ++ for (size_t to_idx = 0; to_idx < array_length (charsets); ++to_idx) ++ for (int do_ignore = 0; do_ignore < 2; ++do_ignore) ++ for (int limit = 1; limit < 5; ++limit) ++ for (int skip = 0; skip < 3; ++skip) ++ { ++ const char *expected_output; ++ if (do_ignore || strstr (charsets[to_idx], "//IGNORE") != NULL) ++ expected_output = "ABXY" + skip; ++ else ++ expected_output = "AB" + skip; ++ one_direction (charsets[from_idx], charsets[to_idx], do_ignore, ++ "AB\xffXY" + skip, expected_output, limit); ++ } ++ ++ return 0; ++} ++ ++#include +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-20 10:56:00.793668915 -0500 ++++ b/iconv/tst-iconv_prog-buffer.sh 2024-11-20 11:11:29.578105370 -0500 +@@ -150,9 +150,8 @@ expect_exit 1 \ + ! 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" \ ++expect_exit 1 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 +diff -Nrup a/iconvdata/cp932.c b/iconvdata/cp932.c +--- a/iconvdata/cp932.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/cp932.c 2024-11-20 11:11:29.579105377 -0500 +@@ -4560,7 +4560,7 @@ static const char from_ucs4_extra[229][2 + if (! ignore_errors_p ()) \ + { \ + /* This is an illegal character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +@@ -4600,7 +4600,7 @@ static const char from_ucs4_extra[229][2 + if (! ignore_errors_p ()) \ + { \ + /* This is an illegal character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +@@ -4635,7 +4635,7 @@ static const char from_ucs4_extra[229][2 + if (! ignore_errors_p ()) \ + { \ + /* This is an illegal character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +diff -Nrup a/iconvdata/euc-jp-ms.c b/iconvdata/euc-jp-ms.c +--- a/iconvdata/euc-jp-ms.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/euc-jp-ms.c 2024-11-20 11:11:29.580105384 -0500 +@@ -4660,7 +4660,7 @@ static const unsigned char from_ucs4_ext + /* This is illegal. */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +@@ -4690,7 +4690,7 @@ static const unsigned char from_ucs4_ext + /* This is an illegal character. */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +@@ -4710,7 +4710,7 @@ static const unsigned char from_ucs4_ext + if (! ignore_errors_p ()) \ + { \ + /* This is an illegal character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + } \ +@@ -4821,7 +4821,7 @@ static const unsigned char from_ucs4_ext + if (! ignore_errors_p ()) \ + { \ + /* This is an illegal character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +diff -Nrup a/iconvdata/gbbig5.c b/iconvdata/gbbig5.c +--- a/iconvdata/gbbig5.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/gbbig5.c 2024-11-20 11:11:29.581105391 -0500 +@@ -4832,7 +4832,7 @@ const char __from_big5_to_gb2312 [13973] + { \ + /* We do not have a mapping for this character. \ + If ignore errors, map it to 0xa1bc - big5 box character */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + \ +@@ -4923,7 +4923,7 @@ const char __from_big5_to_gb2312 [13973] + { \ + /* We do not have a mapping for this character. \ + If ignore errors, map it to 0xa1f5 - gb box character */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + \ +diff -Nrup a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c +--- a/iconvdata/ibm1364.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/ibm1364.c 2024-11-20 11:11:29.581105391 -0500 +@@ -180,7 +180,7 @@ enum + /* This is an illegal character. */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + ++*irreversible; \ +@@ -220,7 +220,7 @@ enum + /* This is an illegal character. */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + ++*irreversible; \ +@@ -301,7 +301,7 @@ enum + \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + ++*irreversible; \ +@@ -333,7 +333,7 @@ enum + /* This is an illegal character. */ \ + if (! ignore_errors_p ()) \ + { \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + ++*irreversible; \ +diff -Nrup a/iconvdata/iso646.c b/iconvdata/iso646.c +--- a/iconvdata/iso646.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/iso646.c 2024-11-20 11:11:29.581105391 -0500 +@@ -314,7 +314,7 @@ gconv_end (struct __gconv_step *data) + ch = 0xf9; \ + else if (var == JP_OCR_B) \ + /* Illegal character. */ \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + else if (var == YU) \ + ch = 0x17e; \ + else if (var == HU) \ +@@ -388,7 +388,7 @@ gconv_end (struct __gconv_step *data) + ch = 0xec; \ + else if (var == JP_OCR_B) \ + /* Illegal character. */ \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + else if (var == YU) \ + ch = 0x10d; \ + else if (var == HU) \ +@@ -404,7 +404,7 @@ gconv_end (struct __gconv_step *data) + break; \ + case 0x80 ... 0xff: \ + /* Illegal character. */ \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + } \ + \ +@@ -441,17 +441,17 @@ gconv_end (struct __gconv_step *data) + case 0x23: \ + if (var == GB || var == ES || var == IT || var == FR || var == FR1 \ + || var == NO2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x24: \ + if (var == CN || var == HU || var == CU || var == SE || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x40: \ + if (var == CA || var == CA2 || var == DE || var == ES || var == ES2 \ + || var == IT || var == YU || var == HU || var == FR || var == FR1 \ + || var == PT || var == PT2 || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x5b: \ + if (var == CA || var == CA2 || var == DE || var == DK || var == ES \ +@@ -459,7 +459,7 @@ gconv_end (struct __gconv_step *data) + || var == HU || var == FR || var == FR1 || var == NO \ + || var == NO2 || var == PT || var == PT2 || var == SE \ + || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + else if (var == CU) \ + ch = 0x7d; \ + break; \ +@@ -469,7 +469,7 @@ gconv_end (struct __gconv_step *data) + || var == YU || var == KR || var == HU || var == CU || var == FR \ + || var == FR1 || var == NO || var == NO2 || var == PT \ + || var == PT2 || var == SE || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x5d: \ + if (var == CA || var == CA2 || var == DE || var == DK || var == ES \ +@@ -477,17 +477,17 @@ gconv_end (struct __gconv_step *data) + || var == HU || var == FR || var == FR1 || var == NO \ + || var == NO2 || var == PT || var == PT2 || var == SE \ + || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x5e: \ + if (var == CA || var == CA2 || var == ES2 || var == YU || var == CU \ + || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x60: \ + if (var == CA || var == CA2 || var == IT || var == JP_OCR_B \ + || var == YU || var == HU || var == FR || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x7b: \ + if (var == CA || var == CA2 || var == DE || var == DK || var == ES \ +@@ -495,14 +495,14 @@ gconv_end (struct __gconv_step *data) + || var == CU || var == FR || var == FR1 || var == NO \ + || var == NO2 || var == PT || var == PT2 || var == SE \ + || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x7c: \ + if (var == CA || var == CA2 || var == DE || var == DK || var == ES \ + || var == ES2 || var == IT || var == YU || var == HU || var == CU \ + || var == FR || var == FR1 || var == NO || var == PT \ + || var == PT2 || var == SE || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + else if (var == NO2) \ + ch = 0x7e; \ + break; \ +@@ -511,7 +511,7 @@ gconv_end (struct __gconv_step *data) + || var == ES2 || var == IT || var == YU || var == HU || var == CU \ + || var == FR || var == FR1 || var == NO || var == NO2 \ + || var == PT || var == PT2 || var == SE || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x7e: \ + if (var == GB || var == CA || var == CA2 || var == DE || var == ES2 \ +@@ -519,21 +519,21 @@ gconv_end (struct __gconv_step *data) + || var == YU || var == HU || var == CU || var == FR || var == FR1 \ + || var == NO || var == NO2 || var == PT || var == SE \ + || var == SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xa1: \ + if (var != ES && var != ES2 && var != CU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0xa3: \ + if (var != GB && var != ES && var != IT && var != FR && var != FR1) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x23; \ + break; \ + case 0xa4: \ + if (var != HU && var != CU && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x24; \ + break; \ + case 0xa5: \ +@@ -542,7 +542,7 @@ gconv_end (struct __gconv_step *data) + else if (var == JP || var == JP_OCR_B) \ + ch = 0x5c; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xa7: \ + if (var == DE || var == ES || var == IT || var == PT) \ +@@ -552,11 +552,11 @@ gconv_end (struct __gconv_step *data) + else if (var == NO2) \ + ch = 0x23; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xa8: \ + if (var != ES2 && var != CU && var != FR && var != FR1) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0xb0: \ +@@ -567,7 +567,7 @@ gconv_end (struct __gconv_step *data) + else if (var == PT) \ + ch = 0x7e; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xb4: \ + if (var == ES2 || var == CU) \ +@@ -575,11 +575,11 @@ gconv_end (struct __gconv_step *data) + else if (var == PT2) \ + ch = 0x40; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xb5: \ + if (var != FR) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x60; \ + break; \ + case 0xbf: \ +@@ -588,31 +588,31 @@ gconv_end (struct __gconv_step *data) + else if (var == ES2 || var == CU) \ + ch = 0x5e; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xc1: \ + if (var != HU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x40; \ + break; \ + case 0xc3: \ + if (var != PT && var != PT2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0xc4: \ + if (var != DE && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0xc5: \ + if (var != DK && var != NO && var != NO2 && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5d; \ + break; \ + case 0xc6: \ + if (var != DK && var != NO && var != NO2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0xc7: \ +@@ -621,7 +621,7 @@ gconv_end (struct __gconv_step *data) + else if (var == PT || var == PT2) \ + ch = 0x5c; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xc9: \ + if (var == CA2) \ +@@ -631,26 +631,26 @@ gconv_end (struct __gconv_step *data) + else if (var == SE2) \ + ch = 0x40; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xd1: \ + if (var != ES && var != ES2 && var != CU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5c; \ + break; \ + case 0xd5: \ + if (var != PT && var != PT2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5d; \ + break; \ + case 0xd6: \ + if (var != DE && var != HU && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5c; \ + break; \ + case 0xd8: \ + if (var != DK && var != NO && var != NO2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5c; \ + break; \ + case 0xdc: \ +@@ -659,11 +659,11 @@ gconv_end (struct __gconv_step *data) + else if (var == SE2) \ + ch = 0x5e; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xdf: \ + if (var != DE) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0xe0: \ +@@ -672,36 +672,36 @@ gconv_end (struct __gconv_step *data) + else if (var == IT) \ + ch = 0x7b; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xe1: \ + if (var != HU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x60; \ + break; \ + case 0xe2: \ + if (var != CA && var != CA2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0xe3: \ + if (var != PT && var != PT2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7b; \ + break; \ + case 0xe4: \ + if (var != DE && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7b; \ + break; \ + case 0xe5: \ + if (var != DK && var != NO && var != NO2 && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7d; \ + break; \ + case 0xe6: \ + if (var != DK && var != NO && var != NO2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7b; \ + break; \ + case 0xe7: \ +@@ -712,11 +712,11 @@ gconv_end (struct __gconv_step *data) + else if (var == PT || var == PT2) \ + ch = 0x7c; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xe8: \ + if (var != CA && var != CA2 && var != IT && var != FR && var != FR1) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7d; \ + break; \ + case 0xe9: \ +@@ -727,51 +727,51 @@ gconv_end (struct __gconv_step *data) + else if (var == SE2) \ + ch = 0x60; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xea: \ + if (var != CA && var != CA2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5d; \ + break; \ + case 0xec: \ + if (var != IT) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0xee: \ + if (var != CA) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5e; \ + break; \ + case 0xf1: \ + if (var != ES && var != ES2 && var != CU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7c; \ + break; \ + case 0xf2: \ + if (var != IT) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7c; \ + break; \ + case 0xf4: \ + if (var != CA && var != CA2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x60; \ + break; \ + case 0xf5: \ + if (var != PT && var != PT2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7d; \ + break; \ + case 0xf6: \ + if (var != DE && var != HU && var != SE && var != SE2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7c; \ + break; \ + case 0xf8: \ + if (var != DK && var != NO && var != NO2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7c; \ + break; \ + case 0xf9: \ +@@ -780,11 +780,11 @@ gconv_end (struct __gconv_step *data) + else if (var == IT) \ + ch = 0x60; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0xfb: \ + if (var != CA && var != CA2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0xfc: \ +@@ -793,93 +793,93 @@ gconv_end (struct __gconv_step *data) + else if (var == SE2) \ + ch = 0x7e; \ + else \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + break; \ + case 0x160: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0x106: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5d; \ + break; \ + case 0x107: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7d; \ + break; \ + case 0x10c: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5e; \ + break; \ + case 0x10d: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0x110: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5c; \ + break; \ + case 0x111: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7c; \ + break; \ + case 0x161: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7b; \ + break; \ + case 0x17d: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x40; \ + break; \ + case 0x17e: \ + if (var != YU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x60; \ + break; \ + case 0x2dd: \ + if (var != HU) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0x2022: \ + if (var != ES2) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x40; \ + break; \ + case 0x203e: \ + if (var != GB && var != CN && var != JP && var != NO && var != SE) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x7e; \ + break; \ + case 0x20a9: \ + if (var != KR) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5c; \ + break; \ + case 0x2329: \ + if (var != JP_OCR_B) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5b; \ + break; \ + case 0x232a: \ + if (var != JP_OCR_B) \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + ch = 0x5d; \ + break; \ + default: \ + if (__glibc_unlikely (ch > 0x7f)) \ + { \ + UNICODE_TAG_HANDLER (ch, 4); \ +- failure = __GCONV_ILLEGAL_INPUT; \ ++ failure = __gconv_mark_illegal_input (step_data); \ + } \ + break; \ + } \ +diff -Nrup a/iconvdata/unicode.c b/iconvdata/unicode.c +--- a/iconvdata/unicode.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/unicode.c 2024-11-20 11:11:29.582105398 -0500 +@@ -164,7 +164,7 @@ gconv_end (struct __gconv_step *data) + surrogates pass through, attackers could make a security \ + hole exploit by synthesizing any desired plane 1-16 \ + character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + inptr += 4; \ +diff -Nrup a/iconvdata/utf-16.c b/iconvdata/utf-16.c +--- a/iconvdata/utf-16.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/utf-16.c 2024-11-20 11:11:29.582105398 -0500 +@@ -207,7 +207,7 @@ gconv_end (struct __gconv_step *data) + We must catch this. If we let surrogates pass through, \ + attackers could make a security hole exploit by \ + synthesizing any desired plane 1-16 character. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + inptr += 4; \ +diff -Nrup a/iconvdata/utf-32.c b/iconvdata/utf-32.c +--- a/iconvdata/utf-32.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/iconvdata/utf-32.c 2024-11-20 11:11:29.582105398 -0500 +@@ -207,7 +207,7 @@ gconv_end (struct __gconv_step *data) + We must catch this. If we let surrogates pass through, \ + attackers could make a security hole exploit by \ + generating "irregular UTF-32" sequences. */ \ +- result = __GCONV_ILLEGAL_INPUT; \ ++ result = __gconv_mark_illegal_input (step_data); \ + if (! ignore_errors_p ()) \ + break; \ + inptr += 4; \ diff --git a/SOURCES/glibc-RHEL-1915-6.patch b/SOURCES/glibc-RHEL-1915-6.patch new file mode 100644 index 0000000..d70b98c --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-6.patch @@ -0,0 +1,715 @@ +commit 8ef3cff9d1ceafe369f982d980678d749fb93bd2 +Author: Florian Weimer +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 + + 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, ¤t_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 + # . + ++# 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" "$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" diff --git a/SOURCES/glibc-RHEL-1915-7.patch b/SOURCES/glibc-RHEL-1915-7.patch new file mode 100644 index 0000000..d3b62f0 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-7.patch @@ -0,0 +1,41 @@ +commit 75819cdd29a193cc2db980878bec305905b22bbc +Author: Florian Weimer +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 + +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 diff --git a/SOURCES/glibc-RHEL-1915-8.patch b/SOURCES/glibc-RHEL-1915-8.patch new file mode 100644 index 0000000..823cc16 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-8.patch @@ -0,0 +1,323 @@ +commit fa1b0d5e9f6e0353e16339430770a7a8824c0468 +Author: Florian Weimer +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 + +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 <&$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 diff --git a/SOURCES/glibc-RHEL-1915-9.patch b/SOURCES/glibc-RHEL-1915-9.patch new file mode 100644 index 0000000..c1828f7 --- /dev/null +++ b/SOURCES/glibc-RHEL-1915-9.patch @@ -0,0 +1,37 @@ +commit 079ebf7624e7fd0ad7fe94a7176a2e132c996d86 +Author: Florian Weimer +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 + +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) diff --git a/SOURCES/glibc-RHEL-2419-1.patch b/SOURCES/glibc-RHEL-2419-1.patch new file mode 100644 index 0000000..932bd01 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-1.patch @@ -0,0 +1,447 @@ +commit 1db84775f831a1494993ce9c118deaf9537cc50a +Author: Frank Barrus +Date: Wed Dec 4 07:55:02 2024 -0500 + + pthreads NPTL: lost wakeup fix 2 + + This fixes the lost wakeup (from a bug in signal stealing) with a change + in the usage of g_signals[] in the condition variable internal state. + It also completely eliminates the concept and handling of signal stealing, + as well as the need for signalers to block to wait for waiters to wake + up every time there is a G1/G2 switch. This greatly reduces the average + and maximum latency for pthread_cond_signal. + + The g_signals[] field now contains a signal count that is relative to + the current g1_start value. Since it is a 32-bit field, and the LSB is + still reserved (though not currently used anymore), it has a 31-bit value + that corresponds to the low 31 bits of the sequence number in g1_start. + (since g1_start also has an LSB flag, this means bits 31:1 in g_signals + correspond to bits 31:1 in g1_start, plus the current signal count) + + By making the signal count relative to g1_start, there is no longer + any ambiguity or A/B/A issue, and thus any checks before blocking, + including the futex call itself, are guaranteed not to block if the G1/G2 + switch occurs, even if the signal count remains the same. This allows + initially safely blocking in G2 until the switch to G1 occurs, and + then transitioning from G1 to a new G1 or G2, and always being able to + distinguish the state change. This removes the race condition and A/B/A + problems that otherwise ocurred if a late (pre-empted) waiter were to + resume just as the futex call attempted to block on g_signal since + otherwise there was no last opportunity to re-check things like whether + the current G1 group was already closed. + + By fixing these issues, the signal stealing code can be eliminated, + since there is no concept of signal stealing anymore. The code to block + for all waiters to exit g_refs can also be removed, since any waiters + that are still in the g_refs region can be guaranteed to safely wake + up and exit. If there are still any left at this time, they are all + sent one final futex wakeup to ensure that they are not blocked any + longer, but there is no need for the signaller to block and wait for + them to wake up and exit the g_refs region. + + The signal count is then effectively "zeroed" but since it is now + relative to g1_start, this is done by advancing it to a new value that + can be observed by any pending blocking waiters. Any late waiters can + always tell the difference, and can thus just cleanly exit if they are + in a stale G1 or G2. They can never steal a signal from the current + G1 if they are not in the current G1, since the signal value that has + to match in the cmpxchg has the low 31 bits of the g1_start value + contained in it, and that's first checked, and then it won't match if + there's a G1/G2 change. + + Note: the 31-bit sequence number used in g_signals is designed to + handle wrap-around when checking the signal count, but if the entire + 31-bit wraparound (2 billion signals) occurs while there is still a + late waiter that has not yet resumed, and it happens to then match + the current g1_start low bits, and the pre-emption occurs after the + normal "closed group" checks (which are 64-bit) but then hits the + futex syscall and signal consuming code, then an A/B/A issue could + still result and cause an incorrect assumption about whether it + should block. This particular scenario seems unlikely in practice. + Note that once awake from the futex, the waiter would notice the + closed group before consuming the signal (since that's still a 64-bit + check that would not be aliased in the wrap-around in g_signals), + so the biggest impact would be blocking on the futex until the next + full wakeup from a G1/G2 switch. + + Signed-off-by: Frank Barrus + Reviewed-by: Carlos O'Donell + +# Conflicts: +# nptl/pthread_cond_common.c (Missing spelling fixes) +# nptl/pthread_cond_wait.c (Likewise) + +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index c35b9ef03afd2c64..b1565b780d175d3a 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -341,7 +341,6 @@ static bool __attribute__ ((unused)) + __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + unsigned int *g1index, int private) + { +- const unsigned int maxspin = 0; + unsigned int g1 = *g1index; + + /* If there is no waiter in G2, we don't do anything. The expression may +@@ -362,84 +361,46 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + * New waiters arriving concurrently with the group switching will all go + into G2 until we atomically make the switch. Waiters existing in G2 + are not affected. +- * Waiters in G1 will be closed out immediately by setting a flag in +- __g_signals, which will prevent waiters from blocking using a futex on +- __g_signals and also notifies them that the group is closed. As a +- result, they will eventually remove their group reference, allowing us +- to close switch group roles. */ +- +- /* First, set the closed flag on __g_signals. This tells waiters that are +- about to wait that they shouldn't do that anymore. This basically +- serves as an advance notificaton of the upcoming change to __g1_start; +- waiters interpret it as if __g1_start was larger than their waiter +- sequence position. This allows us to change __g1_start after waiting +- for all existing waiters with group references to leave, which in turn +- makes recovery after stealing a signal simpler because it then can be +- skipped if __g1_start indicates that the group is closed (otherwise, +- we would have to recover always because waiters don't know how big their +- groups are). Relaxed MO is fine. */ +- atomic_fetch_or_relaxed (cond->__data.__g_signals + g1, 1); +- +- /* Wait until there are no group references anymore. The fetch-or operation +- injects us into the modification order of __g_refs; release MO ensures +- that waiters incrementing __g_refs after our fetch-or see the previous +- changes to __g_signals and to __g1_start that had to happen before we can +- switch this G1 and alias with an older group (we have two groups, so +- aliasing requires switching group roles twice). Note that nobody else +- can have set the wake-request flag, so we do not have to act upon it. +- +- Also note that it is harmless if older waiters or waiters from this G1 +- get a group reference after we have quiesced the group because it will +- remain closed for them either because of the closed flag in __g_signals +- or the later update to __g1_start. New waiters will never arrive here +- but instead continue to go into the still current G2. */ +- unsigned r = atomic_fetch_or_release (cond->__data.__g_refs + g1, 0); +- while ((r >> 1) > 0) +- { +- for (unsigned int spin = maxspin; ((r >> 1) > 0) && (spin > 0); spin--) +- { +- /* TODO Back off. */ +- r = atomic_load_relaxed (cond->__data.__g_refs + g1); +- } +- if ((r >> 1) > 0) +- { +- /* There is still a waiter after spinning. Set the wake-request +- flag and block. Relaxed MO is fine because this is just about +- this futex word. +- +- Update r to include the set wake-request flag so that the upcoming +- futex_wait only blocks if the flag is still set (otherwise, we'd +- violate the basic client-side futex protocol). */ +- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1; +- +- if ((r >> 1) > 0) +- futex_wait_simple (cond->__data.__g_refs + g1, r, private); +- /* Reload here so we eventually see the most recent value even if we +- do not spin. */ +- r = atomic_load_relaxed (cond->__data.__g_refs + g1); +- } +- } +- /* Acquire MO so that we synchronize with the release operation that waiters +- use to decrement __g_refs and thus happen after the waiters we waited +- for. */ +- atomic_thread_fence_acquire (); ++ * Waiters in G1 will be closed out immediately by the advancing of ++ __g_signals to the next "lowseq" (low 31 bits of the new g1_start), ++ which will prevent waiters from blocking using a futex on ++ __g_signals since it provides enough signals for all possible ++ remaining waiters. As a result, they can each consume a signal ++ and they will eventually remove their group reference. */ + + /* Update __g1_start, which finishes closing this group. The value we add + will never be negative because old_orig_size can only be zero when we + switch groups the first time after a condvar was initialized, in which +- case G1 will be at index 1 and we will add a value of 1. See above for +- why this takes place after waiting for quiescence of the group. ++ case G1 will be at index 1 and we will add a value of 1. + Relaxed MO is fine because the change comes with no additional + constraints that others would have to observe. */ + __condvar_add_g1_start_relaxed (cond, + (old_orig_size << 1) + (g1 == 1 ? 1 : - 1)); + +- /* Now reopen the group, thus enabling waiters to again block using the +- futex controlled by __g_signals. Release MO so that observers that see +- no signals (and thus can block) also see the write __g1_start and thus +- that this is now a new group (see __pthread_cond_wait_common for the +- matching acquire MO loads). */ +- atomic_store_release (cond->__data.__g_signals + g1, 0); ++ unsigned int lowseq = ((old_g1_start + old_orig_size) << 1) & ~1U; ++ ++ /* If any waiters still hold group references (and thus could be blocked), ++ then wake them all up now and prevent any running ones from blocking. ++ This is effectively a catch-all for any possible current or future ++ bugs that can allow the group size to reach 0 before all G1 waiters ++ have been awakened or at least given signals to consume, or any ++ other case that can leave blocked (or about to block) older waiters.. */ ++ if ((atomic_fetch_or_release (cond->__data.__g_refs + g1, 0) >> 1) > 0) ++ { ++ /* First advance signals to the end of the group (i.e. enough signals ++ for the entire G1 group) to ensure that waiters which have not ++ yet blocked in the futex will not block. ++ Note that in the vast majority of cases, this should never ++ actually be necessary, since __g_signals will have enough ++ signals for the remaining g_refs waiters. As an optimization, ++ we could check this first before proceeding, although that ++ could still leave the potential for futex lost wakeup bugs ++ if the signal count was non-zero but the futex wakeup ++ was somehow lost. */ ++ atomic_store_release (cond->__data.__g_signals + g1, lowseq); ++ ++ futex_wake (cond->__data.__g_signals + g1, INT_MAX, private); ++ } + + /* At this point, the old G1 is now a valid new G2 (but not in use yet). + No old waiter can neither grab a signal nor acquire a reference without +@@ -451,6 +412,10 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + g1 ^= 1; + *g1index ^= 1; + ++ /* Now advance the new G1 g_signals to the new lowseq, giving it ++ an effective signal count of 0 to start. */ ++ atomic_store_release (cond->__data.__g_signals + g1, lowseq); ++ + /* These values are just observed by signalers, and thus protected by the + lock. */ + unsigned int orig_size = wseq - (old_g1_start + old_orig_size); +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index dc8c511f1a72517a..c34280c6bc9e80fb 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -239,9 +239,7 @@ __condvar_cleanup_waiting (void *arg) + signaled), and a reference count. + + The group reference count is used to maintain the number of waiters that +- are using the group's futex. Before a group can change its role, the +- reference count must show that no waiters are using the futex anymore; this +- prevents ABA issues on the futex word. ++ are using the group's futex. + + To represent which intervals in the waiter sequence the groups cover (and + thus also which group slot contains G1 or G2), we use a 64b counter to +@@ -301,11 +299,12 @@ __condvar_cleanup_waiting (void *arg) + last reference. + * Reference count used by waiters concurrently with signalers that have + acquired the condvar-internal lock. +- __g_signals: The number of signals that can still be consumed. ++ __g_signals: The number of signals that can still be consumed, relative to ++ the current g1_start. (i.e. bits 31 to 1 of __g_signals are bits ++ 31 to 1 of g1_start with the signal count added) + * Used as a futex word by waiters. Used concurrently by waiters and + signalers. +- * LSB is true iff this group has been completely signaled (i.e., it is +- closed). ++ * LSB is currently reserved and 0. + __g_size: Waiters remaining in this group (i.e., which have not been + signaled yet. + * Accessed by signalers and waiters that cancel waiting (both do so only +@@ -329,18 +328,6 @@ __condvar_cleanup_waiting (void *arg) + sufficient because if a waiter can see a sufficiently large value, it could + have also consume a signal in the waiters group. + +- Waiters try to grab a signal from __g_signals without holding a reference +- count, which can lead to stealing a signal from a more recent group after +- their own group was already closed. They cannot always detect whether they +- in fact did because they do not know when they stole, but they can +- conservatively add a signal back to the group they stole from; if they +- did so unnecessarily, all that happens is a spurious wake-up. To make this +- even less likely, __g1_start contains the index of the current g2 too, +- which allows waiters to check if there aliasing on the group slots; if +- there wasn't, they didn't steal from the current G1, which means that the +- G1 they stole from must have been already closed and they do not need to +- fix anything. +- + It is essential that the last field in pthread_cond_t is __g_signals[1]: + The previous condvar used a pointer-sized field in pthread_cond_t, so a + PTHREAD_COND_INITIALIZER from that condvar implementation might only +@@ -436,6 +423,9 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + { + while (1) + { ++ uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); ++ unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; ++ + /* Spin-wait first. + Note that spinning first without checking whether a timeout + passed might lead to what looks like a spurious wake-up even +@@ -447,35 +437,45 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + having to compare against the current time seems to be the right + choice from a performance perspective for most use cases. */ + unsigned int spin = maxspin; +- while (signals == 0 && spin > 0) ++ while (spin > 0 && ((int)(signals - lowseq) < 2)) + { + /* Check that we are not spinning on a group that's already + closed. */ +- if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1)) +- goto done; ++ if (seq < (g1_start >> 1)) ++ break; + + /* TODO Back off. */ + + /* Reload signals. See above for MO. */ + signals = atomic_load_acquire (cond->__data.__g_signals + g); ++ g1_start = __condvar_load_g1_start_relaxed (cond); ++ lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + spin--; + } + +- /* If our group will be closed as indicated by the flag on signals, +- don't bother grabbing a signal. */ +- if (signals & 1) +- goto done; +- +- /* If there is an available signal, don't block. */ +- if (signals != 0) ++ if (seq < (g1_start >> 1)) ++ { ++ /* If the group is closed already, ++ then this waiter originally had enough extra signals to ++ consume, up until the time its group was closed. */ ++ goto done; ++ } ++ ++ /* If there is an available signal, don't block. ++ If __g1_start has advanced at all, then we must be in G1 ++ by now, perhaps in the process of switching back to an older ++ G2, but in either case we're allowed to consume the available ++ signal and should not block anymore. */ ++ if ((int)(signals - lowseq) >= 2) + break; + + /* No signals available after spinning, so prepare to block. + We first acquire a group reference and use acquire MO for that so + that we synchronize with the dummy read-modify-write in + __condvar_quiesce_and_switch_g1 if we read from that. In turn, +- in this case this will make us see the closed flag on __g_signals +- that designates a concurrent attempt to reuse the group's slot. ++ in this case this will make us see the advancement of __g_signals ++ to the upcoming new g1_start that occurs with a concurrent ++ attempt to reuse the group's slot. + We use acquire MO for the __g_signals check to make the + __g1_start check work (see spinning above). + Note that the group reference acquisition will not mask the +@@ -483,15 +483,24 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + an atomic read-modify-write operation and thus extend the release + sequence. */ + atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2); +- if (((atomic_load_acquire (cond->__data.__g_signals + g) & 1) != 0) +- || (seq < (__condvar_load_g1_start_relaxed (cond) >> 1))) ++ signals = atomic_load_acquire (cond->__data.__g_signals + g); ++ g1_start = __condvar_load_g1_start_relaxed (cond); ++ lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; ++ ++ if (seq < (g1_start >> 1)) + { +- /* Our group is closed. Wake up any signalers that might be +- waiting. */ ++ /* group is closed already, so don't block */ + __condvar_dec_grefs (cond, g, private); + goto done; + } + ++ if ((int)(signals - lowseq) >= 2) ++ { ++ /* a signal showed up or G1/G2 switched after we grabbed the refcount */ ++ __condvar_dec_grefs (cond, g, private); ++ break; ++ } ++ + // Now block. + struct _pthread_cleanup_buffer buffer; + struct _condvar_cleanup_buffer cbuffer; +@@ -502,7 +511,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + __pthread_cleanup_push (&buffer, __condvar_cleanup_waiting, &cbuffer); + + err = __futex_abstimed_wait_cancelable64 ( +- cond->__data.__g_signals + g, 0, clockid, abstime, private); ++ cond->__data.__g_signals + g, signals, clockid, abstime, private); + + __pthread_cleanup_pop (&buffer, 0); + +@@ -525,6 +534,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + signals = atomic_load_acquire (cond->__data.__g_signals + g); + } + ++ if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1)) ++ goto done; + } + /* Try to grab a signal. Use acquire MO so that we see an up-to-date value + of __g1_start below (see spinning above for a similar case). In +@@ -533,69 +544,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g, + &signals, signals - 2)); + +- /* We consumed a signal but we could have consumed from a more recent group +- that aliased with ours due to being in the same group slot. If this +- might be the case our group must be closed as visible through +- __g1_start. */ +- uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); +- if (seq < (g1_start >> 1)) +- { +- /* We potentially stole a signal from a more recent group but we do not +- know which group we really consumed from. +- We do not care about groups older than current G1 because they are +- closed; we could have stolen from these, but then we just add a +- spurious wake-up for the current groups. +- We will never steal a signal from current G2 that was really intended +- for G2 because G2 never receives signals (until it becomes G1). We +- could have stolen a signal from G2 that was conservatively added by a +- previous waiter that also thought it stole a signal -- but given that +- that signal was added unnecessarily, it's not a problem if we steal +- it. +- Thus, the remaining case is that we could have stolen from the current +- G1, where "current" means the __g1_start value we observed. However, +- if the current G1 does not have the same slot index as we do, we did +- not steal from it and do not need to undo that. This is the reason +- for putting a bit with G2's index into__g1_start as well. */ +- if (((g1_start & 1) ^ 1) == g) +- { +- /* We have to conservatively undo our potential mistake of stealing +- a signal. We can stop trying to do that when the current G1 +- changes because other spinning waiters will notice this too and +- __condvar_quiesce_and_switch_g1 has checked that there are no +- futex waiters anymore before switching G1. +- Relaxed MO is fine for the __g1_start load because we need to +- merely be able to observe this fact and not have to observe +- something else as well. +- ??? Would it help to spin for a little while to see whether the +- current G1 gets closed? This might be worthwhile if the group is +- small or close to being closed. */ +- unsigned int s = atomic_load_relaxed (cond->__data.__g_signals + g); +- while (__condvar_load_g1_start_relaxed (cond) == g1_start) +- { +- /* Try to add a signal. We don't need to acquire the lock +- because at worst we can cause a spurious wake-up. If the +- group is in the process of being closed (LSB is true), this +- has an effect similar to us adding a signal. */ +- if (((s & 1) != 0) +- || atomic_compare_exchange_weak_relaxed +- (cond->__data.__g_signals + g, &s, s + 2)) +- { +- /* If we added a signal, we also need to add a wake-up on +- the futex. We also need to do that if we skipped adding +- a signal because the group is being closed because +- while __condvar_quiesce_and_switch_g1 could have closed +- the group, it might stil be waiting for futex waiters to +- leave (and one of those waiters might be the one we stole +- the signal from, which cause it to block using the +- futex). */ +- futex_wake (cond->__data.__g_signals + g, 1, private); +- break; +- } +- /* TODO Back off. */ +- } +- } +- } +- + done: + + /* Confirm that we have been woken. We do that before acquiring the mutex diff --git a/SOURCES/glibc-RHEL-2419-10.patch b/SOURCES/glibc-RHEL-2419-10.patch new file mode 100644 index 0000000..e0481ce --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-10.patch @@ -0,0 +1,39 @@ +Partial revert of commit c36fc50781995e6758cae2b6927839d0157f213c +to restore the layout of pthread_cond_t and avoid a downstream +rpminspect and abidiff (libabigail tooling) spurious warning +about internal ABI changes. Without this change all RHEL developers +using pthread_cond_t would have to audit and waive the warning. +The alternative is to update the supression lists used in abidiff, +propagate that to the rpminspect service, and wait for that to +complete before doing the update. The more conservative position +is the partial revert of the layout change. + +This is a downstream-only change and is not required upstream. + +diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h +index 5cd33b765d9689eb..5644472323fe5424 100644 +--- a/sysdeps/nptl/bits/thread-shared-types.h ++++ b/sysdeps/nptl/bits/thread-shared-types.h +@@ -109,7 +109,8 @@ struct __pthread_cond_s + unsigned int __high; + } __g1_start32; + }; +- unsigned int __g_size[2] __LOCK_ALIGNMENT; ++ unsigned int __glibc_unused___g_refs[2] __LOCK_ALIGNMENT; ++ unsigned int __g_size[2]; + unsigned int __g1_orig_size; + unsigned int __wrefs; + unsigned int __g_signals[2]; +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index 7ea6001784783371..43146e91c9d9579b 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -152,7 +152,7 @@ enum + + + /* Conditional variable handling. */ +-#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, 0, 0, {0, 0} } } ++#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } } + + + /* Cleanup buffers */ diff --git a/SOURCES/glibc-RHEL-2419-2.patch b/SOURCES/glibc-RHEL-2419-2.patch new file mode 100644 index 0000000..99e7873 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-2.patch @@ -0,0 +1,133 @@ +commit 0cc973160c23bb67f895bc887dd6942d29f8fee3 +Author: Malte Skarupke +Date: Wed Dec 4 07:55:22 2024 -0500 + + nptl: Update comments and indentation for new condvar implementation + + Some comments were wrong after the most recent commit. This fixes that. + + Also fixing indentation where it was using spaces instead of tabs. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index b1565b780d175d3a..b355e38fb57862b1 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -361,8 +361,9 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + * New waiters arriving concurrently with the group switching will all go + into G2 until we atomically make the switch. Waiters existing in G2 + are not affected. +- * Waiters in G1 will be closed out immediately by the advancing of +- __g_signals to the next "lowseq" (low 31 bits of the new g1_start), ++ * Waiters in G1 have already received a signal and been woken. If they ++ haven't woken yet, they will be closed out immediately by the advancing ++ of __g_signals to the next "lowseq" (low 31 bits of the new g1_start), + which will prevent waiters from blocking using a futex on + __g_signals since it provides enough signals for all possible + remaining waiters. As a result, they can each consume a signal +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index c34280c6bc9e80fb..7dabcb15d2d818e7 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -250,7 +250,7 @@ __condvar_cleanup_waiting (void *arg) + figure out whether they are in a group that has already been completely + signaled (i.e., if the current G1 starts at a later position that the + waiter's position). Waiters cannot determine whether they are currently +- in G2 or G1 -- but they do not have too because all they are interested in ++ in G2 or G1 -- but they do not have to because all they are interested in + is whether there are available signals, and they always start in G2 (whose + group slot they know because of the bit in the waiter sequence. Signalers + will simply fill the right group until it is completely signaled and can +@@ -413,7 +413,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + } + + /* Now wait until a signal is available in our group or it is closed. +- Acquire MO so that if we observe a value of zero written after group ++ Acquire MO so that if we observe (signals == lowseq) after group + switching in __condvar_quiesce_and_switch_g1, we synchronize with that + store and will see the prior update of __g1_start done while switching + groups too. */ +@@ -423,8 +423,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + { + while (1) + { +- uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); +- unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; ++ uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); ++ unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + + /* Spin-wait first. + Note that spinning first without checking whether a timeout +@@ -448,21 +448,21 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + + /* Reload signals. See above for MO. */ + signals = atomic_load_acquire (cond->__data.__g_signals + g); +- g1_start = __condvar_load_g1_start_relaxed (cond); +- lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; ++ g1_start = __condvar_load_g1_start_relaxed (cond); ++ lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + spin--; + } + +- if (seq < (g1_start >> 1)) ++ if (seq < (g1_start >> 1)) + { +- /* If the group is closed already, ++ /* If the group is closed already, + then this waiter originally had enough extra signals to + consume, up until the time its group was closed. */ + goto done; +- } ++ } + + /* If there is an available signal, don't block. +- If __g1_start has advanced at all, then we must be in G1 ++ If __g1_start has advanced at all, then we must be in G1 + by now, perhaps in the process of switching back to an older + G2, but in either case we're allowed to consume the available + signal and should not block anymore. */ +@@ -484,22 +484,23 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + sequence. */ + atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2); + signals = atomic_load_acquire (cond->__data.__g_signals + g); +- g1_start = __condvar_load_g1_start_relaxed (cond); +- lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; ++ g1_start = __condvar_load_g1_start_relaxed (cond); ++ lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + +- if (seq < (g1_start >> 1)) ++ if (seq < (g1_start >> 1)) + { +- /* group is closed already, so don't block */ ++ /* group is closed already, so don't block */ + __condvar_dec_grefs (cond, g, private); + goto done; + } + + if ((int)(signals - lowseq) >= 2) + { +- /* a signal showed up or G1/G2 switched after we grabbed the refcount */ ++ /* a signal showed up or G1/G2 switched after we grabbed the ++ refcount */ + __condvar_dec_grefs (cond, g, private); + break; +- } ++ } + + // Now block. + struct _pthread_cleanup_buffer buffer; +@@ -537,10 +538,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1)) + goto done; + } +- /* Try to grab a signal. Use acquire MO so that we see an up-to-date value +- of __g1_start below (see spinning above for a similar case). In +- particular, if we steal from a more recent group, we will also see a +- more recent __g1_start below. */ ++ /* Try to grab a signal. See above for MO. (if we do another loop ++ iteration we need to see the correct value of g1_start) */ + while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g, + &signals, signals - 2)); + diff --git a/SOURCES/glibc-RHEL-2419-3.patch b/SOURCES/glibc-RHEL-2419-3.patch new file mode 100644 index 0000000..00456d2 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-3.patch @@ -0,0 +1,67 @@ +commit b42cc6af11062c260c7dfa91f1c89891366fed3e +Author: Malte Skarupke +Date: Wed Dec 4 07:55:50 2024 -0500 + + nptl: Remove unnecessary catch-all-wake in condvar group switch + + This wake is unnecessary. We only switch groups after every sleeper in a group + has been woken. Sure, they may take a while to actually wake up and may still + hold a reference, but waking them a second time doesn't speed that up. Instead + this just makes the code more complicated and may hide problems. + + In particular this safety wake wouldn't even have helped with the bug that was + fixed by Barrus' patch: The bug there was that pthread_cond_signal would not + switch g1 when it should, so we wouldn't even have entered this code path. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index b355e38fb57862b1..517ad52077829552 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -361,13 +361,7 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + * New waiters arriving concurrently with the group switching will all go + into G2 until we atomically make the switch. Waiters existing in G2 + are not affected. +- * Waiters in G1 have already received a signal and been woken. If they +- haven't woken yet, they will be closed out immediately by the advancing +- of __g_signals to the next "lowseq" (low 31 bits of the new g1_start), +- which will prevent waiters from blocking using a futex on +- __g_signals since it provides enough signals for all possible +- remaining waiters. As a result, they can each consume a signal +- and they will eventually remove their group reference. */ ++ * Waiters in G1 have already received a signal and been woken. */ + + /* Update __g1_start, which finishes closing this group. The value we add + will never be negative because old_orig_size can only be zero when we +@@ -380,29 +374,6 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + + unsigned int lowseq = ((old_g1_start + old_orig_size) << 1) & ~1U; + +- /* If any waiters still hold group references (and thus could be blocked), +- then wake them all up now and prevent any running ones from blocking. +- This is effectively a catch-all for any possible current or future +- bugs that can allow the group size to reach 0 before all G1 waiters +- have been awakened or at least given signals to consume, or any +- other case that can leave blocked (or about to block) older waiters.. */ +- if ((atomic_fetch_or_release (cond->__data.__g_refs + g1, 0) >> 1) > 0) +- { +- /* First advance signals to the end of the group (i.e. enough signals +- for the entire G1 group) to ensure that waiters which have not +- yet blocked in the futex will not block. +- Note that in the vast majority of cases, this should never +- actually be necessary, since __g_signals will have enough +- signals for the remaining g_refs waiters. As an optimization, +- we could check this first before proceeding, although that +- could still leave the potential for futex lost wakeup bugs +- if the signal count was non-zero but the futex wakeup +- was somehow lost. */ +- atomic_store_release (cond->__data.__g_signals + g1, lowseq); +- +- futex_wake (cond->__data.__g_signals + g1, INT_MAX, private); +- } +- + /* At this point, the old G1 is now a valid new G2 (but not in use yet). + No old waiter can neither grab a signal nor acquire a reference without + noticing that __g1_start is larger. diff --git a/SOURCES/glibc-RHEL-2419-4.patch b/SOURCES/glibc-RHEL-2419-4.patch new file mode 100644 index 0000000..486903c --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-4.patch @@ -0,0 +1,107 @@ +commit 4f7b051f8ee3feff1b53b27a906f245afaa9cee1 +Author: Malte Skarupke +Date: Wed Dec 4 07:56:13 2024 -0500 + + nptl: Remove unnecessary quadruple check in pthread_cond_wait + + pthread_cond_wait was checking whether it was in a closed group no less than + four times. Checking once is enough. Here are the four checks: + + 1. While spin-waiting. This was dead code: maxspin is set to 0 and has been + for years. + 2. Before deciding to go to sleep, and before incrementing grefs: I kept this + 3. After incrementing grefs. There is no reason to think that the group would + close while we do an atomic increment. Obviously it could close at any + point, but that doesn't mean we have to recheck after every step. This + check was equally good as check 2, except it has to do more work. + 4. When we find ourselves in a group that has a signal. We only get here after + we check that we're not in a closed group. There is no need to check again. + The check would only have helped in cases where the compare_exchange in the + next line would also have failed. Relying on the compare_exchange is fine. + + Removing the duplicate checks clarifies the code. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 7dabcb15d2d818e7..ba9a19bedc2c176f 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -367,7 +367,6 @@ static __always_inline int + __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + clockid_t clockid, const struct __timespec64 *abstime) + { +- const int maxspin = 0; + int err; + int result = 0; + +@@ -426,33 +425,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); + unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + +- /* Spin-wait first. +- Note that spinning first without checking whether a timeout +- passed might lead to what looks like a spurious wake-up even +- though we should return ETIMEDOUT (e.g., if the caller provides +- an absolute timeout that is clearly in the past). However, +- (1) spurious wake-ups are allowed, (2) it seems unlikely that a +- user will (ab)use pthread_cond_wait as a check for whether a +- point in time is in the past, and (3) spinning first without +- having to compare against the current time seems to be the right +- choice from a performance perspective for most use cases. */ +- unsigned int spin = maxspin; +- while (spin > 0 && ((int)(signals - lowseq) < 2)) +- { +- /* Check that we are not spinning on a group that's already +- closed. */ +- if (seq < (g1_start >> 1)) +- break; +- +- /* TODO Back off. */ +- +- /* Reload signals. See above for MO. */ +- signals = atomic_load_acquire (cond->__data.__g_signals + g); +- g1_start = __condvar_load_g1_start_relaxed (cond); +- lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; +- spin--; +- } +- + if (seq < (g1_start >> 1)) + { + /* If the group is closed already, +@@ -483,24 +455,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + an atomic read-modify-write operation and thus extend the release + sequence. */ + atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2); +- signals = atomic_load_acquire (cond->__data.__g_signals + g); +- g1_start = __condvar_load_g1_start_relaxed (cond); +- lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; +- +- if (seq < (g1_start >> 1)) +- { +- /* group is closed already, so don't block */ +- __condvar_dec_grefs (cond, g, private); +- goto done; +- } +- +- if ((int)(signals - lowseq) >= 2) +- { +- /* a signal showed up or G1/G2 switched after we grabbed the +- refcount */ +- __condvar_dec_grefs (cond, g, private); +- break; +- } + + // Now block. + struct _pthread_cleanup_buffer buffer; +@@ -534,9 +488,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + /* Reload signals. See above for MO. */ + signals = atomic_load_acquire (cond->__data.__g_signals + g); + } +- +- if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1)) +- goto done; + } + /* Try to grab a signal. See above for MO. (if we do another loop + iteration we need to see the correct value of g1_start) */ diff --git a/SOURCES/glibc-RHEL-2419-5.patch b/SOURCES/glibc-RHEL-2419-5.patch new file mode 100644 index 0000000..3df4fa8 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-5.patch @@ -0,0 +1,172 @@ +commit c36fc50781995e6758cae2b6927839d0157f213c +Author: Malte Skarupke +Date: Wed Dec 4 07:56:38 2024 -0500 + + nptl: Remove g_refs from condition variables + + This variable used to be needed to wait in group switching until all sleepers + have confirmed that they have woken. This is no longer needed. Nothing waits + on this variable so there is no need to track how many threads are currently + asleep in each group. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +# Conflicts: +# nptl/tst-cond22.c (No atomic wide counter refactor) +# sysdeps/nptl/bits/thread-shared-types.h (Likewise) + +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index ba9a19bedc2c176f..9652dbafe08dfde1 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -144,23 +144,6 @@ __condvar_cancel_waiting (pthread_cond_t *cond, uint64_t seq, unsigned int g, + } + } + +-/* Wake up any signalers that might be waiting. */ +-static void +-__condvar_dec_grefs (pthread_cond_t *cond, unsigned int g, int private) +-{ +- /* Release MO to synchronize-with the acquire load in +- __condvar_quiesce_and_switch_g1. */ +- if (atomic_fetch_add_release (cond->__data.__g_refs + g, -2) == 3) +- { +- /* Clear the wake-up request flag before waking up. We do not need more +- than relaxed MO and it doesn't matter if we apply this for an aliased +- group because we wake all futex waiters right after clearing the +- flag. */ +- atomic_fetch_and_relaxed (cond->__data.__g_refs + g, ~(unsigned int) 1); +- futex_wake (cond->__data.__g_refs + g, INT_MAX, private); +- } +-} +- + /* Clean-up for cancellation of waiters waiting for normal signals. We cancel + our registration as a waiter, confirm we have woken up, and re-acquire the + mutex. */ +@@ -172,8 +155,6 @@ __condvar_cleanup_waiting (void *arg) + pthread_cond_t *cond = cbuffer->cond; + unsigned g = cbuffer->wseq & 1; + +- __condvar_dec_grefs (cond, g, cbuffer->private); +- + __condvar_cancel_waiting (cond, cbuffer->wseq >> 1, g, cbuffer->private); + /* FIXME With the current cancellation implementation, it is possible that + a thread is cancelled after it has returned from a syscall. This could +@@ -328,15 +309,6 @@ __condvar_cleanup_waiting (void *arg) + sufficient because if a waiter can see a sufficiently large value, it could + have also consume a signal in the waiters group. + +- It is essential that the last field in pthread_cond_t is __g_signals[1]: +- The previous condvar used a pointer-sized field in pthread_cond_t, so a +- PTHREAD_COND_INITIALIZER from that condvar implementation might only +- initialize 4 bytes to zero instead of the 8 bytes we need (i.e., 44 bytes +- in total instead of the 48 we need). __g_signals[1] is not accessed before +- the first group switch (G2 starts at index 0), which will set its value to +- zero after a harmless fetch-or whose return value is ignored. This +- effectively completes initialization. +- + + Limitations: + * This condvar isn't designed to allow for more than +@@ -441,21 +413,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + if ((int)(signals - lowseq) >= 2) + break; + +- /* No signals available after spinning, so prepare to block. +- We first acquire a group reference and use acquire MO for that so +- that we synchronize with the dummy read-modify-write in +- __condvar_quiesce_and_switch_g1 if we read from that. In turn, +- in this case this will make us see the advancement of __g_signals +- to the upcoming new g1_start that occurs with a concurrent +- attempt to reuse the group's slot. +- We use acquire MO for the __g_signals check to make the +- __g1_start check work (see spinning above). +- Note that the group reference acquisition will not mask the +- release MO when decrementing the reference count because we use +- an atomic read-modify-write operation and thus extend the release +- sequence. */ +- atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2); +- + // Now block. + struct _pthread_cleanup_buffer buffer; + struct _condvar_cleanup_buffer cbuffer; +@@ -472,18 +429,11 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + + if (__glibc_unlikely (err == ETIMEDOUT || err == EOVERFLOW)) + { +- __condvar_dec_grefs (cond, g, private); +- /* If we timed out, we effectively cancel waiting. Note that +- we have decremented __g_refs before cancellation, so that a +- deadlock between waiting for quiescence of our group in +- __condvar_quiesce_and_switch_g1 and us trying to acquire +- the lock during cancellation is not possible. */ ++ /* If we timed out, we effectively cancel waiting. */ + __condvar_cancel_waiting (cond, seq, g, private); + result = err; + goto done; + } +- else +- __condvar_dec_grefs (cond, g, private); + + /* Reload signals. See above for MO. */ + signals = atomic_load_acquire (cond->__data.__g_signals + g); +diff --git a/nptl/tst-cond22.c b/nptl/tst-cond22.c +index 64f19ea0a55af057..ebeeeaf666070076 100644 +--- a/nptl/tst-cond22.c ++++ b/nptl/tst-cond22.c +@@ -106,10 +106,10 @@ do_test (void) + status = 1; + } + +- printf ("cond = { %llu, %llu, %u/%u/%u, %u/%u/%u, %u, %u }\n", ++ printf ("cond = { %llu, %llu, %u/%u, %u/%u, %u, %u }\n", + c.__data.__wseq, c.__data.__g1_start, +- c.__data.__g_signals[0], c.__data.__g_refs[0], c.__data.__g_size[0], +- c.__data.__g_signals[1], c.__data.__g_refs[1], c.__data.__g_size[1], ++ c.__data.__g_signals[0], c.__data.__g_size[0], ++ c.__data.__g_signals[1], c.__data.__g_size[1], + c.__data.__g1_orig_size, c.__data.__wrefs); + + if (pthread_create (&th, NULL, tf, (void *) 1l) != 0) +@@ -149,10 +149,10 @@ do_test (void) + status = 1; + } + +- printf ("cond = { %llu, %llu, %u/%u/%u, %u/%u/%u, %u, %u }\n", ++ printf ("cond = { %llu, %llu, %u/%u, %u/%u, %u, %u }\n", + c.__data.__wseq, c.__data.__g1_start, +- c.__data.__g_signals[0], c.__data.__g_refs[0], c.__data.__g_size[0], +- c.__data.__g_signals[1], c.__data.__g_refs[1], c.__data.__g_size[1], ++ c.__data.__g_signals[0], c.__data.__g_size[0], ++ c.__data.__g_signals[1], c.__data.__g_size[1], + c.__data.__g1_orig_size, c.__data.__wrefs); + + return status; +diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h +index 44bf1e358dbdaaff..5cd33b765d9689eb 100644 +--- a/sysdeps/nptl/bits/thread-shared-types.h ++++ b/sysdeps/nptl/bits/thread-shared-types.h +@@ -109,8 +109,7 @@ struct __pthread_cond_s + unsigned int __high; + } __g1_start32; + }; +- unsigned int __g_refs[2] __LOCK_ALIGNMENT; +- unsigned int __g_size[2]; ++ unsigned int __g_size[2] __LOCK_ALIGNMENT; + unsigned int __g1_orig_size; + unsigned int __wrefs; + unsigned int __g_signals[2]; +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index 43146e91c9d9579b..7ea6001784783371 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -152,7 +152,7 @@ enum + + + /* Conditional variable handling. */ +-#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } } ++#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, 0, 0, {0, 0} } } + + + /* Cleanup buffers */ diff --git a/SOURCES/glibc-RHEL-2419-6.patch b/SOURCES/glibc-RHEL-2419-6.patch new file mode 100644 index 0000000..7e966e5 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-6.patch @@ -0,0 +1,91 @@ +commit 929a4764ac90382616b6a21f099192b2475da674 +Author: Malte Skarupke +Date: Wed Dec 4 08:03:44 2024 -0500 + + nptl: Use a single loop in pthread_cond_wait instaed of a nested loop + + The loop was a little more complicated than necessary. There was only one + break statement out of the inner loop, and the outer loop was nearly empty. + So just remove the outer loop, moving its code to the one break statement in + the inner loop. This allows us to replace all gotos with break statements. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 9652dbafe08dfde1..4886056d136db138 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -383,17 +383,15 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + return err; + } + +- /* Now wait until a signal is available in our group or it is closed. +- Acquire MO so that if we observe (signals == lowseq) after group +- switching in __condvar_quiesce_and_switch_g1, we synchronize with that +- store and will see the prior update of __g1_start done while switching +- groups too. */ +- unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g); +- +- do +- { ++ + while (1) + { ++ /* Now wait until a signal is available in our group or it is closed. ++ Acquire MO so that if we observe (signals == lowseq) after group ++ switching in __condvar_quiesce_and_switch_g1, we synchronize with that ++ store and will see the prior update of __g1_start done while switching ++ groups too. */ ++ unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g); + uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); + unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + +@@ -402,7 +400,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + /* If the group is closed already, + then this waiter originally had enough extra signals to + consume, up until the time its group was closed. */ +- goto done; ++ break; + } + + /* If there is an available signal, don't block. +@@ -411,7 +409,16 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + G2, but in either case we're allowed to consume the available + signal and should not block anymore. */ + if ((int)(signals - lowseq) >= 2) +- break; ++ { ++ /* Try to grab a signal. See above for MO. (if we do another loop ++ iteration we need to see the correct value of g1_start) */ ++ if (atomic_compare_exchange_weak_acquire ( ++ cond->__data.__g_signals + g, ++ &signals, signals - 2)) ++ break; ++ else ++ continue; ++ } + + // Now block. + struct _pthread_cleanup_buffer buffer; +@@ -432,19 +439,9 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + /* If we timed out, we effectively cancel waiting. */ + __condvar_cancel_waiting (cond, seq, g, private); + result = err; +- goto done; ++ break; + } +- +- /* Reload signals. See above for MO. */ +- signals = atomic_load_acquire (cond->__data.__g_signals + g); + } +- } +- /* Try to grab a signal. See above for MO. (if we do another loop +- iteration we need to see the correct value of g1_start) */ +- while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g, +- &signals, signals - 2)); +- +- done: + + /* Confirm that we have been woken. We do that before acquiring the mutex + to allow for execution of pthread_cond_destroy while having acquired the diff --git a/SOURCES/glibc-RHEL-2419-7.patch b/SOURCES/glibc-RHEL-2419-7.patch new file mode 100644 index 0000000..87c54f2 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-7.patch @@ -0,0 +1,138 @@ +commit ee6c14ed59d480720721aaacc5fb03213dc153da +Author: Malte Skarupke +Date: Wed Dec 4 08:04:10 2024 -0500 + + nptl: Fix indentation + + In my previous change I turned a nested loop into a simple loop. I'm doing + the resulting indentation changes in a separate commit to make the diff on + the previous commit easier to review. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 4886056d136db138..6c130436b016977a 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -384,65 +384,65 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + } + + +- while (1) +- { +- /* Now wait until a signal is available in our group or it is closed. +- Acquire MO so that if we observe (signals == lowseq) after group +- switching in __condvar_quiesce_and_switch_g1, we synchronize with that +- store and will see the prior update of __g1_start done while switching +- groups too. */ +- unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g); +- uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); +- unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; +- +- if (seq < (g1_start >> 1)) +- { +- /* If the group is closed already, +- then this waiter originally had enough extra signals to +- consume, up until the time its group was closed. */ +- break; +- } +- +- /* If there is an available signal, don't block. +- If __g1_start has advanced at all, then we must be in G1 +- by now, perhaps in the process of switching back to an older +- G2, but in either case we're allowed to consume the available +- signal and should not block anymore. */ +- if ((int)(signals - lowseq) >= 2) +- { +- /* Try to grab a signal. See above for MO. (if we do another loop +- iteration we need to see the correct value of g1_start) */ +- if (atomic_compare_exchange_weak_acquire ( +- cond->__data.__g_signals + g, ++ while (1) ++ { ++ /* Now wait until a signal is available in our group or it is closed. ++ Acquire MO so that if we observe (signals == lowseq) after group ++ switching in __condvar_quiesce_and_switch_g1, we synchronize with that ++ store and will see the prior update of __g1_start done while switching ++ groups too. */ ++ unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g); ++ uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); ++ unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; ++ ++ if (seq < (g1_start >> 1)) ++ { ++ /* If the group is closed already, ++ then this waiter originally had enough extra signals to ++ consume, up until the time its group was closed. */ ++ break; ++ } ++ ++ /* If there is an available signal, don't block. ++ If __g1_start has advanced at all, then we must be in G1 ++ by now, perhaps in the process of switching back to an older ++ G2, but in either case we're allowed to consume the available ++ signal and should not block anymore. */ ++ if ((int)(signals - lowseq) >= 2) ++ { ++ /* Try to grab a signal. See above for MO. (if we do another loop ++ iteration we need to see the correct value of g1_start) */ ++ if (atomic_compare_exchange_weak_acquire ( ++ cond->__data.__g_signals + g, + &signals, signals - 2)) +- break; +- else +- continue; +- } +- +- // Now block. +- struct _pthread_cleanup_buffer buffer; +- struct _condvar_cleanup_buffer cbuffer; +- cbuffer.wseq = wseq; +- cbuffer.cond = cond; +- cbuffer.mutex = mutex; +- cbuffer.private = private; +- __pthread_cleanup_push (&buffer, __condvar_cleanup_waiting, &cbuffer); +- +- err = __futex_abstimed_wait_cancelable64 ( +- cond->__data.__g_signals + g, signals, clockid, abstime, private); +- +- __pthread_cleanup_pop (&buffer, 0); +- +- if (__glibc_unlikely (err == ETIMEDOUT || err == EOVERFLOW)) +- { +- /* If we timed out, we effectively cancel waiting. */ +- __condvar_cancel_waiting (cond, seq, g, private); +- result = err; + break; +- } ++ else ++ continue; + } + ++ // Now block. ++ struct _pthread_cleanup_buffer buffer; ++ struct _condvar_cleanup_buffer cbuffer; ++ cbuffer.wseq = wseq; ++ cbuffer.cond = cond; ++ cbuffer.mutex = mutex; ++ cbuffer.private = private; ++ __pthread_cleanup_push (&buffer, __condvar_cleanup_waiting, &cbuffer); ++ ++ err = __futex_abstimed_wait_cancelable64 ( ++ cond->__data.__g_signals + g, signals, clockid, abstime, private); ++ ++ __pthread_cleanup_pop (&buffer, 0); ++ ++ if (__glibc_unlikely (err == ETIMEDOUT || err == EOVERFLOW)) ++ { ++ /* If we timed out, we effectively cancel waiting. */ ++ __condvar_cancel_waiting (cond, seq, g, private); ++ result = err; ++ break; ++ } ++ } ++ + /* Confirm that we have been woken. We do that before acquiring the mutex + to allow for execution of pthread_cond_destroy while having acquired the + mutex. */ diff --git a/SOURCES/glibc-RHEL-2419-8.patch b/SOURCES/glibc-RHEL-2419-8.patch new file mode 100644 index 0000000..eff1b1a --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-8.patch @@ -0,0 +1,147 @@ +commit 4b79e27a5073c02f6bff9aa8f4791230a0ab1867 +Author: Malte Skarupke +Date: Wed Dec 4 08:04:54 2024 -0500 + + nptl: rename __condvar_quiesce_and_switch_g1 + + This function no longer waits for threads to leave g1, so rename it to + __condvar_switch_g1 + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_broadcast.c b/nptl/pthread_cond_broadcast.c +index f1275b2f15817788..3dff819952718892 100644 +--- a/nptl/pthread_cond_broadcast.c ++++ b/nptl/pthread_cond_broadcast.c +@@ -61,7 +61,7 @@ ___pthread_cond_broadcast (pthread_cond_t *cond) + cond->__data.__g_size[g1] << 1); + cond->__data.__g_size[g1] = 0; + +- /* We need to wake G1 waiters before we quiesce G1 below. */ ++ /* We need to wake G1 waiters before we switch G1 below. */ + /* TODO Only set it if there are indeed futex waiters. We could + also try to move this out of the critical section in cases when + G2 is empty (and we don't need to quiesce). */ +@@ -70,7 +70,7 @@ ___pthread_cond_broadcast (pthread_cond_t *cond) + + /* G1 is complete. Step (2) is next unless there are no waiters in G2, in + which case we can stop. */ +- if (__condvar_quiesce_and_switch_g1 (cond, wseq, &g1, private)) ++ if (__condvar_switch_g1 (cond, wseq, &g1, private)) + { + /* Step (3): Send signals to all waiters in the old G2 / new G1. */ + atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index 517ad52077829552..7b2b1e4605f163e7 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -329,16 +329,15 @@ __condvar_get_private (int flags) + return FUTEX_SHARED; + } + +-/* This closes G1 (whose index is in G1INDEX), waits for all futex waiters to +- leave G1, converts G1 into a fresh G2, and then switches group roles so that +- the former G2 becomes the new G1 ending at the current __wseq value when we +- eventually make the switch (WSEQ is just an observation of __wseq by the +- signaler). ++/* This closes G1 (whose index is in G1INDEX), converts G1 into a fresh G2, ++ and then switches group roles so that the former G2 becomes the new G1 ++ ending at the current __wseq value when we eventually make the switch ++ (WSEQ is just an observation of __wseq by the signaler). + If G2 is empty, it will not switch groups because then it would create an + empty G1 which would require switching groups again on the next signal. + Returns false iff groups were not switched because G2 was empty. */ + static bool __attribute__ ((unused)) +-__condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, ++__condvar_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + unsigned int *g1index, int private) + { + unsigned int g1 = *g1index; +@@ -354,8 +353,7 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + + cond->__data.__g_size[g1 ^ 1]) == 0) + return false; + +- /* Now try to close and quiesce G1. We have to consider the following kinds +- of waiters: ++ /* We have to consider the following kinds of waiters: + * Waiters from less recent groups than G1 are not affected because + nothing will change for them apart from __g1_start getting larger. + * New waiters arriving concurrently with the group switching will all go +@@ -363,12 +361,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + are not affected. + * Waiters in G1 have already received a signal and been woken. */ + +- /* Update __g1_start, which finishes closing this group. The value we add +- will never be negative because old_orig_size can only be zero when we +- switch groups the first time after a condvar was initialized, in which +- case G1 will be at index 1 and we will add a value of 1. +- Relaxed MO is fine because the change comes with no additional +- constraints that others would have to observe. */ ++ /* Update __g1_start, which closes this group. The value we add will never ++ be negative because old_orig_size can only be zero when we switch groups ++ the first time after a condvar was initialized, in which case G1 will be ++ at index 1 and we will add a value of 1. Relaxed MO is fine because the ++ change comes with no additional constraints that others would have to ++ observe. */ + __condvar_add_g1_start_relaxed (cond, + (old_orig_size << 1) + (g1 == 1 ? 1 : - 1)); + +diff --git a/nptl/pthread_cond_signal.c b/nptl/pthread_cond_signal.c +index 171193b13e203290..4f7639e386fc207a 100644 +--- a/nptl/pthread_cond_signal.c ++++ b/nptl/pthread_cond_signal.c +@@ -70,18 +70,17 @@ ___pthread_cond_signal (pthread_cond_t *cond) + bool do_futex_wake = false; + + /* If G1 is still receiving signals, we put the signal there. If not, we +- check if G2 has waiters, and if so, quiesce and switch G1 to the former +- G2; if this results in a new G1 with waiters (G2 might have cancellations +- already, see __condvar_quiesce_and_switch_g1), we put the signal in the +- new G1. */ ++ check if G2 has waiters, and if so, switch G1 to the former G2; if this ++ results in a new G1 with waiters (G2 might have cancellations already, ++ see __condvar_switch_g1), we put the signal in the new G1. */ + if ((cond->__data.__g_size[g1] != 0) +- || __condvar_quiesce_and_switch_g1 (cond, wseq, &g1, private)) ++ || __condvar_switch_g1 (cond, wseq, &g1, private)) + { + /* Add a signal. Relaxed MO is fine because signaling does not need to +- establish a happens-before relation (see above). We do not mask the +- release-MO store when initializing a group in +- __condvar_quiesce_and_switch_g1 because we use an atomic +- read-modify-write and thus extend that store's release sequence. */ ++ establish a happens-before relation (see above). We do not mask the ++ release-MO store when initializing a group in __condvar_switch_g1 ++ because we use an atomic read-modify-write and thus extend that ++ store's release sequence. */ + atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, 2); + cond->__data.__g_size[g1]--; + /* TODO Only set it if there are indeed futex waiters. */ +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 6c130436b016977a..173bd134164eed44 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -355,8 +355,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + because we do not need to establish any happens-before relation with + signalers (see __pthread_cond_signal); modification order alone + establishes a total order of waiters/signals. We do need acquire MO +- to synchronize with group reinitialization in +- __condvar_quiesce_and_switch_g1. */ ++ to synchronize with group reinitialization in __condvar_switch_g1. */ + uint64_t wseq = __condvar_fetch_add_wseq_acquire (cond, 2); + /* Find our group's index. We always go into what was G2 when we acquired + our position. */ +@@ -388,9 +387,9 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + { + /* Now wait until a signal is available in our group or it is closed. + Acquire MO so that if we observe (signals == lowseq) after group +- switching in __condvar_quiesce_and_switch_g1, we synchronize with that +- store and will see the prior update of __g1_start done while switching +- groups too. */ ++ switching in __condvar_switch_g1, we synchronize with that store and ++ will see the prior update of __g1_start done while switching groups ++ too. */ + unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g); + uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); + unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; diff --git a/SOURCES/glibc-RHEL-2419-9.patch b/SOURCES/glibc-RHEL-2419-9.patch new file mode 100644 index 0000000..4f94d43 --- /dev/null +++ b/SOURCES/glibc-RHEL-2419-9.patch @@ -0,0 +1,179 @@ +commit 91bb902f58264a2fd50fbce8f39a9a290dd23706 +Author: Malte Skarupke +Date: Wed Dec 4 08:05:40 2024 -0500 + + nptl: Use all of g1_start and g_signals + + The LSB of g_signals was unused. The LSB of g1_start was used to indicate + which group is G2. This was used to always go to sleep in pthread_cond_wait + if a waiter is in G2. A comment earlier in the file says that this is not + correct to do: + + "Waiters cannot determine whether they are currently in G2 or G1 -- but they + do not have to because all they are interested in is whether there are + available signals" + + I either would have had to update the comment, or get rid of the check. I + chose to get rid of the check. In fact I don't quite know why it was there. + There will never be available signals for group G2, so we didn't need the + special case. Even if there were, this would just be a spurious wake. This + might have caught some cases where the count has wrapped around, but it + wouldn't reliably do that, (and even if it did, why would you want to force a + sleep in that case?) and we don't support that many concurrent waiters + anyway. Getting rid of it allows us to use one more bit, making us more + robust to wraparound. + + Signed-off-by: Malte Skarupke + Reviewed-by: Carlos O'Donell + +diff --git a/nptl/pthread_cond_broadcast.c b/nptl/pthread_cond_broadcast.c +index 3dff819952718892..6fd6cfe9d002c5d5 100644 +--- a/nptl/pthread_cond_broadcast.c ++++ b/nptl/pthread_cond_broadcast.c +@@ -58,7 +58,7 @@ ___pthread_cond_broadcast (pthread_cond_t *cond) + { + /* Add as many signals as the remaining size of the group. */ + atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, +- cond->__data.__g_size[g1] << 1); ++ cond->__data.__g_size[g1]); + cond->__data.__g_size[g1] = 0; + + /* We need to wake G1 waiters before we switch G1 below. */ +@@ -74,7 +74,7 @@ ___pthread_cond_broadcast (pthread_cond_t *cond) + { + /* Step (3): Send signals to all waiters in the old G2 / new G1. */ + atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, +- cond->__data.__g_size[g1] << 1); ++ cond->__data.__g_size[g1]); + cond->__data.__g_size[g1] = 0; + /* TODO Only set it if there are indeed futex waiters. */ + do_futex_wake = true; +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index 7b2b1e4605f163e7..485aca4076a372d7 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -348,9 +348,9 @@ __condvar_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + behavior. + Note that this works correctly for a zero-initialized condvar too. */ + unsigned int old_orig_size = __condvar_get_orig_size (cond); +- uint64_t old_g1_start = __condvar_load_g1_start_relaxed (cond) >> 1; +- if (((unsigned) (wseq - old_g1_start - old_orig_size) +- + cond->__data.__g_size[g1 ^ 1]) == 0) ++ uint64_t old_g1_start = __condvar_load_g1_start_relaxed (cond); ++ uint64_t new_g1_start = old_g1_start + old_orig_size; ++ if (((unsigned) (wseq - new_g1_start) + cond->__data.__g_size[g1 ^ 1]) == 0) + return false; + + /* We have to consider the following kinds of waiters: +@@ -361,16 +361,10 @@ __condvar_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + are not affected. + * Waiters in G1 have already received a signal and been woken. */ + +- /* Update __g1_start, which closes this group. The value we add will never +- be negative because old_orig_size can only be zero when we switch groups +- the first time after a condvar was initialized, in which case G1 will be +- at index 1 and we will add a value of 1. Relaxed MO is fine because the +- change comes with no additional constraints that others would have to +- observe. */ +- __condvar_add_g1_start_relaxed (cond, +- (old_orig_size << 1) + (g1 == 1 ? 1 : - 1)); +- +- unsigned int lowseq = ((old_g1_start + old_orig_size) << 1) & ~1U; ++ /* Update __g1_start, which closes this group. Relaxed MO is fine because ++ the change comes with no additional constraints that others would have ++ to observe. */ ++ __condvar_add_g1_start_relaxed (cond, old_orig_size); + + /* At this point, the old G1 is now a valid new G2 (but not in use yet). + No old waiter can neither grab a signal nor acquire a reference without +@@ -382,13 +376,13 @@ __condvar_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + g1 ^= 1; + *g1index ^= 1; + +- /* Now advance the new G1 g_signals to the new lowseq, giving it ++ /* Now advance the new G1 g_signals to the new g1_start, giving it + an effective signal count of 0 to start. */ +- atomic_store_release (cond->__data.__g_signals + g1, lowseq); ++ atomic_store_release (cond->__data.__g_signals + g1, (unsigned)new_g1_start); + + /* These values are just observed by signalers, and thus protected by the + lock. */ +- unsigned int orig_size = wseq - (old_g1_start + old_orig_size); ++ unsigned int orig_size = wseq - new_g1_start; + __condvar_set_orig_size (cond, orig_size); + /* Use and addition to not loose track of cancellations in what was + previously G2. */ +diff --git a/nptl/pthread_cond_signal.c b/nptl/pthread_cond_signal.c +index 4f7639e386fc207a..9a5bac92fe8fc246 100644 +--- a/nptl/pthread_cond_signal.c ++++ b/nptl/pthread_cond_signal.c +@@ -81,7 +81,7 @@ ___pthread_cond_signal (pthread_cond_t *cond) + release-MO store when initializing a group in __condvar_switch_g1 + because we use an atomic read-modify-write and thus extend that + store's release sequence. */ +- atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, 2); ++ atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, 1); + cond->__data.__g_size[g1]--; + /* TODO Only set it if there are indeed futex waiters. */ + do_futex_wake = true; +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 173bd134164eed44..944b241ec26b9b32 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -85,7 +85,7 @@ __condvar_cancel_waiting (pthread_cond_t *cond, uint64_t seq, unsigned int g, + not hold a reference on the group. */ + __condvar_acquire_lock (cond, private); + +- uint64_t g1_start = __condvar_load_g1_start_relaxed (cond) >> 1; ++ uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); + if (g1_start > seq) + { + /* Our group is closed, so someone provided enough signals for it. +@@ -260,7 +260,6 @@ __condvar_cleanup_waiting (void *arg) + * Waiters fetch-add while having acquire the mutex associated with the + condvar. Signalers load it and fetch-xor it concurrently. + __g1_start: Starting position of G1 (inclusive) +- * LSB is index of current G2. + * Modified by signalers while having acquired the condvar-internal lock + and observed concurrently by waiters. + __g1_orig_size: Initial size of G1 +@@ -281,11 +280,9 @@ __condvar_cleanup_waiting (void *arg) + * Reference count used by waiters concurrently with signalers that have + acquired the condvar-internal lock. + __g_signals: The number of signals that can still be consumed, relative to +- the current g1_start. (i.e. bits 31 to 1 of __g_signals are bits +- 31 to 1 of g1_start with the signal count added) ++ the current g1_start. (i.e. g1_start with the signal count added) + * Used as a futex word by waiters. Used concurrently by waiters and + signalers. +- * LSB is currently reserved and 0. + __g_size: Waiters remaining in this group (i.e., which have not been + signaled yet. + * Accessed by signalers and waiters that cancel waiting (both do so only +@@ -392,9 +389,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + too. */ + unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g); + uint64_t g1_start = __condvar_load_g1_start_relaxed (cond); +- unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U; + +- if (seq < (g1_start >> 1)) ++ if (seq < g1_start) + { + /* If the group is closed already, + then this waiter originally had enough extra signals to +@@ -407,13 +403,13 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + by now, perhaps in the process of switching back to an older + G2, but in either case we're allowed to consume the available + signal and should not block anymore. */ +- if ((int)(signals - lowseq) >= 2) ++ if ((int)(signals - (unsigned int)g1_start) > 0) + { + /* Try to grab a signal. See above for MO. (if we do another loop + iteration we need to see the correct value of g1_start) */ + if (atomic_compare_exchange_weak_acquire ( + cond->__data.__g_signals + g, +- &signals, signals - 2)) ++ &signals, signals - 1)) + break; + else + continue; diff --git a/SOURCES/glibc-RHEL-24740-1.patch b/SOURCES/glibc-RHEL-24740-1.patch new file mode 100644 index 0000000..7fd8043 --- /dev/null +++ b/SOURCES/glibc-RHEL-24740-1.patch @@ -0,0 +1,315 @@ +commit 3367d8e180848030d1646f088759f02b8dfe0d6f +Author: Amrita H S +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 + Reviewed-by: Paul E. Murphy + +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 ++ . */ ++#include ++ ++#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 ++ . */ ++ ++#if defined __LITTLE_ENDIAN__ && IS_IN (libc) ++#define STRCMP __strcmp_power10 ++ ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(name) ++ ++#include ++#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 : diff --git a/SOURCES/glibc-RHEL-24740-2.patch b/SOURCES/glibc-RHEL-24740-2.patch new file mode 100644 index 0000000..11f9510 --- /dev/null +++ b/SOURCES/glibc-RHEL-24740-2.patch @@ -0,0 +1,435 @@ +commit b9182c793caa05df5d697427c0538936e6396d4b +Author: MAHESH BODAPATI +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 + +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 ++ . */ ++ ++#include ++ ++# 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 ++ . */ ++ ++#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 ++#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) diff --git a/SOURCES/glibc-RHEL-24740-3.patch b/SOURCES/glibc-RHEL-24740-3.patch new file mode 100644 index 0000000..353966c --- /dev/null +++ b/SOURCES/glibc-RHEL-24740-3.patch @@ -0,0 +1,218 @@ +commit 90bcc8721ef82b7378d2b080141228660e862d56 +Author: Amrita H S +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 + Co-Authored-By: Paul E. Murphy + Reviewed-by: Rajalakshmi Srinivasaraghavan + +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): diff --git a/SOURCES/glibc-RHEL-38225-1.patch b/SOURCES/glibc-RHEL-38225-1.patch new file mode 100644 index 0000000..4a2a2b4 --- /dev/null +++ b/SOURCES/glibc-RHEL-38225-1.patch @@ -0,0 +1,69 @@ +commit f942a732d37a96217ef828116ebe64a644db18d7 +Author: Joe Talbott +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 + +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); + diff --git a/SOURCES/glibc-RHEL-38225-2.patch b/SOURCES/glibc-RHEL-38225-2.patch new file mode 100644 index 0000000..fc29da0 --- /dev/null +++ b/SOURCES/glibc-RHEL-38225-2.patch @@ -0,0 +1,529 @@ +commit ae18044f95271ed422ed847bd8d8c6d8e84674ce +Author: Joe Simmons-Talbott +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_ 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 + Reviewed-By: Joseph Myers + +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 + #include + #include ++#include + + /* 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); diff --git a/SOURCES/glibc-RHEL-41189.patch b/SOURCES/glibc-RHEL-41189.patch new file mode 100644 index 0000000..3e31fbf --- /dev/null +++ b/SOURCES/glibc-RHEL-41189.patch @@ -0,0 +1,320 @@ +From 3de73f974fab55430177c811c9c9ba3f251d5747 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + +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 diff --git a/SOURCES/glibc-RHEL-46724.patch b/SOURCES/glibc-RHEL-46724.patch new file mode 100644 index 0000000..a9f04e4 --- /dev/null +++ b/SOURCES/glibc-RHEL-46724.patch @@ -0,0 +1,70 @@ +commit 7fe1fde499507126f7de10ebf12fecaf77ae6602 +Author: Joseph Myers +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 diff --git a/SOURCES/glibc-RHEL-46725-1.patch b/SOURCES/glibc-RHEL-46725-1.patch new file mode 100644 index 0000000..389e7d3 --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-1.patch @@ -0,0 +1,2531 @@ +commit 7ec4d7e3d1c0c6da11dbad1292fd9d94124c57ca +Author: Maciej W. Rozycki +Date: Thu Nov 7 06:14:24 2024 +0000 + + stdio-common: Add tests for formatted printf output specifiers + + This is a collection of tests for formatted printf output specifiers + covering the d, i, o, u, x, and X integer conversions, the e, E, f, F, + g, and G floating-point conversions, the c character conversion, and the + s string conversion. Also the hh, h, l, and ll length modifiers are + covered with the integer conversions as is the L length modifier with + the floating-point conversions. + + The -, +, space, #, and 0 flags are iterated over, as permitted by the + conversion handled, in tuples of 1..5, including tuples with repetitions + of 2, and combined with field width and/or precision, again as permitted + by the conversion. The resulting format string is then used to produce + output from respective sets of input data corresponding to the specific + conversion under test. POSIX extensions beyond ISO C are not used. + + Output is produced in the form of records which include both the format + string (and width and/or precision where given in the form of separate + arguments) and the conversion result, and is verified with GNU AWK using + the format obtained from each such record against the reference value + also supplied, relying on the fact that GNU AWK has its own independent + implementation of format processing, striving to be ISO C compatible. + + In the course of implementation I have determined that in the non-bignum + mode GNU AWK uses system sprintf(3) for the floating-point conversions, + defeating the objective of doing the verification against an independent + implementation. Additionally the bignum mode (using MPFR) is required + to correctly output wider integer and floating-point data. Therefore + for the conversions affected the relevant shell scripts sanity-check AWK + and terminate with unsupported status if the bignum mode is unavailable + for floating-point data or where data is output incorrectly. + + The f and F floating-point conversions are build-time options for GNU + AWK, depending on the environment, so they are probed for before being + used. Similarly the a and A floating-point conversions, however they + are currently not used, see below. Also GNU AWK does not handle the b + or B integer conversions at all at the moment, as at 5.3.0. Support for + the a, A, b, and B conversions can however be easily added following the + approach taken for the f and F conversions. + + Output produced by gawk for the a and A floating-point conversions does + not match one produced by us: insufficient precision is used where one + hasn't been explicitly given, e.g. for the negated maximum finite IEEE + 754 64-bit value of -1.79769313486231570814527423731704357e+308 and "%a" + format we produce -0x1.fffffffffffffp+1023 vs gawk's -0x1.000000p+1024 + and a different exponent is chosen otherwise, such as with "%.a" where + we output -0x2p+1023 vs gawk's -0x1p+1024 for the same value, or "%.20a" + where -0x1.fffffffffffff0000000p+1023 is our output, but gawk produces + -0xf.ffffffffffff80000000p+1020 instead. Consequently I chose not to + include a and A conversions in testing at this time. + + And last but not least there are numerous corner cases that GNU AWK does + not handle correctly, which are worked around by explicit handling in + the AWK script. These are in particular: + + - extraneous leading 0 produced for the alternative form with the o + conversion, e.g. { printf "%#.2o", 1 } produces "001" rather than + "01", + + - unexpected 0 produced where no characters are expected for the input + of 0 and the alternative form with the precision of 0 and the integer + hexadecimal conversions, e.g. { printf "%#.x", 0 } produces "0" rather + than "", + + - missing + character in the non-bignum mode only for the input of 0 + with the + flag, precision of 0 and the signed integer conversions, + e.g. { printf "%+.i", 0 } produces "" rather than "+", + + - missing space character in the non-bignum mode only for the input of 0 + with the space flag, precision of 0 and the signed integer + conversions, e.g. { printf "% .i", 0 } produces "" rather than " ", + + - for released gawk versions of up to 4.2.1 missing - character for the + input of -NaN with the floating-point conversions, e.g. { printf "%e", + "-nan" }' produces "nan" rather than "-nan", + + - for released gawk versions from 5.0.0 onwards + character output for + the input of -NaN with the floating-point conversions, e.g. { printf + "%e", "-nan" }' produces "+nan" rather than "-nan", + + - for released gawk versions from 5.0.0 onwards + character output for + the input of Inf or NaN in the absence of the + or space flags with + the floating-point conversions, e.g. { printf "%e", "inf" }' produces + "+inf" rather than "inf", + + - for released gawk versions of up to 4.2.1 missing + character for the + input of Inf or NaN with the + flag and the floating-point + conversions, e.g. { printf "%+e", "inf" }' produces "inf" rather than + "+inf", + + - for released gawk versions of up to 4.2.1 missing space character for + the input of Inf or NaN with the space flag and the floating-point + conversions, e.g. { printf "% e", "nan" }' produces "nan" rather than + " nan", + + - for released gawk versions from 5.0.0 onwards + character output for + the input of Inf or NaN with the space flag and the floating-point + conversions, e.g. { printf "% e", "inf" }' produces "+inf" rather than + " inf", + + - for released gawk versions from 5.0.0 onwards the field width is + ignored for the input of Inf or NaN and the floating-point + conversions, e.g. { printf "%20e", "-inf" }' produces "-inf" rather + than " -inf", + + NB for released gawk versions of up to 4.2.1 floating-point conversion + issues apply to the bignum mode only, as in the non-bignum mode system + sprintf(3) is used. As from version 5.0.0 specialized handling has been + added for [-]Inf and [-]NaN inputs and the issues listed apply to both + modes. The '--posix' flag makes gawk versions from 5.0.0 onwards avoid + the issue with field width and the + character unconditionally output + for the input of Inf or NaN, however not the remaining issues and then + the 'gensub' function is not supported in the POSIX mode, so to go this + path I deemed not worth it. + + Each test completes within single seconds except for the long double + one. There the F/f formats produce a large number of digits, which + appears to be computationally intensive and CPU-bound. Standalone + execution time for 'tst-printf-format-p-ldouble --direct f' is in the + range of 00m36s for POWER9@2.166GHz and 09m52s for FU740@1.2GHz and + output redirected locally to /dev/null, and 10m11s for FU740 and output + redirected over 100Mbps network via SSH to /dev/null, so the throughput + of the network adds very little (~3.2% in this case) to the processing + time. This is with IEEE 754 quad. + + So I have scaled the timeout for 'tst-printf-format-skeleton-ldouble' + accordingly. Regardless, following recent practice the test has been + added to the standard rather than extended set. However, unlike most + of the remaining tests it has been split by the conversion specifier, + so as to allow better parallelization of this long-running test. As + a side effect this lets the test report the unsupported status for the + F/f conversions where applicable, so 'tst-printf-format-p-double' has + been split for consistency as well. + + Only printf itself is handled at the moment, but the infrastructure + provides for all the printf family functions to be verified, changes + for which to be supplied separately. The complication around having + some tests iterating over all the relevant conversion specifiers and + other verifying conversion specifiers individually combined with + iterating over printf family functions has hit a peculiarity in GNU + make where the use of multiple targets with a pattern rule is handled + differently from such use with an ordinary rule. Consequently it + seems impossible to bulk-define a pattern rule using '$(foreach ...)', + where each target would simply trigger the recipe according to the + pattern and matching dependencies individually (such a rule does work, + but implies all targets to be updated with a single recipe execution). + + Therefore as a compromise a single single-target pattern rule has been + defined that has listed all the conversion-specific scripts and all the + test executables as dependencies. Consequently tests will be rerun in + the absence of changes to their actual sources or scripts whenever an + unrelated file has changed that has been listed. Also all the formatted + printf output tests will always be built whenever any single one is to + be run. This only affects test development and not test runs in the + field, though it does change the order of execution of the individual + steps and also acts as a Makefile barrier in parallel runs. As the + execution time dominates the compilation time for these tests it is not + seen as a serious shortcoming. + + As pointed out by Florian Weimer the malloc tracing + facility can take a substantial amount of time in calling dladdr(3) to + determine the caller's location. This is not needed by the verification + made with these tests, so I chose to interpose the symbol with a stub + implementation that always fails in the shared skeleton. We have total + control over the test environment, so I think it is a safe and minimal + impact approach. If there's ever anything else added to the tests that + would actually rely on dladdr(3) returning usable results, only then we + can think of a different approach. + + Reviewed-by: DJ Delorie + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 09d3622823203f74..0a45dcb4f45c0a5d 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -22,6 +22,34 @@ subdir := stdio-common + + include ../Makeconfig + ++# List of markers for printf family function tests. ++xprintf-funcs := p ++ ++# List of data types and formats for individual per-conversion printf tests. ++fmt-convs := double ldouble ++fmts := E e F f G g ++ ++# List of data types grouping all conversions in single printf tests. ++nonfmt-convs := c char int llong long s short ++nonfmt-convs += uchar uint ullong ulong ushort ++ ++convs := $(sort $(fmt-convs) $(nonfmt-convs)) ++ ++xprintf-srcs := \ ++ $(foreach p,$(xprintf-funcs), \ ++ $(foreach c,$(convs),tst-printf-format-$(p)-$(c))) ++ ++fmt-xprintf-stems := \ ++ $(foreach f,$(fmts), \ ++ $(foreach p,$(xprintf-funcs), \ ++ $(foreach c,$(fmt-convs), \ ++ tst-printf-format-$(p)-$(c)-$(f)))) ++nonfmt-xprintf-stems := \ ++ $(foreach p,$(xprintf-funcs), \ ++ $(foreach c,$(nonfmt-convs),tst-printf-format-$(p)-$(c))) ++ ++xprintf-stems := $(sort $(fmt-xprintf-stems) $(nonfmt-xprintf-stems)) ++ + headers := \ + bits/printf-ldbl.h \ + bits/stdio_lim.h \ +@@ -240,6 +268,7 @@ endif + endif + + test-srcs = \ ++ $(xprintf-srcs) \ + tst-printf \ + tst-printfsz-islongdouble \ + tst-unbputc \ +@@ -247,6 +276,7 @@ test-srcs = \ + + ifeq ($(run-built-tests),yes) + tests-special += \ ++ $(foreach f,$(xprintf-stems),$(objpfx)$(f).out) \ + $(objpfx)tst-printf.out \ + $(objpfx)tst-printfsz-islongdouble.out \ + $(objpfx)tst-setvbuf1-cmp.out \ +@@ -257,6 +287,7 @@ tests-special += \ + ifeq (yes,$(build-shared)) + ifneq ($(PERL),no) + tests-special += \ ++ $(foreach f,$(xprintf-stems),$(objpfx)$(f)-mem.out) \ + $(objpfx)tst-freopen2-mem.out \ + $(objpfx)tst-freopen3-mem.out \ + $(objpfx)tst-freopen4-mem.out \ +@@ -276,6 +307,8 @@ tests-special += \ + # tests-special + + generated += \ ++ $(foreach f,$(xprintf-stems),$(f)-mem.out) \ ++ $(foreach f,$(xprintf-stems),$(f).mtrace) \ + tst-freopen2-mem.out \ + tst-freopen2.mtrace \ + tst-freopen3-mem.out \ +@@ -402,6 +435,21 @@ $(objpfx)tst-printf.out: tst-printf.sh $(objpfx)tst-printf + $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ + $(evaluate-test) + ++# We can't split a quoted recipe line, so do it via an auxiliary variable. ++make-tst-printf-format-out = \ ++ AWK='$(AWK)' BASH='$(BASH)' \ ++ $(BASH) $< $@ $(common-objpfx) \ ++ '$(run-program-prefix-before-env) \ ++ $(run-program-env) \ ++ MALLOC_TRACE=$(@:.out=.mtrace) \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so \ ++ $(run-program-prefix-after-env)' ++$(objpfx)tst-printf-format-%.out: \ ++ tst-printf-format.sh $(foreach c,$(convs),tst-printf-format-$(c).sh) \ ++ $(foreach f,$(xprintf-srcs),$(objpfx)$(f)) tst-printf-format.awk ++ $(make-tst-printf-format-out) > $@; \ ++ $(evaluate-test) ++ + $(objpfx)tst-printfsz-islongdouble.out: \ + tst-printfsz-islongdouble.sh $(objpfx)tst-printfsz-islongdouble + $(SHELL) $^ '$(test-program-prefix)' $@; \ +@@ -415,6 +463,10 @@ $(objpfx)tst-printf-bz18872.c: tst-printf-bz18872.sh + $(objpfx)tst-%-mem.out: $(objpfx)tst-%.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-$*.mtrace > $@; \ + $(evaluate-test) ++$(objpfx)tst-printf-format-%-mem.out: $(objpfx)tst-printf-format-%.out ++ $(common-objpfx)malloc/mtrace \ ++ $(objpfx)tst-printf-format-$*.mtrace > $@; \ ++ $(evaluate-test) + + errlist-h = $(firstword $(wildcard $(addsuffix /errlist.h,$(sysdirs) .))) + +diff --git a/stdio-common/tst-printf-format-c.sh b/stdio-common/tst-printf-format-c.sh +new file mode 100644 +index 0000000000000000..2b8d72050f670fd6 +--- /dev/null ++++ b/stdio-common/tst-printf-format-c.sh +@@ -0,0 +1,34 @@ ++#!/bin/bash ++# Testing of the 'c' printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++echo Verifying c ++(set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-c c | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion c output error, first line:\n/") 2>&1 || ++ exit 1 +diff --git a/stdio-common/tst-printf-format-char.sh b/stdio-common/tst-printf-format-char.sh +new file mode 100644 +index 0000000000000000..99219679df2ddfb7 +--- /dev/null ++++ b/stdio-common/tst-printf-format-char.sh +@@ -0,0 +1,40 @@ ++#!/bin/bash ++# Testing of signed char printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=0 ++ ++for f in d i; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-char $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-double.sh b/stdio-common/tst-printf-format-double.sh +new file mode 100644 +index 0000000000000000..b4e61acfdc615c22 +--- /dev/null ++++ b/stdio-common/tst-printf-format-double.sh +@@ -0,0 +1,74 @@ ++#!/bin/bash ++# Testing of double printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++format=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++# For floating-point formats we need to use the bignum mode even if the ++# regular mode would do, because GAWK in the latter mode uses sprintf(3) ++# internally to process the conversion requested, so any bug in our code ++# would then be verified against itself, defeating the objective of doing ++# the verification against an independent implementation. ++AWK="${AWK:-awk} -M" ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="-1.79769313486231570814527423731704357e+308" ++val=$(echo "$ref" | $AWK '{ printf "%.35e\n", $1 }' 2>&1) && ++ test "$val" = "$ref" && status=0 ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++# Check for any additional conversions that AWK handles conditionally ++# according to its version and/or the environment it has been built in. ++# The 'A' and 'a' conversions are not suitable to use at this point, as ++# output produced by AWK is different apparently due to a subtlety in ++# rounding, so do not try them. ++declare -A conversion_disabled ++ref="-inf" ++for f in f F; do ++ conversion_disabled[$f]=true ++ val=$(echo "$ref" | $AWK '{ printf "%'$f'\n", $1 }' 2>&1) && ++ test "${val^^}" = "${ref^^}" && unset conversion_disabled[$f] ++done ++ ++if test "${conversion_disabled[$format]+set}" = set; then ++ echo Unsupported $format ++ status=77 ++else ++ echo Verifying $format ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-double $format | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | ++ sed "s/^/Conversion $format output error, first line:\n/") 2>&1 || ++ status=1 ++fi ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-int.sh b/stdio-common/tst-printf-format-int.sh +new file mode 100644 +index 0000000000000000..32dcfb160a3ab5e9 +--- /dev/null ++++ b/stdio-common/tst-printf-format-int.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash ++# Testing of int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="-2147483648" ++for AWK in "$AWK -M" "$AWK"; do ++ val=$(echo "$ref" | $AWK '{ printf "%d\n", $1 }' 2>&1) || continue ++ test "$val" = "$ref" && status=0 && break ++done ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++for f in d i; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-int $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-ldouble.sh b/stdio-common/tst-printf-format-ldouble.sh +new file mode 100644 +index 0000000000000000..4bfecadea9d7fe80 +--- /dev/null ++++ b/stdio-common/tst-printf-format-ldouble.sh +@@ -0,0 +1,74 @@ ++#!/bin/bash ++# Testing of long double printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++format=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++# For floating-point formats we need to use the bignum mode even if the ++# regular mode would do, because GAWK in the latter mode uses sprintf(3) ++# internally to process the conversion requested, so any bug in our code ++# would then be verified against itself, defeating the objective of doing ++# the verification against an independent implementation. ++AWK="${AWK:-awk} -M" ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="-1.18973149535723176508575932662800702e+4932" ++val=$(echo "$ref" | $AWK '{ PREC=113; printf "%.35e\n", $1 }' 2>&1) && ++ test "$val" = "$ref" && status=0 ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++# Check for any additional conversions that AWK handles conditionally ++# according to its version and/or the environment it has been built in. ++# The 'A' and 'a' conversions are not suitable to use at this point, as ++# output produced by AWK is different apparently due to a subtlety in ++# rounding, so do not try them. ++declare -A conversion_disabled ++ref="-inf" ++for f in f F; do ++ conversion_disabled[$f]=true ++ val=$(echo "$ref" | $AWK '{ printf "%'$f'\n", $1 }' 2>&1) && ++ test "${val^^}" = "${ref^^}" && unset conversion_disabled[$f] ++done ++ ++if test "${conversion_disabled[$format]+set}" = set; then ++ echo Unsupported $format ++ status=77 ++else ++ echo Verifying $format ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-ldouble $format | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | ++ sed "s/^/Conversion $format output error, first line:\n/") 2>&1 || ++ status=1 ++fi ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-llong.sh b/stdio-common/tst-printf-format-llong.sh +new file mode 100644 +index 0000000000000000..b028a2c89b30a9b6 +--- /dev/null ++++ b/stdio-common/tst-printf-format-llong.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash ++# Testing of long long int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="9223372036854775807" ++for AWK in "$AWK -M" "$AWK"; do ++ val=$(echo "$ref" | $AWK '{ printf "%d\n", $1 }' 2>&1) || continue ++ test "$val" = "$ref" && status=0 && break ++done ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++for f in d i; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-llong $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-long.sh b/stdio-common/tst-printf-format-long.sh +new file mode 100644 +index 0000000000000000..77c67ea5bff12c05 +--- /dev/null ++++ b/stdio-common/tst-printf-format-long.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash ++# Testing of long int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="9223372036854775807" ++for AWK in "$AWK -M" "$AWK"; do ++ val=$(echo "$ref" | $AWK '{ printf "%d\n", $1 }' 2>&1) || continue ++ test "$val" = "$ref" && status=0 && break ++done ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++for f in d i; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-long $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-p-c.c b/stdio-common/tst-printf-format-p-c.c +new file mode 100644 +index 0000000000000000..ba46f55431aa59c1 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-c.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-c.c" +diff --git a/stdio-common/tst-printf-format-p-char.c b/stdio-common/tst-printf-format-p-char.c +new file mode 100644 +index 0000000000000000..7640bf8f662e3515 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-char.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-char.c" +diff --git a/stdio-common/tst-printf-format-p-double.c b/stdio-common/tst-printf-format-p-double.c +new file mode 100644 +index 0000000000000000..8271ec7beaa9e57d +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-double.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-double.c" +diff --git a/stdio-common/tst-printf-format-p-int.c b/stdio-common/tst-printf-format-p-int.c +new file mode 100644 +index 0000000000000000..cdfaaacc34772cc9 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-int.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-int.c" +diff --git a/stdio-common/tst-printf-format-p-ldouble.c b/stdio-common/tst-printf-format-p-ldouble.c +new file mode 100644 +index 0000000000000000..266989db32a848bb +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-ldouble.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-ldouble.c" +diff --git a/stdio-common/tst-printf-format-p-llong.c b/stdio-common/tst-printf-format-p-llong.c +new file mode 100644 +index 0000000000000000..936f626a45e76211 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-llong.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-llong.c" +diff --git a/stdio-common/tst-printf-format-p-long.c b/stdio-common/tst-printf-format-p-long.c +new file mode 100644 +index 0000000000000000..c82c3cac0957a1a3 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-long.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-long.c" +diff --git a/stdio-common/tst-printf-format-p-s.c b/stdio-common/tst-printf-format-p-s.c +new file mode 100644 +index 0000000000000000..4b0201ae9465a6a8 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-s.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-s.c" +diff --git a/stdio-common/tst-printf-format-p-short.c b/stdio-common/tst-printf-format-p-short.c +new file mode 100644 +index 0000000000000000..2bf17f1b2522f5ed +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-short.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-short.c" +diff --git a/stdio-common/tst-printf-format-p-uchar.c b/stdio-common/tst-printf-format-p-uchar.c +new file mode 100644 +index 0000000000000000..02a70c3f1546c422 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-uchar.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-uchar.c" +diff --git a/stdio-common/tst-printf-format-p-uint.c b/stdio-common/tst-printf-format-p-uint.c +new file mode 100644 +index 0000000000000000..e61455e01013aba0 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-uint.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-uint.c" +diff --git a/stdio-common/tst-printf-format-p-ullong.c b/stdio-common/tst-printf-format-p-ullong.c +new file mode 100644 +index 0000000000000000..16b2541acd66299f +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-ullong.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-ullong.c" +diff --git a/stdio-common/tst-printf-format-p-ulong.c b/stdio-common/tst-printf-format-p-ulong.c +new file mode 100644 +index 0000000000000000..0b3a7fd2568f763b +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-ulong.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-ulong.c" +diff --git a/stdio-common/tst-printf-format-p-ushort.c b/stdio-common/tst-printf-format-p-ushort.c +new file mode 100644 +index 0000000000000000..fa62f500ab00cbb3 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p-ushort.c +@@ -0,0 +1,20 @@ ++/* Test for formatted 'printf' 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 ++ . */ ++ ++#include "tst-printf-format-p.h" ++#include "tst-printf-format-skeleton-ushort.c" +diff --git a/stdio-common/tst-printf-format-p.h b/stdio-common/tst-printf-format-p.h +new file mode 100644 +index 0000000000000000..a9ffbb0d0e76a485 +--- /dev/null ++++ b/stdio-common/tst-printf-format-p.h +@@ -0,0 +1,29 @@ ++/* Test feature wrapper for formatted 'printf' 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 ++ . */ ++ ++#include ++ ++#define printf_under_test(...) \ ++({ \ ++ int result; \ ++ \ ++ result = printf (__VA_ARGS__); \ ++ if (result < 0) \ ++ perror ("printf"); \ ++ result; \ ++}) +diff --git a/stdio-common/tst-printf-format-s.sh b/stdio-common/tst-printf-format-s.sh +new file mode 100644 +index 0000000000000000..fa0690f9800a60ce +--- /dev/null ++++ b/stdio-common/tst-printf-format-s.sh +@@ -0,0 +1,34 @@ ++#!/bin/bash ++# Testing of the 's' printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++echo Verifying s ++(set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-s s | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion s output error, first line:\n/") 2>&1 || ++ exit 1 +diff --git a/stdio-common/tst-printf-format-short.sh b/stdio-common/tst-printf-format-short.sh +new file mode 100644 +index 0000000000000000..a610a15fa1f6e96a +--- /dev/null ++++ b/stdio-common/tst-printf-format-short.sh +@@ -0,0 +1,40 @@ ++#!/bin/bash ++# Testing of short int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=0 ++ ++for f in d i; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-short $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-skeleton-c.c b/stdio-common/tst-printf-format-skeleton-c.c +new file mode 100644 +index 0000000000000000..3f9bbc91e3a58e59 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-c.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 3 ++#define HUGE_WIDTH 4 ++#define REF_FMT "c" ++#define REF_VAL(v) (v) ++typedef unsigned char type_t; ++static const type_t vals[] = { 0, 42, UCHAR_MAX }; ++static const char length[] = ""; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-char.c b/stdio-common/tst-printf-format-skeleton-char.c +new file mode 100644 +index 0000000000000000..8c7b44b061f69cb6 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-char.c +@@ -0,0 +1,31 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 3 ++#define HUGE_WIDTH 5 ++#define REF_FMT "i" ++#define REF_VAL(v) ((((v) & 0xff) ^ 0x80) - 0x80) ++typedef int type_t; ++static const type_t vals[] = ++ { SCHAR_MIN - 123, SCHAR_MIN - 1, SCHAR_MIN, -123, -1, 0, 1, 42, SCHAR_MAX, ++ SCHAR_MAX + 1, SCHAR_MAX + 42 }; ++static const char length[] = "hh"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-double.c b/stdio-common/tst-printf-format-skeleton-double.c +new file mode 100644 +index 0000000000000000..03ac594736fd352f +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-double.c +@@ -0,0 +1,33 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++#include ++ ++#define MID_WIDTH 20 ++#define HUGE_WIDTH 320 ++#define REF_FMT ".35e" ++#define REF_VAL(v) (v) ++#define PREC DBL_MANT_DIG ++typedef double type_t; ++static const type_t vals[] = ++ { -HUGE_VAL, -DBL_MAX, -DBL_MIN, copysign (0, -1), -NAN, NAN, 0, DBL_MIN, ++ DBL_MAX, HUGE_VAL }; ++static const char length[] = ""; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-int.c b/stdio-common/tst-printf-format-skeleton-int.c +new file mode 100644 +index 0000000000000000..5d2076c53f6bbc2d +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-int.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 8 ++#define HUGE_WIDTH 15 ++#define REF_FMT "i" ++#define REF_VAL(v) (v) ++typedef int type_t; ++static const type_t vals[] = { INT_MIN, -123, -1, 0, 1, 42, INT_MAX }; ++static const char length[] = ""; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-ldouble.c b/stdio-common/tst-printf-format-skeleton-ldouble.c +new file mode 100644 +index 0000000000000000..ed47e7796390ecaf +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-ldouble.c +@@ -0,0 +1,38 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#define MID_WIDTH 20 ++#define HUGE_WIDTH 4950 ++#define REF_FMT ".35Le" ++#define REF_VAL(v) (v) ++#define PREC LDBL_MANT_DIG ++typedef long double type_t; ++static const type_t vals[] = ++ { -HUGE_VAL, -LDBL_MAX, -LDBL_MIN, copysign (0, -1), -NAN, NAN, 0, LDBL_MIN, ++ LDBL_MAX, HUGE_VAL }; ++static const char length[] = "L"; ++ ++#ifndef TIMEOUT ++# define TIMEOUT (DEFAULT_TIMEOUT * 64) ++#endif ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-llong.c b/stdio-common/tst-printf-format-skeleton-llong.c +new file mode 100644 +index 0000000000000000..9a4b7a39af660ba3 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-llong.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 15 ++#define HUGE_WIDTH 25 ++#define REF_FMT "lli" ++#define REF_VAL(v) (v) ++typedef long long int type_t; ++static const type_t vals[] = { LLONG_MIN, -123, -1, 0, 1, 42, LLONG_MAX }; ++static const char length[] = "ll"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-long.c b/stdio-common/tst-printf-format-skeleton-long.c +new file mode 100644 +index 0000000000000000..bf011b7fdb375fc6 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-long.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 15 ++#define HUGE_WIDTH 25 ++#define REF_FMT "li" ++#define REF_VAL(v) (v) ++typedef long int type_t; ++static const type_t vals[] = { LONG_MIN, -123, -1, 0, 1, 42, LONG_MAX }; ++static const char length[] = "l"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-s.c b/stdio-common/tst-printf-format-skeleton-s.c +new file mode 100644 +index 0000000000000000..59aab9fc89836ec6 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-s.c +@@ -0,0 +1,30 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 5 ++#define HUGE_WIDTH 10 ++#define REF_FMT "s" ++#define REF_VAL(v) (v) ++typedef const char *type_t; ++static const type_t vals[] = ++ { "", "The", "quick", "brown fox", "jumps over the lazy dog" }; ++static const char length[] = ""; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-short.c b/stdio-common/tst-printf-format-skeleton-short.c +new file mode 100644 +index 0000000000000000..1b7c8c09d71df95a +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-short.c +@@ -0,0 +1,31 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 4 ++#define HUGE_WIDTH 7 ++#define REF_FMT "i" ++#define REF_VAL(v) ((((v) & 0xffff) ^ 0x8000) - 0x8000) ++typedef int type_t; ++static const type_t vals[] = ++ { SHRT_MIN - 123, SHRT_MIN - 1, SHRT_MIN, -123, -1, 0, 1, 42, SHRT_MAX, ++ SHRT_MAX + 1, SHRT_MAX + 42 }; ++static const char length[] = "h"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-uchar.c b/stdio-common/tst-printf-format-skeleton-uchar.c +new file mode 100644 +index 0000000000000000..389188d746ffc508 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-uchar.c +@@ -0,0 +1,30 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 3 ++#define HUGE_WIDTH 4 ++#define REF_FMT "u" ++#define REF_VAL(v) ((v) & 0xff) ++typedef unsigned int type_t; ++static const type_t vals[] = ++ { 0, 1, 42, UCHAR_MAX, UCHAR_MAX + 1, UCHAR_MAX + 42 }; ++static const char length[] = "hh"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-uint.c b/stdio-common/tst-printf-format-skeleton-uint.c +new file mode 100644 +index 0000000000000000..6a4159111402c467 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-uint.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 7 ++#define HUGE_WIDTH 14 ++#define REF_FMT "u" ++#define REF_VAL(v) (v) ++typedef unsigned int type_t; ++static const type_t vals[] = { 0, 1, 42, UINT_MAX }; ++static const char length[] = ""; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-ullong.c b/stdio-common/tst-printf-format-skeleton-ullong.c +new file mode 100644 +index 0000000000000000..a2ad7893cfec8b11 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-ullong.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf output for unsigned long long int convs. ++ 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 14 ++#define HUGE_WIDTH 24 ++#define REF_FMT "llu" ++#define REF_VAL(v) (v) ++typedef unsigned long long int type_t; ++static const type_t vals[] = { 0, 1, 42, UINT_MAX, ULLONG_MAX }; ++static const char length[] = "ll"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-ulong.c b/stdio-common/tst-printf-format-skeleton-ulong.c +new file mode 100644 +index 0000000000000000..05cd4e0efcc657e1 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-ulong.c +@@ -0,0 +1,29 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 14 ++#define HUGE_WIDTH 24 ++#define REF_FMT "lu" ++#define REF_VAL(v) (v) ++typedef unsigned long int type_t; ++static const type_t vals[] = { 0, 1, 42, ULONG_MAX }; ++static const char length[] = "l"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton-ushort.c b/stdio-common/tst-printf-format-skeleton-ushort.c +new file mode 100644 +index 0000000000000000..5cc2e0283a54fa04 +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton-ushort.c +@@ -0,0 +1,30 @@ ++/* Test skeleton for formatted printf output for unsigned short int convs. ++ 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 ++ . */ ++ ++#include ++ ++#define MID_WIDTH 3 ++#define HUGE_WIDTH 6 ++#define REF_FMT "u" ++#define REF_VAL(v) ((v) & 0xffff) ++typedef unsigned int type_t; ++static const type_t vals[] = ++ { 0, 1, 42, USHRT_MAX, USHRT_MAX + 1, USHRT_MAX + 42 }; ++static const char length[] = "h"; ++ ++#include "tst-printf-format-skeleton.c" +diff --git a/stdio-common/tst-printf-format-skeleton.c b/stdio-common/tst-printf-format-skeleton.c +new file mode 100644 +index 0000000000000000..e564d3a85395507e +--- /dev/null ++++ b/stdio-common/tst-printf-format-skeleton.c +@@ -0,0 +1,380 @@ ++/* Test skeleton for formatted printf 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 ++ . */ ++ ++/* The following definitions have to be supplied by the source including ++ this skeleton: ++ ++ Macros: ++ MID_WIDTH Medium width/precision positive integer constant. Choose ++ such as to cause some, but not all the strings produced ++ to be truncated for the conversions handled. ++ HUGE_WIDTH Large width/precision positive integer constant. Choose ++ such as to cause none of the strings produced to be ++ truncated for the conversions handled. ++ REF_FMT Reference output format string. Use no flags and such ++ a precision and length modifier, where applicable, and ++ a conversion as to make sure the output produced allows ++ the original value to be reproduced. ++ REF_VAL(v) Reference value V transformation. For conversions with ++ a truncating length modifier define such as to reproduce ++ the truncation operation, otherwise let V pass through. ++ PREC [optional] Working precision positive integer constant. ++ Set to the number of binary digits in the significand for ++ the argument type handled; usually for floating-point ++ conversions only, but it may be required for 128-bit or ++ wider integer data types as well. ++ ++ Typedefs: ++ type_t Variadic function argument type. Define to the promoted ++ type corresponding to the conversion argument type ++ handled. ++ ++ Variables: ++ vals Array of TYPE_T values. Choose such as to cover boundary ++ and any special cases. ++ length Length modifier string. Define according to the ++ conversion argument type handled. ++ ++ The feature to be tested is wrapped into 'printf_under_test'. It is up ++ to the source including this skeleton if this is going to be a macro ++ or an actual function. ++ ++ See tst-*printf-format-*.c for usage examples. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to nonzero to select all possible tuples with repetitions of 1..n ++ elements from the set of flags as defined in FLAGS array below; n is ++ the length of FLAGS array. Otherwise select all possible tuples with ++ repetitions of 1..2 elements, followed by tuples of 3..n elements where ++ the index of each element k; k = 2..n in FLAGS is lower than the index ++ of element k-1 in FLAGS. */ ++#ifndef TST_PRINTF_DUPS ++# define TST_PRINTF_DUPS 0 ++#endif ++/* Set to nonzero to report the precision (number of significand digits) ++ required for floating-point calculations. */ ++#ifndef PREC ++# define PREC 0 ++#endif ++ ++/* The list of conversions permitted for the '#' flag, the '0' flag, ++ and precision respectively. */ ++#define HASH_FORMATS "boxXaAeEfFgG" ++#define ZERO_FORMATS "bdiouxXaAeEfFgG" ++#define PREC_FORMATS "bdiouxXaAeEfFgGs" ++ ++/* Output format conversion flags. */ ++static struct ++{ ++ /* Flag character. */ ++ char f; ++ /* List of conversion specifiers the flag is valid for; NULL if all. */ ++ const char *s; ++} const flags[] = ++ { {'-'}, {'+'}, {' '}, {'#', HASH_FORMATS}, {'0', ZERO_FORMATS} }; ++ ++/* Helper to initialize elements of the PW array for the width and ++ precision to be specified as a positive integer directly in the ++ format, and then as both a negative and a positive argument to '*'. */ ++#define STR(v) #v ++#define WPINIT(v) {0, STR (v)}, {v, NULL}, {-v, NULL} ++ ++/* Width and precision settings to iterate over; zero is initialized ++ directly as it has no corresponding negated value and other values ++ use the helper above. */ ++static struct wp ++{ ++ /* Integer argument to '*', used if S is NULL. */ ++ int i; ++ /* String denoting an integer to use in the format, or NULL to use '*'. */ ++ const char *s; ++} const wp[] = ++ { {0, "0"}, {0, NULL}, WPINIT (1), WPINIT (2), ++ WPINIT (MID_WIDTH), WPINIT (HUGE_WIDTH) }; ++ ++/* Produce a record according to '%' and zero or more output format flags ++ already provided in FMT at indices 0..IDX-1, width W if non-NULL, '.' ++ precision specifier if POINT set to true, precision P if non-NULL, ++ any length modifiers L, conversion C, and value VAL. ++ ++ Record formats produced: ++ ++ %:: ++ %.:: ++ %:: ++ %.:: ++ %.

:: ++ %.

:: ++ %*::: ++ %*.::: ++ %.*:

:: ++ %*.*::

:: ++ ++ Return 0 on success, -1 on failure. */ ++ ++static int ++do_printf (char *fmt, size_t idx, ++ const struct wp *w, bool point, const struct wp *p, ++ const char *l, char c, type_t val) ++{ ++ int wpval[2] = { 0 }; ++ size_t nint = 0; ++ int result; ++ size_t i; ++ ++ if (w != NULL) ++ { ++ if (w->s == NULL) ++ { ++ fmt[idx++] = '*'; ++ wpval[nint++] = w->i; ++ } ++ else ++ for (i = 0; w->s[i] != '\0'; i++) ++ fmt[idx++] = w->s[i]; ++ } ++ if (point) ++ fmt[idx++] = '.'; ++ if (p != NULL) ++ { ++ if (p->s == NULL) ++ { ++ fmt[idx++] = '*'; ++ wpval[nint++] = p->i; ++ } ++ else ++ for (i = 0; p->s[i] != '\0'; i++) ++ fmt[idx++] = p->s[i]; ++ } ++ for (i = 0; length[i] != '\0'; i++) ++ fmt[idx++] = length[i]; ++ fmt[idx++] = c; ++ fmt[idx] = ':'; ++ fmt[idx + 1] = '\0'; ++ if (fputs (fmt, stdout) == EOF) ++ { ++ perror ("fputs"); ++ return -1; ++ } ++ fmt[idx++] = '\0'; ++ if (nint > 0) ++ { ++ result = printf ("%i:", wpval[0]); ++ if (result < 0) ++ { ++ perror ("printf"); ++ return -1; ++ } ++ if (nint > 1) ++ { ++ result = printf ("%i:", wpval[1]); ++ if (result < 0) ++ { ++ perror ("printf"); ++ return -1; ++ } ++ } ++ } ++ switch (nint) ++ { ++ case 0: ++ result = printf_under_test (fmt, val); ++ break; ++ case 1: ++ result = printf_under_test (fmt, wpval[0], val); ++ break; ++ case 2: ++ result = printf_under_test (fmt, wpval[0], wpval[1], val); ++ break; ++ default: ++ fputs ("Broken test, nint > 2\n", stderr); ++ return -1; ++ } ++ if (result < 0) ++ return -1; ++ if (fputs (":\n", stdout) == EOF) ++ { ++ perror ("fputs"); ++ return -1; ++ } ++ return 0; ++} ++ ++/* Produce a list of records according to '%' and zero or more output ++ format flags already provided in FMT at indices 0..IDX-1, iterating ++ over widths and precisions defined in global WP array, any length ++ modifiers L, conversion C, and value VAL. Inline '0' is omitted for ++ the width, as it is a flag already handled among the flags supplied. ++ Precision is omitted where the conversion does not allow it. ++ ++ Return 0 on success, -1 on failure. */ ++ ++static int ++do_printf_flags (char *fmt, size_t idx, const char *l, char c, type_t val) ++{ ++ bool do_prec = strchr (PREC_FORMATS, c) != NULL; ++ size_t i; ++ ++ if (do_printf (fmt, idx, NULL, false, NULL, l, c, val) < 0) ++ return -1; ++ if (do_prec && do_printf (fmt, idx, NULL, true, NULL, l, c, val) < 0) ++ return -1; ++ for (i = 0; i < array_length (wp); i++) ++ { ++ size_t j; ++ ++ if (do_prec && do_printf (fmt, idx, NULL, true, wp + i, l, c, val) < 0) ++ return -1; ++ /* Inline '0' is a flag rather than width and is handled elsewhere. */ ++ if (wp[i].s != NULL && wp[i].s[0] == '0' && wp[i].s[1] == '\0') ++ continue; ++ if (do_printf (fmt, idx, wp + i, false, NULL, l, c, val) < 0) ++ return -1; ++ if (do_prec) ++ { ++ if (do_printf (fmt, idx, wp + i, true, NULL, l, c, val) < 0) ++ return -1; ++ for (j = 0; j < array_length (wp); j++) ++ if (do_printf (fmt, idx, wp + i, true, wp + j, l, c, val) < 0) ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++/* Produce a list of records using the formatted output specifier ++ supplied in ARGV[1] preceded by any length modifier supplied in ++ the global LENGTH variable, iterating over format flags defined ++ in the global FLAGS array, and values supplied in the global VALS ++ array. Note that the output specifier supplied is not verified ++ against TYPE_T, so undefined behavior will result if this is used ++ incorrectly. ++ ++ If PREC is nonzero, then this record: ++ ++ prec: ++ ++ is produced at the beginning. Then for each VAL from VALS a block ++ of records is produced starting with: ++ ++ val: ++ ++ where VAL is formatted according to REF_FMT output format. The ++ block continues with records as shown with DO_PRINTF above using ++ flags iterated over according to TST_PRINTF_DUPS. ++ ++ See the top of this file for the definitions that have to be ++ provided by the source including this skeleton. */ ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ char fmt[100] = {'%'}; ++ size_t j; ++ size_t v; ++ char c; ++ ++ if (argc < 2 || *argv[1] == '\0') ++ { ++ fprintf (stderr, "Usage: %s \n", basename (argv[0])); ++ return EXIT_FAILURE; ++ } ++ ++ mtrace (); ++ ++ if (PREC && printf ("prec:%i\n", PREC) < 0) ++ { ++ perror ("printf"); ++ return EXIT_FAILURE; ++ } ++ ++ c = *argv[1]; ++ for (v = 0; v < array_length (vals); v++) ++ { ++ if (printf ("val:%" REF_FMT "\n", REF_VAL (vals[v])) < 0) ++ { ++ perror ("printf"); ++ return EXIT_FAILURE; ++ } ++ ++ if (do_printf_flags (fmt, 1, length, c, vals[v]) < 0) ++ return EXIT_FAILURE; ++ for (j = 0; j < array_length (flags); j++) ++ { ++ bool done = false; ++ size_t i[j + 1]; ++ size_t k; ++ ++ memset (i, 0, sizeof (i)); ++ while (!done) ++ { ++ bool skip = false; ++ size_t idx = 1; ++ char f; ++ ++ for (k = 0; k <= j; k++) ++ { ++ const char *s = flags[i[k]].s; ++ ++ if (s && strchr (s, c) == NULL) ++ skip = true; ++ if (!TST_PRINTF_DUPS && j > 1 && k > 0 && i[k] >= i[k - 1]) ++ skip = true; ++ if (skip) ++ break; ++ ++ f = flags[i[k]].f; ++ fmt[idx++] = f; ++ } ++ if (!skip && do_printf_flags (fmt, idx, length, c, vals[v]) < 0) ++ return EXIT_FAILURE; ++ for (k = 0; k <= j; k++) ++ { ++ i[k]++; ++ if (i[k] < array_length (flags)) ++ break; ++ else if (k == j) ++ done = true; ++ else ++ i[k] = 0; ++ } ++ } ++ } ++ } ++ ++ return EXIT_SUCCESS; ++} ++ ++/* Interpose 'dladdr' with a stub to speed up malloc tracing. */ ++ ++int ++dladdr (const void *, Dl_info *) ++{ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/stdio-common/tst-printf-format-uchar.sh b/stdio-common/tst-printf-format-uchar.sh +new file mode 100644 +index 0000000000000000..8385d479cccf597f +--- /dev/null ++++ b/stdio-common/tst-printf-format-uchar.sh +@@ -0,0 +1,40 @@ ++#!/bin/bash ++# Testing of unsigned char printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=0 ++ ++for f in o u x X; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-uchar $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-uint.sh b/stdio-common/tst-printf-format-uint.sh +new file mode 100644 +index 0000000000000000..6806c99ce0470f1a +--- /dev/null ++++ b/stdio-common/tst-printf-format-uint.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash ++# Testing of unsigned int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="4294967295" ++for AWK in "$AWK -M" "$AWK"; do ++ val=$(echo "$ref" | $AWK '{ printf "%d\n", $1 }' 2>&1) || continue ++ test "$val" = "$ref" && status=0 && break ++done ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++for f in o u x X; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-uint $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-ullong.sh b/stdio-common/tst-printf-format-ullong.sh +new file mode 100644 +index 0000000000000000..c4fa69c2d16f85ce +--- /dev/null ++++ b/stdio-common/tst-printf-format-ullong.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash ++# Testing of unsigned long long int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="18446744073709551615" ++for AWK in "$AWK -M" "$AWK"; do ++ val=$(echo "$ref" | $AWK '{ printf "%d\n", $1 }' 2>&1) || continue ++ test "$val" = "$ref" && status=0 && break ++done ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++for f in o u x X; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-ullong $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-ulong.sh b/stdio-common/tst-printf-format-ulong.sh +new file mode 100644 +index 0000000000000000..fce881afe3c0be72 +--- /dev/null ++++ b/stdio-common/tst-printf-format-ulong.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash ++# Testing of unsigned long int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=77 ++ ++# Verify that AWK can handle the range required. It also catches: ++# "gawk: warning: -M ignored: MPFR/GMP support not compiled in" ++# message produced where bignum support is not there, which is the ++# only indication as the use of '-M' does not affect the exit status ++# in this case. ++ref="18446744073709551615" ++for AWK in "$AWK -M" "$AWK"; do ++ val=$(echo "$ref" | $AWK '{ printf "%d\n", $1 }' 2>&1) || continue ++ test "$val" = "$ref" && status=0 && break ++done ++ ++test $status -eq 0 || { echo "No working AWK found" && exit $status; } ++ ++for f in o u x X; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-ulong $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format-ushort.sh b/stdio-common/tst-printf-format-ushort.sh +new file mode 100644 +index 0000000000000000..2f411b777e67e220 +--- /dev/null ++++ b/stdio-common/tst-printf-format-ushort.sh +@@ -0,0 +1,40 @@ ++#!/bin/bash ++# Testing of unsigned short int printf 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 ++# . ++ ++set -e ++ ++xprintf=$1; shift ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++AWK=${AWK:-awk} ++ ++status=0 ++ ++for f in o u x X; do ++ echo Verifying $f ++ (set -o pipefail ++ ${test_program_prefix} \ ++ ${common_objpfx}stdio-common/tst-printf-format-${xprintf}-ushort $f | ++ $AWK -f tst-printf-format.awk 2>&1 | ++ head -n 1 | sed "s/^/Conversion $f output error, first line:\n/") 2>&1 || ++ status=1 ++done ++ ++exit $status +diff --git a/stdio-common/tst-printf-format.awk b/stdio-common/tst-printf-format.awk +new file mode 100644 +index 0000000000000000..8b4bc7b1e45202eb +--- /dev/null ++++ b/stdio-common/tst-printf-format.awk +@@ -0,0 +1,127 @@ ++# Testing of printf 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 ++# . ++ ++BEGIN { ++ FS = ":" ++} ++ ++/^prec:/ { ++ PREC = $2 ++ next ++} ++ ++/^val:/ { ++ val = $2 ++ # Prepend "+" for +Inf or +NaN value lacking a sign, because gawk ++ # interpretes them as strings rather than numeric values in the ++ # non-bignum mode unless a sign has been explicitly given. Keep ++ # original 'val' for reporting. ++ value = gensub(/^(INF|NAN|inf|nan)/, "+\\1", 1, val) ++ next ++} ++ ++/^%/ { ++ # Discard the trailing empty field, used to improve legibility of data. ++ input = $--NF ++ format = $1 ++ width = $2 ++ precision = "." $(NF - 1) ++ # Discard any negative precision, which is to be taken as if omitted. ++ sub(/\.-.*/, "", precision) ++ # Simplify handling and paste the precision and width specified as ++ # arguments to '*' directly into the format. ++ sub(/\.\*/, precision, format) ++ sub(/\*/, width, format) ++ # Discard length modifiers. They are only relevant to C data types. ++ sub(/([DHLjhltz]|wf?[1-9][0-9]*)/, "", format) ++ # Discard the '#' flag with the octal conversion if output starts with ++ # 0 in the absence of this flag. In that case no extra 0 is supposed ++ # to be produced, but gawk prepends it anyway. ++ if (format ~ /#.*o/) ++ { ++ tmpfmt = gensub(/#/, "", "g", format) ++ tmpout = sprintf(tmpfmt, value) ++ if (tmpout ~ /^ *0/) ++ format = tmpfmt ++ } ++ # Likewise with the hexadecimal conversion where zero value with the ++ # precision of zero is supposed to produce no characters, but gawk ++ # outputs 0 instead. ++ else if (format ~ /#.*[Xx]/) ++ { ++ tmpfmt = gensub(/#/, "", "g", format) ++ tmpout = sprintf(tmpfmt, value) ++ if (tmpout ~ /^ *$/) ++ format = tmpfmt ++ } ++ # AWK interpretes input opportunistically as a number, which interferes ++ # with how the 'c' conversion works: "a" input will result in "a" output ++ # however "0" input will result in "^@" output rather than "0". Force ++ # the value to be interpreted as a string then, by appending "". ++ output = sprintf(format, value "") ++ # Make up for various anomalies with the handling of +/-Inf and +/-NaN ++ # values and reprint the output produced using the string conversion, ++ # with the field width carried over and the relevant flags handled by ++ # hand. ++ if (format ~ /[EFGefg]/ && value ~ /(INF|NAN|inf|nan)/) ++ { ++ minus = format ~ /-/ ? "-" : "" ++ sign = value ~ /-/ ? "-" : format ~ /\+/ ? "+" : format ~ / / ? " " : "" ++ if (format ~ /^%[^\.1-9]*[1-9][0-9]*/) ++ width = gensub(/^%[^\.1-9]*([1-9][0-9]*).*$/, "\\1", 1, format) ++ else ++ width = "" ++ output = gensub(/[-+ ]/, "", "g", output) ++ output = sprintf("%" minus width "s", sign output) ++ } ++ # Produce "+" where the '+' flag has been used with a signed integer ++ # conversion for zero value, observing any field width in effect. ++ # In that case "+" is always supposed to be produced, but with the ++ # precision of zero gawk in the non-bignum mode produces any padding ++ # requested only. ++ else if (format ~ /\+.*[di]/ && value == 0) ++ { ++ output = gensub(/^( *) $/, format ~ /-/ ? "+\\1" : "\\1+", 1, output) ++ output = gensub(/^$/, "+", 1, output) ++ } ++ # Produce " " where the space flag has been used with a signed integer ++ # conversion for zero value. In that case at least one " " is ++ # supposed to be produced, but with the precision of zero gawk in the ++ # non-bignum mode produces nothing. ++ else if (format ~ / .*[di]/ && value == 0) ++ { ++ output = gensub(/^$/, " ", 1, output) ++ } ++ if (output != input) ++ { ++ printf "(\"%s\"%s%s, %s) => \"%s\", expected \"%s\"\n", \ ++ $1, (NF > 2 ? ", " $2 : ""), (NF > 3 ? ", " $3 : ""), val, \ ++ input, output > "/dev/stderr" ++ status = 1 ++ } ++ next ++} ++ ++{ ++ printf "unrecognized input: \"%s\"\n", $0 > "/dev/stderr" ++ status = 1 ++} ++ ++END { ++ exit status ++} +diff --git a/stdio-common/tst-printf-format.sh b/stdio-common/tst-printf-format.sh +new file mode 100644 +index 0000000000000000..466c4a5f4feac231 +--- /dev/null ++++ b/stdio-common/tst-printf-format.sh +@@ -0,0 +1,39 @@ ++#!/bin/bash ++# Formatted printf output test script dispatcher. ++# 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 ++# . ++ ++set -e ++ ++output=${1##*/}; shift ++ ++tmp=${output#tst-printf-format-} ++tmp=${tmp%.out} ++ ++# We are given the name of the make target in $1. With the common prefix ++# and suffix both removed we are left with the inner part, which encodes ++# the function under test, the conversion type, and optionally the format ++# specifier, all separated with hyphens, i.e. F-T-S or F-T. Extract them ++# and call the script corresponding to the conversion type, passing the ++# function under test and any format specifier as arguments. ++ ++xprintf=${tmp%%-*}; tmp=${tmp#*-} ++conv=${tmp%%-*}; tmp=${tmp#${conv}} ++fmt=${tmp#*-} ++script=tst-printf-format-$conv.sh ++ ++exec ${BASH:-bash} $script $xprintf $fmt "$@" diff --git a/SOURCES/glibc-RHEL-46725-10.patch b/SOURCES/glibc-RHEL-46725-10.patch new file mode 100644 index 0000000..95d1f17 --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-10.patch @@ -0,0 +1,428 @@ +commit 6018ba05c01b1e17d77742a123e8c443f8fc713c +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++ ++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; ++} diff --git a/SOURCES/glibc-RHEL-46725-11.patch b/SOURCES/glibc-RHEL-46725-11.patch new file mode 100644 index 0000000..dc87993 --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-11.patch @@ -0,0 +1,458 @@ +commit ac72dd90905e1693c108c9f36f0c7e79d6ad5501 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#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; ++} diff --git a/SOURCES/glibc-RHEL-46725-12.patch b/SOURCES/glibc-RHEL-46725-12.patch new file mode 100644 index 0000000..4017bda --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-12.patch @@ -0,0 +1,458 @@ +commit 11a2169e4066e6b848f1e6e4c31ec4e2210cecd8 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#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; ++} diff --git a/SOURCES/glibc-RHEL-46725-2.patch b/SOURCES/glibc-RHEL-46725-2.patch new file mode 100644 index 0000000..03f480f --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-2.patch @@ -0,0 +1,459 @@ +commit b350a60b6ecd77b7ec30c7969de1df8b73642e55 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++ ++#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 diff --git a/SOURCES/glibc-RHEL-46725-3.patch b/SOURCES/glibc-RHEL-46725-3.patch new file mode 100644 index 0000000..3312e21 --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-3.patch @@ -0,0 +1,452 @@ +commit b3e8a756ad569fd31181b74b3729d29df3eb55f3 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* 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; \ ++}) diff --git a/SOURCES/glibc-RHEL-46725-4.patch b/SOURCES/glibc-RHEL-46725-4.patch new file mode 100644 index 0000000..5a69126 --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-4.patch @@ -0,0 +1,423 @@ +commit 1dc5cdc3da19e10d47e50a5ea2ea3ce62ee2fa82 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++ ++#define printf_under_test(...) \ ++({ \ ++ int result; \ ++ \ ++ result = fprintf (stdout, __VA_ARGS__); \ ++ if (result < 0) \ ++ perror ("fprintf"); \ ++ result; \ ++}) diff --git a/SOURCES/glibc-RHEL-46725-5.patch b/SOURCES/glibc-RHEL-46725-5.patch new file mode 100644 index 0000000..411003a --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-5.patch @@ -0,0 +1,454 @@ +commit c683ac8520e8064e7be3a22922d80849271290ac +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++#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; \ ++}) diff --git a/SOURCES/glibc-RHEL-46725-6.patch b/SOURCES/glibc-RHEL-46725-6.patch new file mode 100644 index 0000000..6d13904 --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-6.patch @@ -0,0 +1,454 @@ +commit 0b6379cb98590c28088f017ddcc0edb8ad7d0131 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++#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; \ ++}) diff --git a/SOURCES/glibc-RHEL-46725-7.patch b/SOURCES/glibc-RHEL-46725-7.patch new file mode 100644 index 0000000..d4ff4ba --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-7.patch @@ -0,0 +1,428 @@ +commit bad554d9b4f10988eb7fdb814fbaa5e89416d781 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++ ++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; ++} diff --git a/SOURCES/glibc-RHEL-46725-8.patch b/SOURCES/glibc-RHEL-46725-8.patch new file mode 100644 index 0000000..8f0a2be --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-8.patch @@ -0,0 +1,454 @@ +commit 349670f8093d920d4d683472c88029f6901f7ae7 +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46725-9.patch b/SOURCES/glibc-RHEL-46725-9.patch new file mode 100644 index 0000000..14f90da --- /dev/null +++ b/SOURCES/glibc-RHEL-46725-9.patch @@ -0,0 +1,456 @@ +commit fae4eacae75e4f2767998aca703d6efaae2a747f +Author: Maciej W. Rozycki +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 + +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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* 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; ++} diff --git a/SOURCES/glibc-RHEL-46728.patch b/SOURCES/glibc-RHEL-46728.patch new file mode 100644 index 0000000..439d9ab --- /dev/null +++ b/SOURCES/glibc-RHEL-46728.patch @@ -0,0 +1,287 @@ +From 4945ffc88a8ad49280bae64165683ddfd12b2390 Mon Sep 17 00:00:00 2001 +From: DJ Delorie +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 + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* 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 diff --git a/SOURCES/glibc-RHEL-46733-1.patch b/SOURCES/glibc-RHEL-46733-1.patch new file mode 100644 index 0000000..acab115 --- /dev/null +++ b/SOURCES/glibc-RHEL-46733-1.patch @@ -0,0 +1,171 @@ +Partial backport (libio/Makefile, stdio-common/Makefile only) of: + +commit a7fe3e805d2ee128ac5f43b2a24201726d41cc04 +Author: Carlos O'Donell +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 + +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 diff --git a/SOURCES/glibc-RHEL-46733-2.patch b/SOURCES/glibc-RHEL-46733-2.patch new file mode 100644 index 0000000..16a0bf4 --- /dev/null +++ b/SOURCES/glibc-RHEL-46733-2.patch @@ -0,0 +1,79 @@ +commit 3e4a01870ef9605ccf6475215a4b32aa86d5d206 +Author: Aaron Merey +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 + +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 ++ . */ ++ ++#include ++#include ++ ++/* 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 diff --git a/SOURCES/glibc-RHEL-46733-3.patch b/SOURCES/glibc-RHEL-46733-3.patch new file mode 100644 index 0000000..753c87b --- /dev/null +++ b/SOURCES/glibc-RHEL-46733-3.patch @@ -0,0 +1,155 @@ +commit 35dc62de3d5d73a91d4ca8fa9799b510a34d170d +Author: Aaron Merey +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 + +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 + #include + +-/* 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* 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 +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 diff --git a/SOURCES/glibc-RHEL-46734.patch b/SOURCES/glibc-RHEL-46734.patch new file mode 100644 index 0000000..d63056b --- /dev/null +++ b/SOURCES/glibc-RHEL-46734.patch @@ -0,0 +1,273 @@ +commit 1d72fa3cfa046f7293421a7e58f2a272474ea901 +Author: Sergey Kolosov +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 + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46735.patch b/SOURCES/glibc-RHEL-46735.patch new file mode 100644 index 0000000..7dd21db --- /dev/null +++ b/SOURCES/glibc-RHEL-46735.patch @@ -0,0 +1,167 @@ +commit d14c977c65aac7db35bb59380ef99d6582c4f930 +Author: Joseph Myers +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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46736-1.patch b/SOURCES/glibc-RHEL-46736-1.patch new file mode 100644 index 0000000..16146ee --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-1.patch @@ -0,0 +1,67 @@ +commit e3fdbe9f39747206b9c3fbb0219f29fd5b35d020 +Author: Adhemerval Zanella +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 ++ . */ ++ ++#include ++#include ++#include ++ ++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); diff --git a/SOURCES/glibc-RHEL-46736-10.patch b/SOURCES/glibc-RHEL-46736-10.patch new file mode 100644 index 0000000..d65bf05 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-10.patch @@ -0,0 +1,30 @@ +commit 6948ee4edf0c57c556f8d5f394d9191216d05780 +Author: Florian Weimer +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 diff --git a/SOURCES/glibc-RHEL-46736-11.patch b/SOURCES/glibc-RHEL-46736-11.patch new file mode 100644 index 0000000..ed7722a --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-11.patch @@ -0,0 +1,216 @@ +commit 42c810c2cf3554afbdd60885b7da6bb4e702466f +Author: Joseph Myers +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 +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 +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 diff --git a/SOURCES/glibc-RHEL-46736-2.patch b/SOURCES/glibc-RHEL-46736-2.patch new file mode 100644 index 0000000..9adda66 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-2.patch @@ -0,0 +1,168 @@ +commit da55fae9e277a0c138d4395fee505e5d2f8b2b84 +Author: Carlos O'Donell +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 = \ diff --git a/SOURCES/glibc-RHEL-46736-3.patch b/SOURCES/glibc-RHEL-46736-3.patch new file mode 100644 index 0000000..2dde8b5 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-3.patch @@ -0,0 +1,261 @@ +commit 96d0bf98cafd0b63721f369ca21ec64590551d47 +Author: Joseph Myers +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 ++ . */ ++ ++#ifndef SUPPORT_FILE_CONTENTS_H ++#define SUPPORT_FILE_CONTENTS_H ++ ++#include ++#include ++ ++__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 ++ . */ ++ ++#include ++ ++#include ++ ++/* 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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++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 ++ . */ ++ ++#include ++#include ++ ++/* 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 ++ . */ ++ ++#include ++ ++#include ++#include ++ ++/* 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)); ++} diff --git a/SOURCES/glibc-RHEL-46736-4.patch b/SOURCES/glibc-RHEL-46736-4.patch new file mode 100644 index 0000000..cb728cb --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-4.patch @@ -0,0 +1,739 @@ +commit ed4bb289cf739f537deb735eaa01be531df084b9 +Author: Joseph Myers +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 +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 +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 diff --git a/SOURCES/glibc-RHEL-46736-5.patch b/SOURCES/glibc-RHEL-46736-5.patch new file mode 100644 index 0000000..ca67e62 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-5.patch @@ -0,0 +1,69 @@ +commit f512634ddef242ef0ff025ddeba64ce51035040f +Author: Joseph Myers +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; diff --git a/SOURCES/glibc-RHEL-46736-6.patch b/SOURCES/glibc-RHEL-46736-6.patch new file mode 100644 index 0000000..5650c7b --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-6.patch @@ -0,0 +1,119 @@ +commit 9c0d6f7a1046aba111e25e34ec07242853e859dc +Author: Joseph Myers +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 + #include ++#include + #include + #include + +@@ -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); diff --git a/SOURCES/glibc-RHEL-46736-7.patch b/SOURCES/glibc-RHEL-46736-7.patch new file mode 100644 index 0000000..e025835 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-7.patch @@ -0,0 +1,86 @@ +commit e44ca1c085b3bd41266c882ea1cb0fd436231635 +Author: Joseph Myers +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); diff --git a/SOURCES/glibc-RHEL-46736-8.patch b/SOURCES/glibc-RHEL-46736-8.patch new file mode 100644 index 0000000..c265ed5 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-8.patch @@ -0,0 +1,33 @@ +commit a2509a8bc955988f01f389a1cf74db3a9da42409 +Author: Joseph Myers +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 + 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}) diff --git a/SOURCES/glibc-RHEL-46736-9.patch b/SOURCES/glibc-RHEL-46736-9.patch new file mode 100644 index 0000000..f9316a1 --- /dev/null +++ b/SOURCES/glibc-RHEL-46736-9.patch @@ -0,0 +1,495 @@ +commit e0f3bf10acf4aab27752847828bfecd3fce41190 +Author: Joseph Myers +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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 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 +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 +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 +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 +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 +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 diff --git a/SOURCES/glibc-RHEL-46738-1.patch b/SOURCES/glibc-RHEL-46738-1.patch new file mode 100644 index 0000000..e6e0118 --- /dev/null +++ b/SOURCES/glibc-RHEL-46738-1.patch @@ -0,0 +1,34 @@ +From 53fcdf5f743aa9b02972eec658e66f96d6a63386 Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +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: +Link: +Signed-off-by: Alejandro Colomar + +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 diff --git a/SOURCES/glibc-RHEL-46738-2.patch b/SOURCES/glibc-RHEL-46738-2.patch new file mode 100644 index 0000000..c2423d5 --- /dev/null +++ b/SOURCES/glibc-RHEL-46738-2.patch @@ -0,0 +1,52 @@ +From bd0ea9ff7e8d5f7d54112dfa96d541c3c60e36ae Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +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" +Cc: Siddhesh Poyarekar +Cc: Bruno Haible +Cc: Martin Uecker +Cc: Xi Ruoyao +Cc: Florian Weimer +Cc: Joseph Myers +Signed-off-by: Alejandro Colomar +Reviewed-by: Maciej W. Rozycki + +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 + diff --git a/SOURCES/glibc-RHEL-46738-3.patch b/SOURCES/glibc-RHEL-46738-3.patch new file mode 100644 index 0000000..3b57355 --- /dev/null +++ b/SOURCES/glibc-RHEL-46738-3.patch @@ -0,0 +1,21 @@ +From cfdd9e7aa45cdc575df237e2d2eee3219a06829b Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +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 +Reviewed-by: Maciej W. Rozycki + +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 diff --git a/SOURCES/glibc-RHEL-46738-4.patch b/SOURCES/glibc-RHEL-46738-4.patch new file mode 100644 index 0000000..6f30744 --- /dev/null +++ b/SOURCES/glibc-RHEL-46738-4.patch @@ -0,0 +1,405 @@ +From ae5062201d7e9d18fe88bff4bc71088374c394fb Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +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 +Reviewed-by: Maciej W. Rozycki + +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 . + +@@ -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 . + +@@ -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 . + Based on the single byte version by Per Bothner . +@@ -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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46738-5.patch b/SOURCES/glibc-RHEL-46738-5.patch new file mode 100644 index 0000000..9eb8107 --- /dev/null +++ b/SOURCES/glibc-RHEL-46738-5.patch @@ -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. */ diff --git a/SOURCES/glibc-RHEL-46739-1.patch b/SOURCES/glibc-RHEL-46739-1.patch new file mode 100644 index 0000000..2292c12 --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-1.patch @@ -0,0 +1,49 @@ +commit 207d64feb26279e152c50744e3c37e68491aca99 +Author: Joseph Myers +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 + #include + #include + #include +@@ -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; \ ++ } \ + } \ + } + diff --git a/SOURCES/glibc-RHEL-46739-10.patch b/SOURCES/glibc-RHEL-46739-10.patch new file mode 100644 index 0000000..0bcd14c --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-10.patch @@ -0,0 +1,38 @@ +commit 378039ca578c2ea93095a1e710d96f58c68a3997 +Author: Joseph Myers +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 }, \ diff --git a/SOURCES/glibc-RHEL-46739-11.patch b/SOURCES/glibc-RHEL-46739-11.patch new file mode 100644 index 0000000..0e21b24 --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-11.patch @@ -0,0 +1,439 @@ +commit 94ca2c0894f0e1b62625c369cc598a2b9236622c +Author: Joseph Myers +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 + . */ + ++/* 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 + #include + #include +@@ -25,6 +29,60 @@ + #include + #include + ++#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); + } diff --git a/SOURCES/glibc-RHEL-46739-2.patch b/SOURCES/glibc-RHEL-46739-2.patch new file mode 100644 index 0000000..da1873c --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-2.patch @@ -0,0 +1,16723 @@ +commit d73ed2601b7c3c93c3529149a3d7f7b6177900a8 +Author: Joseph Myers +Date: Tue Aug 27 12:38:01 2024 +0000 + + More thoroughly test underflow / errno in tst-strtod-round + + Add tests of underflow in tst-strtod-round, and thus also test for + errno being unchanged when there is neither overflow nor underflow. + The errno setting before the function call to test for being unchanged + is adjusted to set errno to 12345 instead of 0, so that any bugs where + strtod sets errno to 0 would be detected. + + This doesn't add any new test inputs for tst-strtod-round, and in + particular doesn't cover the edge cases of underflow the way + tst-strtod-underflow does (none of the existing test inputs for + tst-strtod-round actually exercise cases that have underflow with + before-rounding tininess detection but not with after-rounding + tininess detection), but at least it provides some coverage (as per + the recent discussions) that ordinary non-overflowing non-underflowing + inputs to these functions do not set errno. + + Tested for x86_64. + +diff --git a/stdlib/gen-tst-strtod-round.c b/stdlib/gen-tst-strtod-round.c +index 94d6afeaefac26af..48baacd6eabcbfc4 100644 +--- a/stdlib/gen-tst-strtod-round.c ++++ b/stdlib/gen-tst-strtod-round.c +@@ -46,6 +46,7 @@ static int + string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd) + { + mpfr_clear_overflow (); ++ mpfr_clear_underflow (); + #ifdef WORKAROUND + mpfr_t f2; + mpfr_init2 (f2, 100000); +@@ -53,12 +54,16 @@ string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd) + int r = mpfr_set (f, f2, rnd); + r |= mpfr_subnormalize (f, r, rnd); + mpfr_clear (f2); +- return r0 | r; ++ r |= r0; + #else + int r = mpfr_strtofr (f, s, NULL, 0, rnd); + r |= mpfr_subnormalize (f, r, rnd); +- return r; + #endif ++ if (r == 0) ++ /* The MPFR underflow flag is set for exact subnormal results, ++ which is not wanted here. */ ++ mpfr_clear_underflow (); ++ return r; + } + + void +@@ -70,6 +75,21 @@ print_fp (FILE *fout, mpfr_t f, const char *suffix) + mpfr_fprintf (fout, "\t%Ra%s", f, suffix); + } + ++static const char * ++suffix_to_print (bool overflow, bool underflow, bool underflow_before_rounding, ++ bool with_comma) ++{ ++ if (overflow) ++ return with_comma ? ", true, false,\n" : ", true, false"; ++ if (underflow) ++ return with_comma ? ", false, true,\n" : ", false, true"; ++ if (underflow_before_rounding) ++ return (with_comma ++ ? ", false, !TININESS_AFTER_ROUNDING,\n" ++ : ", false, !TININESS_AFTER_ROUNDING"); ++ return with_comma ? ", false, false,\n" : ", false, false"; ++} ++ + static void + round_str (FILE *fout, const char *s, int prec, int emin, int emax, + bool ibm_ld) +@@ -80,8 +100,11 @@ round_str (FILE *fout, const char *s, int prec, int emin, int emax, + mpfr_set_emin (emin); + mpfr_set_emax (emax); + mpfr_init (f); ++ string_to_fp (f, s, MPFR_RNDZ); ++ bool underflow_before_rounding = mpfr_underflow_p () != 0; + int r = string_to_fp (f, s, MPFR_RNDD); + bool overflow = mpfr_overflow_p () != 0; ++ bool underflow = mpfr_underflow_p () != 0; + if (ibm_ld) + { + assert (prec == 106 && emin == -1073 && emax == 1024); +@@ -97,19 +120,27 @@ round_str (FILE *fout, const char *s, int prec, int emin, int emax, + } + } + mpfr_fprintf (fout, "\t%s,\n", r ? "false" : "true"); +- print_fp (fout, f, overflow ? ", true,\n" : ", false,\n"); ++ print_fp (fout, f, ++ suffix_to_print (overflow, underflow, underflow_before_rounding, ++ true)); + string_to_fp (f, s, MPFR_RNDN); + overflow = (mpfr_overflow_p () != 0 + || (ibm_ld && mpfr_cmpabs (f, max_value) > 0)); +- print_fp (fout, f, overflow ? ", true,\n" : ", false,\n"); ++ print_fp (fout, f, ++ suffix_to_print (overflow, underflow, underflow_before_rounding, ++ true)); + string_to_fp (f, s, MPFR_RNDZ); + overflow = (mpfr_overflow_p () != 0 + || (ibm_ld && mpfr_cmpabs (f, max_value) > 0)); +- print_fp (fout, f, overflow ? ", true,\n" : ", false,\n"); ++ print_fp (fout, f, ++ suffix_to_print (overflow, underflow, underflow_before_rounding, ++ true)); + string_to_fp (f, s, MPFR_RNDU); + overflow = (mpfr_overflow_p () != 0 + || (ibm_ld && mpfr_cmpabs (f, max_value) > 0)); +- print_fp (fout, f, overflow ? ", true" : ", false"); ++ print_fp (fout, f, ++ suffix_to_print (overflow, underflow, underflow_before_rounding, ++ false)); + mpfr_clear (f); + if (ibm_ld) + mpfr_clear (max_value); +diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h +index 8899d15f9b8a810d..13e62dd2b0588a16 100644 +--- a/stdlib/tst-strtod-round-data.h ++++ b/stdlib/tst-strtod-round-data.h +@@ -2,1852 +2,1852 @@ + static const struct test tests[] = { + TEST ("3.518437208883201171875E+013", + false, +- 0x2p+44, false, +- 0x2p+44, false, +- 0x2p+44, false, +- 0x2.000004p+44, false, +- false, +- 0x2.0000000000002p+44, false, +- 0x2.0000000000004p+44, false, +- 0x2.0000000000002p+44, false, +- 0x2.0000000000004p+44, false, +- true, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- true, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- true, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- true, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false, +- 0x2.0000000000003p+44, false), ++ 0x2p+44, false, false, ++ 0x2p+44, false, false, ++ 0x2p+44, false, false, ++ 0x2.000004p+44, false, false, ++ false, ++ 0x2.0000000000002p+44, false, false, ++ 0x2.0000000000004p+44, false, false, ++ 0x2.0000000000002p+44, false, false, ++ 0x2.0000000000004p+44, false, false, ++ true, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ true, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ true, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ true, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false, ++ 0x2.0000000000003p+44, false, false), + TEST ("1.00000005960464477550", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000001p+0, false, +- false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000004p+0, false, +- false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000004p+0, false, +- false, +- 0x1.0000010000000002048242f2ffp+0, false, +- 0x1.0000010000000002048242f2ff8p+0, false, +- 0x1.0000010000000002048242f2ffp+0, false, +- 0x1.0000010000000002048242f2ff8p+0, false, +- false, +- 0x1.0000010000000002048242f2ff66p+0, false, +- 0x1.0000010000000002048242f2ff67p+0, false, +- 0x1.0000010000000002048242f2ff66p+0, false, +- 0x1.0000010000000002048242f2ff67p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000004p+0, false, false, ++ false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000004p+0, false, false, ++ false, ++ 0x1.0000010000000002048242f2ffp+0, false, false, ++ 0x1.0000010000000002048242f2ff8p+0, false, false, ++ 0x1.0000010000000002048242f2ffp+0, false, false, ++ 0x1.0000010000000002048242f2ff8p+0, false, false, ++ false, ++ 0x1.0000010000000002048242f2ff66p+0, false, false, ++ 0x1.0000010000000002048242f2ff67p+0, false, false, ++ 0x1.0000010000000002048242f2ff66p+0, false, false, ++ 0x1.0000010000000002048242f2ff67p+0, false, false), + TEST ("1.0000000596046447755", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000001p+0, false, +- false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000004p+0, false, +- false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000002p+0, false, +- 0x1.0000010000000004p+0, false, +- false, +- 0x1.0000010000000002048242f2ffp+0, false, +- 0x1.0000010000000002048242f2ff8p+0, false, +- 0x1.0000010000000002048242f2ffp+0, false, +- 0x1.0000010000000002048242f2ff8p+0, false, +- false, +- 0x1.0000010000000002048242f2ff66p+0, false, +- 0x1.0000010000000002048242f2ff67p+0, false, +- 0x1.0000010000000002048242f2ff66p+0, false, +- 0x1.0000010000000002048242f2ff67p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000004p+0, false, false, ++ false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ 0x1.0000010000000004p+0, false, false, ++ false, ++ 0x1.0000010000000002048242f2ffp+0, false, false, ++ 0x1.0000010000000002048242f2ff8p+0, false, false, ++ 0x1.0000010000000002048242f2ffp+0, false, false, ++ 0x1.0000010000000002048242f2ff8p+0, false, false, ++ false, ++ 0x1.0000010000000002048242f2ff66p+0, false, false, ++ 0x1.0000010000000002048242f2ff67p+0, false, false, ++ 0x1.0000010000000002048242f2ff66p+0, false, false, ++ 0x1.0000010000000002048242f2ff67p+0, false, false), + TEST ("1.000000059604644776", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000001p+0, false, +- false, +- 0x1.000001000000000ap+0, false, +- 0x1.000001000000000cp+0, false, +- 0x1.000001000000000ap+0, false, +- 0x1.000001000000000cp+0, false, +- false, +- 0x1.000001000000000ap+0, false, +- 0x1.000001000000000cp+0, false, +- 0x1.000001000000000ap+0, false, +- 0x1.000001000000000cp+0, false, +- false, +- 0x1.000001000000000b3db12bdc21p+0, false, +- 0x1.000001000000000b3db12bdc21p+0, false, +- 0x1.000001000000000b3db12bdc21p+0, false, +- 0x1.000001000000000b3db12bdc218p+0, false, +- false, +- 0x1.000001000000000b3db12bdc213cp+0, false, +- 0x1.000001000000000b3db12bdc213dp+0, false, +- 0x1.000001000000000b3db12bdc213cp+0, false, +- 0x1.000001000000000b3db12bdc213dp+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ false, ++ 0x1.000001000000000ap+0, false, false, ++ 0x1.000001000000000cp+0, false, false, ++ 0x1.000001000000000ap+0, false, false, ++ 0x1.000001000000000cp+0, false, false, ++ false, ++ 0x1.000001000000000ap+0, false, false, ++ 0x1.000001000000000cp+0, false, false, ++ 0x1.000001000000000ap+0, false, false, ++ 0x1.000001000000000cp+0, false, false, ++ false, ++ 0x1.000001000000000b3db12bdc21p+0, false, false, ++ 0x1.000001000000000b3db12bdc21p+0, false, false, ++ 0x1.000001000000000b3db12bdc21p+0, false, false, ++ 0x1.000001000000000b3db12bdc218p+0, false, false, ++ false, ++ 0x1.000001000000000b3db12bdc213cp+0, false, false, ++ 0x1.000001000000000b3db12bdc213dp+0, false, false, ++ 0x1.000001000000000b3db12bdc213cp+0, false, false, ++ 0x1.000001000000000b3db12bdc213dp+0, false, false), + TEST ("1.000000059604644775", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000000fffffffp+0, false, +- 0x1.000001p+0, false, +- 0x1.000000fffffffp+0, false, +- 0x1.000001p+0, false, +- false, +- 0x1.000000fffffffff8p+0, false, +- 0x1.000000fffffffff8p+0, false, +- 0x1.000000fffffffff8p+0, false, +- 0x1.000000fffffffffap+0, false, +- false, +- 0x1.000000fffffffff8p+0, false, +- 0x1.000000fffffffff8p+0, false, +- 0x1.000000fffffffff8p+0, false, +- 0x1.000000fffffffffap+0, false, +- false, +- 0x1.000000fffffffff8cb535a09dd8p+0, false, +- 0x1.000000fffffffff8cb535a09dd8p+0, false, +- 0x1.000000fffffffff8cb535a09dd8p+0, false, +- 0x1.000000fffffffff8cb535a09dep+0, false, +- false, +- 0x1.000000fffffffff8cb535a09dd9p+0, false, +- 0x1.000000fffffffff8cb535a09dd91p+0, false, +- 0x1.000000fffffffff8cb535a09dd9p+0, false, +- 0x1.000000fffffffff8cb535a09dd91p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000000fffffffp+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000000fffffffp+0, false, false, ++ 0x1.000001p+0, false, false, ++ false, ++ 0x1.000000fffffffff8p+0, false, false, ++ 0x1.000000fffffffff8p+0, false, false, ++ 0x1.000000fffffffff8p+0, false, false, ++ 0x1.000000fffffffffap+0, false, false, ++ false, ++ 0x1.000000fffffffff8p+0, false, false, ++ 0x1.000000fffffffff8p+0, false, false, ++ 0x1.000000fffffffff8p+0, false, false, ++ 0x1.000000fffffffffap+0, false, false, ++ false, ++ 0x1.000000fffffffff8cb535a09dd8p+0, false, false, ++ 0x1.000000fffffffff8cb535a09dd8p+0, false, false, ++ 0x1.000000fffffffff8cb535a09dd8p+0, false, false, ++ 0x1.000000fffffffff8cb535a09dep+0, false, false, ++ false, ++ 0x1.000000fffffffff8cb535a09dd9p+0, false, false, ++ 0x1.000000fffffffff8cb535a09dd91p+0, false, false, ++ 0x1.000000fffffffff8cb535a09dd9p+0, false, false, ++ 0x1.000000fffffffff8cb535a09dd91p+0, false, false), + TEST ("1.00000005960464478", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000001p+0, false, +- false, +- 0x1.0000010000000054p+0, false, +- 0x1.0000010000000056p+0, false, +- 0x1.0000010000000054p+0, false, +- 0x1.0000010000000056p+0, false, +- false, +- 0x1.0000010000000054p+0, false, +- 0x1.0000010000000056p+0, false, +- 0x1.0000010000000054p+0, false, +- 0x1.0000010000000056p+0, false, +- false, +- 0x1.0000010000000055072873252f8p+0, false, +- 0x1.0000010000000055072873253p+0, false, +- 0x1.0000010000000055072873252f8p+0, false, +- 0x1.0000010000000055072873253p+0, false, +- false, +- 0x1.0000010000000055072873252febp+0, false, +- 0x1.0000010000000055072873252febp+0, false, +- 0x1.0000010000000055072873252febp+0, false, +- 0x1.0000010000000055072873252fecp+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ false, ++ 0x1.0000010000000054p+0, false, false, ++ 0x1.0000010000000056p+0, false, false, ++ 0x1.0000010000000054p+0, false, false, ++ 0x1.0000010000000056p+0, false, false, ++ false, ++ 0x1.0000010000000054p+0, false, false, ++ 0x1.0000010000000056p+0, false, false, ++ 0x1.0000010000000054p+0, false, false, ++ 0x1.0000010000000056p+0, false, false, ++ false, ++ 0x1.0000010000000055072873252f8p+0, false, false, ++ 0x1.0000010000000055072873253p+0, false, false, ++ 0x1.0000010000000055072873252f8p+0, false, false, ++ 0x1.0000010000000055072873253p+0, false, false, ++ false, ++ 0x1.0000010000000055072873252febp+0, false, false, ++ 0x1.0000010000000055072873252febp+0, false, false, ++ 0x1.0000010000000055072873252febp+0, false, false, ++ 0x1.0000010000000055072873252fecp+0, false, false), + TEST ("1.0000000596046448", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000001p+0, false, +- false, +- 0x1.00000100000001c4p+0, false, +- 0x1.00000100000001c6p+0, false, +- 0x1.00000100000001c4p+0, false, +- 0x1.00000100000001c6p+0, false, +- false, +- 0x1.00000100000001c4p+0, false, +- 0x1.00000100000001c6p+0, false, +- 0x1.00000100000001c4p+0, false, +- 0x1.00000100000001c6p+0, false, +- false, +- 0x1.00000100000001c5f67cd79279p+0, false, +- 0x1.00000100000001c5f67cd792798p+0, false, +- 0x1.00000100000001c5f67cd79279p+0, false, +- 0x1.00000100000001c5f67cd792798p+0, false, +- false, +- 0x1.00000100000001c5f67cd7927953p+0, false, +- 0x1.00000100000001c5f67cd7927954p+0, false, +- 0x1.00000100000001c5f67cd7927953p+0, false, +- 0x1.00000100000001c5f67cd7927954p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ false, ++ 0x1.00000100000001c4p+0, false, false, ++ 0x1.00000100000001c6p+0, false, false, ++ 0x1.00000100000001c4p+0, false, false, ++ 0x1.00000100000001c6p+0, false, false, ++ false, ++ 0x1.00000100000001c4p+0, false, false, ++ 0x1.00000100000001c6p+0, false, false, ++ 0x1.00000100000001c4p+0, false, false, ++ 0x1.00000100000001c6p+0, false, false, ++ false, ++ 0x1.00000100000001c5f67cd79279p+0, false, false, ++ 0x1.00000100000001c5f67cd792798p+0, false, false, ++ 0x1.00000100000001c5f67cd79279p+0, false, false, ++ 0x1.00000100000001c5f67cd792798p+0, false, false, ++ false, ++ 0x1.00000100000001c5f67cd7927953p+0, false, false, ++ 0x1.00000100000001c5f67cd7927954p+0, false, false, ++ 0x1.00000100000001c5f67cd7927953p+0, false, false, ++ 0x1.00000100000001c5f67cd7927954p+0, false, false), + TEST ("1.000000059604645", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.0000010000001p+0, false, +- 0x1.0000010000001p+0, false, +- 0x1.0000010000001p+0, false, +- 0x1.0000010000002p+0, false, +- false, +- 0x1.000001000000102ep+0, false, +- 0x1.000001000000103p+0, false, +- 0x1.000001000000102ep+0, false, +- 0x1.000001000000103p+0, false, +- false, +- 0x1.000001000000102ep+0, false, +- 0x1.000001000000103p+0, false, +- 0x1.000001000000102ep+0, false, +- 0x1.000001000000103p+0, false, +- false, +- 0x1.000001000000102f4fc8c3d757p+0, false, +- 0x1.000001000000102f4fc8c3d7578p+0, false, +- 0x1.000001000000102f4fc8c3d757p+0, false, +- 0x1.000001000000102f4fc8c3d7578p+0, false, +- false, +- 0x1.000001000000102f4fc8c3d75769p+0, false, +- 0x1.000001000000102f4fc8c3d75769p+0, false, +- 0x1.000001000000102f4fc8c3d75769p+0, false, +- 0x1.000001000000102f4fc8c3d7576ap+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.0000010000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ 0x1.0000010000002p+0, false, false, ++ false, ++ 0x1.000001000000102ep+0, false, false, ++ 0x1.000001000000103p+0, false, false, ++ 0x1.000001000000102ep+0, false, false, ++ 0x1.000001000000103p+0, false, false, ++ false, ++ 0x1.000001000000102ep+0, false, false, ++ 0x1.000001000000103p+0, false, false, ++ 0x1.000001000000102ep+0, false, false, ++ 0x1.000001000000103p+0, false, false, ++ false, ++ 0x1.000001000000102f4fc8c3d757p+0, false, false, ++ 0x1.000001000000102f4fc8c3d7578p+0, false, false, ++ 0x1.000001000000102f4fc8c3d757p+0, false, false, ++ 0x1.000001000000102f4fc8c3d7578p+0, false, false, ++ false, ++ 0x1.000001000000102f4fc8c3d75769p+0, false, false, ++ 0x1.000001000000102f4fc8c3d75769p+0, false, false, ++ 0x1.000001000000102f4fc8c3d75769p+0, false, false, ++ 0x1.000001000000102f4fc8c3d7576ap+0, false, false), + TEST ("1.00000005960464", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000000fffffeap+0, false, +- 0x1.000000fffffeap+0, false, +- 0x1.000000fffffeap+0, false, +- 0x1.000000fffffebp+0, false, +- false, +- 0x1.000000fffffea7e4p+0, false, +- 0x1.000000fffffea7e6p+0, false, +- 0x1.000000fffffea7e4p+0, false, +- 0x1.000000fffffea7e6p+0, false, +- false, +- 0x1.000000fffffea7e4p+0, false, +- 0x1.000000fffffea7e6p+0, false, +- 0x1.000000fffffea7e4p+0, false, +- 0x1.000000fffffea7e6p+0, false, +- false, +- 0x1.000000fffffea7e5975eb11da7p+0, false, +- 0x1.000000fffffea7e5975eb11da78p+0, false, +- 0x1.000000fffffea7e5975eb11da7p+0, false, +- 0x1.000000fffffea7e5975eb11da78p+0, false, +- false, +- 0x1.000000fffffea7e5975eb11da74ap+0, false, +- 0x1.000000fffffea7e5975eb11da74bp+0, false, +- 0x1.000000fffffea7e5975eb11da74ap+0, false, +- 0x1.000000fffffea7e5975eb11da74bp+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000000fffffeap+0, false, false, ++ 0x1.000000fffffeap+0, false, false, ++ 0x1.000000fffffeap+0, false, false, ++ 0x1.000000fffffebp+0, false, false, ++ false, ++ 0x1.000000fffffea7e4p+0, false, false, ++ 0x1.000000fffffea7e6p+0, false, false, ++ 0x1.000000fffffea7e4p+0, false, false, ++ 0x1.000000fffffea7e6p+0, false, false, ++ false, ++ 0x1.000000fffffea7e4p+0, false, false, ++ 0x1.000000fffffea7e6p+0, false, false, ++ 0x1.000000fffffea7e4p+0, false, false, ++ 0x1.000000fffffea7e6p+0, false, false, ++ false, ++ 0x1.000000fffffea7e5975eb11da7p+0, false, false, ++ 0x1.000000fffffea7e5975eb11da78p+0, false, false, ++ 0x1.000000fffffea7e5975eb11da7p+0, false, false, ++ 0x1.000000fffffea7e5975eb11da78p+0, false, false, ++ false, ++ 0x1.000000fffffea7e5975eb11da74ap+0, false, false, ++ 0x1.000000fffffea7e5975eb11da74bp+0, false, false, ++ 0x1.000000fffffea7e5975eb11da74ap+0, false, false, ++ 0x1.000000fffffea7e5975eb11da74bp+0, false, false), + TEST ("1.0000000596046", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000000fffff36p+0, false, +- 0x1.000000fffff36p+0, false, +- 0x1.000000fffff36p+0, false, +- 0x1.000000fffff37p+0, false, +- false, +- 0x1.000000fffff36596p+0, false, +- 0x1.000000fffff36598p+0, false, +- 0x1.000000fffff36596p+0, false, +- 0x1.000000fffff36598p+0, false, +- false, +- 0x1.000000fffff36596p+0, false, +- 0x1.000000fffff36598p+0, false, +- 0x1.000000fffff36596p+0, false, +- 0x1.000000fffff36598p+0, false, +- false, +- 0x1.000000fffff36597d40e1b5026p+0, false, +- 0x1.000000fffff36597d40e1b50268p+0, false, +- 0x1.000000fffff36597d40e1b5026p+0, false, +- 0x1.000000fffff36597d40e1b50268p+0, false, +- false, +- 0x1.000000fffff36597d40e1b502655p+0, false, +- 0x1.000000fffff36597d40e1b502656p+0, false, +- 0x1.000000fffff36597d40e1b502655p+0, false, +- 0x1.000000fffff36597d40e1b502656p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000000fffff36p+0, false, false, ++ 0x1.000000fffff36p+0, false, false, ++ 0x1.000000fffff36p+0, false, false, ++ 0x1.000000fffff37p+0, false, false, ++ false, ++ 0x1.000000fffff36596p+0, false, false, ++ 0x1.000000fffff36598p+0, false, false, ++ 0x1.000000fffff36596p+0, false, false, ++ 0x1.000000fffff36598p+0, false, false, ++ false, ++ 0x1.000000fffff36596p+0, false, false, ++ 0x1.000000fffff36598p+0, false, false, ++ 0x1.000000fffff36596p+0, false, false, ++ 0x1.000000fffff36598p+0, false, false, ++ false, ++ 0x1.000000fffff36597d40e1b5026p+0, false, false, ++ 0x1.000000fffff36597d40e1b50268p+0, false, false, ++ 0x1.000000fffff36597d40e1b5026p+0, false, false, ++ 0x1.000000fffff36597d40e1b50268p+0, false, false, ++ false, ++ 0x1.000000fffff36597d40e1b502655p+0, false, false, ++ 0x1.000000fffff36597d40e1b502656p+0, false, false, ++ 0x1.000000fffff36597d40e1b502655p+0, false, false, ++ 0x1.000000fffff36597d40e1b502656p+0, false, false), + TEST ("1.000000059605", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001000063fp+0, false, +- 0x1.000001000064p+0, false, +- 0x1.000001000063fp+0, false, +- 0x1.000001000064p+0, false, +- false, +- 0x1.000001000063fcap+0, false, +- 0x1.000001000063fca2p+0, false, +- 0x1.000001000063fcap+0, false, +- 0x1.000001000063fca2p+0, false, +- false, +- 0x1.000001000063fcap+0, false, +- 0x1.000001000063fca2p+0, false, +- 0x1.000001000063fcap+0, false, +- 0x1.000001000063fca2p+0, false, +- false, +- 0x1.000001000063fca17533f5572f8p+0, false, +- 0x1.000001000063fca17533f5573p+0, false, +- 0x1.000001000063fca17533f5572f8p+0, false, +- 0x1.000001000063fca17533f5573p+0, false, +- false, +- 0x1.000001000063fca17533f5572fe9p+0, false, +- 0x1.000001000063fca17533f5572feap+0, false, +- 0x1.000001000063fca17533f5572fe9p+0, false, +- 0x1.000001000063fca17533f5572feap+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001000063fp+0, false, false, ++ 0x1.000001000064p+0, false, false, ++ 0x1.000001000063fp+0, false, false, ++ 0x1.000001000064p+0, false, false, ++ false, ++ 0x1.000001000063fcap+0, false, false, ++ 0x1.000001000063fca2p+0, false, false, ++ 0x1.000001000063fcap+0, false, false, ++ 0x1.000001000063fca2p+0, false, false, ++ false, ++ 0x1.000001000063fcap+0, false, false, ++ 0x1.000001000063fca2p+0, false, false, ++ 0x1.000001000063fcap+0, false, false, ++ 0x1.000001000063fca2p+0, false, false, ++ false, ++ 0x1.000001000063fca17533f5572f8p+0, false, false, ++ 0x1.000001000063fca17533f5573p+0, false, false, ++ 0x1.000001000063fca17533f5572f8p+0, false, false, ++ 0x1.000001000063fca17533f5573p+0, false, false, ++ false, ++ 0x1.000001000063fca17533f5572fe9p+0, false, false, ++ 0x1.000001000063fca17533f5572feap+0, false, false, ++ 0x1.000001000063fca17533f5572fe9p+0, false, false, ++ 0x1.000001000063fca17533f5572feap+0, false, false), + TEST ("1.00000005960", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000000fffae49p+0, false, +- 0x1.000000fffae4ap+0, false, +- 0x1.000000fffae49p+0, false, +- 0x1.000000fffae4ap+0, false, +- false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- false, +- 0x1.000000fffae49ca916dacfff38p+0, false, +- 0x1.000000fffae49ca916dacfff38p+0, false, +- 0x1.000000fffae49ca916dacfff38p+0, false, +- 0x1.000000fffae49ca916dacfff388p+0, false, +- false, +- 0x1.000000fffae49ca916dacfff382dp+0, false, +- 0x1.000000fffae49ca916dacfff382dp+0, false, +- 0x1.000000fffae49ca916dacfff382dp+0, false, +- 0x1.000000fffae49ca916dacfff382ep+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000000fffae49p+0, false, false, ++ 0x1.000000fffae4ap+0, false, false, ++ 0x1.000000fffae49p+0, false, false, ++ 0x1.000000fffae4ap+0, false, false, ++ false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ false, ++ 0x1.000000fffae49ca916dacfff38p+0, false, false, ++ 0x1.000000fffae49ca916dacfff38p+0, false, false, ++ 0x1.000000fffae49ca916dacfff38p+0, false, false, ++ 0x1.000000fffae49ca916dacfff388p+0, false, false, ++ false, ++ 0x1.000000fffae49ca916dacfff382dp+0, false, false, ++ 0x1.000000fffae49ca916dacfff382dp+0, false, false, ++ 0x1.000000fffae49ca916dacfff382dp+0, false, false, ++ 0x1.000000fffae49ca916dacfff382ep+0, false, false), + TEST ("1.0000000596", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000000fffae49p+0, false, +- 0x1.000000fffae4ap+0, false, +- 0x1.000000fffae49p+0, false, +- 0x1.000000fffae4ap+0, false, +- false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- 0x1.000000fffae49ca8p+0, false, +- 0x1.000000fffae49caap+0, false, +- false, +- 0x1.000000fffae49ca916dacfff38p+0, false, +- 0x1.000000fffae49ca916dacfff38p+0, false, +- 0x1.000000fffae49ca916dacfff38p+0, false, +- 0x1.000000fffae49ca916dacfff388p+0, false, +- false, +- 0x1.000000fffae49ca916dacfff382dp+0, false, +- 0x1.000000fffae49ca916dacfff382dp+0, false, +- 0x1.000000fffae49ca916dacfff382dp+0, false, +- 0x1.000000fffae49ca916dacfff382ep+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000000fffae49p+0, false, false, ++ 0x1.000000fffae4ap+0, false, false, ++ 0x1.000000fffae49p+0, false, false, ++ 0x1.000000fffae4ap+0, false, false, ++ false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ 0x1.000000fffae49ca8p+0, false, false, ++ 0x1.000000fffae49caap+0, false, false, ++ false, ++ 0x1.000000fffae49ca916dacfff38p+0, false, false, ++ 0x1.000000fffae49ca916dacfff38p+0, false, false, ++ 0x1.000000fffae49ca916dacfff38p+0, false, false, ++ 0x1.000000fffae49ca916dacfff388p+0, false, false, ++ false, ++ 0x1.000000fffae49ca916dacfff382dp+0, false, false, ++ 0x1.000000fffae49ca916dacfff382dp+0, false, false, ++ 0x1.000000fffae49ca916dacfff382dp+0, false, false, ++ 0x1.000000fffae49ca916dacfff382ep+0, false, false), + TEST ("1.000000060", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.00000101b2b29p+0, false, +- 0x1.00000101b2b2ap+0, false, +- 0x1.00000101b2b29p+0, false, +- 0x1.00000101b2b2ap+0, false, +- false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a48p+0, false, +- false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a48p+0, false, +- false, +- 0x1.00000101b2b29a4692b67b7ca3p+0, false, +- 0x1.00000101b2b29a4692b67b7ca3p+0, false, +- 0x1.00000101b2b29a4692b67b7ca3p+0, false, +- 0x1.00000101b2b29a4692b67b7ca38p+0, false, +- false, +- 0x1.00000101b2b29a4692b67b7ca313p+0, false, +- 0x1.00000101b2b29a4692b67b7ca314p+0, false, +- 0x1.00000101b2b29a4692b67b7ca313p+0, false, +- 0x1.00000101b2b29a4692b67b7ca314p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.00000101b2b29p+0, false, false, ++ 0x1.00000101b2b2ap+0, false, false, ++ 0x1.00000101b2b29p+0, false, false, ++ 0x1.00000101b2b2ap+0, false, false, ++ false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a48p+0, false, false, ++ false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a48p+0, false, false, ++ false, ++ 0x1.00000101b2b29a4692b67b7ca3p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca3p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca3p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca38p+0, false, false, ++ false, ++ 0x1.00000101b2b29a4692b67b7ca313p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca314p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca313p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca314p+0, false, false), + TEST ("1.00000006", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.00000101b2b29p+0, false, +- 0x1.00000101b2b2ap+0, false, +- 0x1.00000101b2b29p+0, false, +- 0x1.00000101b2b2ap+0, false, +- false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a48p+0, false, +- false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a46p+0, false, +- 0x1.00000101b2b29a48p+0, false, +- false, +- 0x1.00000101b2b29a4692b67b7ca3p+0, false, +- 0x1.00000101b2b29a4692b67b7ca3p+0, false, +- 0x1.00000101b2b29a4692b67b7ca3p+0, false, +- 0x1.00000101b2b29a4692b67b7ca38p+0, false, +- false, +- 0x1.00000101b2b29a4692b67b7ca313p+0, false, +- 0x1.00000101b2b29a4692b67b7ca314p+0, false, +- 0x1.00000101b2b29a4692b67b7ca313p+0, false, +- 0x1.00000101b2b29a4692b67b7ca314p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.00000101b2b29p+0, false, false, ++ 0x1.00000101b2b2ap+0, false, false, ++ 0x1.00000101b2b29p+0, false, false, ++ 0x1.00000101b2b2ap+0, false, false, ++ false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a48p+0, false, false, ++ false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a46p+0, false, false, ++ 0x1.00000101b2b29a48p+0, false, false, ++ false, ++ 0x1.00000101b2b29a4692b67b7ca3p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca3p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca3p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca38p+0, false, false, ++ false, ++ 0x1.00000101b2b29a4692b67b7ca313p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca314p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca313p+0, false, false, ++ 0x1.00000101b2b29a4692b67b7ca314p+0, false, false), + TEST ("1.0000001", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001ad7f29ap+0, false, +- 0x1.000001ad7f29bp+0, false, +- 0x1.000001ad7f29ap+0, false, +- 0x1.000001ad7f29bp+0, false, +- false, +- 0x1.000001ad7f29abcap+0, false, +- 0x1.000001ad7f29abcap+0, false, +- 0x1.000001ad7f29abcap+0, false, +- 0x1.000001ad7f29abccp+0, false, +- false, +- 0x1.000001ad7f29abcap+0, false, +- 0x1.000001ad7f29abcap+0, false, +- 0x1.000001ad7f29abcap+0, false, +- 0x1.000001ad7f29abccp+0, false, +- false, +- 0x1.000001ad7f29abcaf485787a65p+0, false, +- 0x1.000001ad7f29abcaf485787a65p+0, false, +- 0x1.000001ad7f29abcaf485787a65p+0, false, +- 0x1.000001ad7f29abcaf485787a658p+0, false, +- false, +- 0x1.000001ad7f29abcaf485787a652p+0, false, +- 0x1.000001ad7f29abcaf485787a6521p+0, false, +- 0x1.000001ad7f29abcaf485787a652p+0, false, +- 0x1.000001ad7f29abcaf485787a6521p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001ad7f29ap+0, false, false, ++ 0x1.000001ad7f29bp+0, false, false, ++ 0x1.000001ad7f29ap+0, false, false, ++ 0x1.000001ad7f29bp+0, false, false, ++ false, ++ 0x1.000001ad7f29abcap+0, false, false, ++ 0x1.000001ad7f29abcap+0, false, false, ++ 0x1.000001ad7f29abcap+0, false, false, ++ 0x1.000001ad7f29abccp+0, false, false, ++ false, ++ 0x1.000001ad7f29abcap+0, false, false, ++ 0x1.000001ad7f29abcap+0, false, false, ++ 0x1.000001ad7f29abcap+0, false, false, ++ 0x1.000001ad7f29abccp+0, false, false, ++ false, ++ 0x1.000001ad7f29abcaf485787a65p+0, false, false, ++ 0x1.000001ad7f29abcaf485787a65p+0, false, false, ++ 0x1.000001ad7f29abcaf485787a65p+0, false, false, ++ 0x1.000001ad7f29abcaf485787a658p+0, false, false, ++ false, ++ 0x1.000001ad7f29abcaf485787a652p+0, false, false, ++ 0x1.000001ad7f29abcaf485787a6521p+0, false, false, ++ 0x1.000001ad7f29abcaf485787a652p+0, false, false, ++ 0x1.000001ad7f29abcaf485787a6521p+0, false, false), + TEST ("1.000000", + true, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- true, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- true, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- true, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- true, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- true, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ true, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ true, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ true, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ true, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ true, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false), + TEST ("1.00000000000000011113", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- false, +- 0x1.0000000000000801fc96557232p+0, false, +- 0x1.0000000000000801fc96557232p+0, false, +- 0x1.0000000000000801fc96557232p+0, false, +- 0x1.0000000000000801fc965572328p+0, false, +- false, +- 0x1.0000000000000801fc9655723222p+0, false, +- 0x1.0000000000000801fc9655723222p+0, false, +- 0x1.0000000000000801fc9655723222p+0, false, +- 0x1.0000000000000801fc9655723223p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ false, ++ 0x1.0000000000000801fc96557232p+0, false, false, ++ 0x1.0000000000000801fc96557232p+0, false, false, ++ 0x1.0000000000000801fc96557232p+0, false, false, ++ 0x1.0000000000000801fc965572328p+0, false, false, ++ false, ++ 0x1.0000000000000801fc9655723222p+0, false, false, ++ 0x1.0000000000000801fc9655723222p+0, false, false, ++ 0x1.0000000000000801fc9655723222p+0, false, false, ++ 0x1.0000000000000801fc9655723223p+0, false, false), + TEST ("1.00000000000000011103", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- false, +- 0x1.00000000000008002459c076c48p+0, false, +- 0x1.00000000000008002459c076c5p+0, false, +- 0x1.00000000000008002459c076c48p+0, false, +- 0x1.00000000000008002459c076c5p+0, false, +- false, +- 0x1.00000000000008002459c076c4f7p+0, false, +- 0x1.00000000000008002459c076c4f8p+0, false, +- 0x1.00000000000008002459c076c4f7p+0, false, +- 0x1.00000000000008002459c076c4f8p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ false, ++ 0x1.00000000000008002459c076c48p+0, false, false, ++ 0x1.00000000000008002459c076c5p+0, false, false, ++ 0x1.00000000000008002459c076c48p+0, false, false, ++ 0x1.00000000000008002459c076c5p+0, false, false, ++ false, ++ 0x1.00000000000008002459c076c4f7p+0, false, false, ++ 0x1.00000000000008002459c076c4f8p+0, false, false, ++ 0x1.00000000000008002459c076c4f7p+0, false, false, ++ 0x1.00000000000008002459c076c4f8p+0, false, false), + TEST ("1.00000000000000011102", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- false, +- 0x1.00000000000007fff5207e5dap+0, false, +- 0x1.00000000000007fff5207e5da08p+0, false, +- 0x1.00000000000007fff5207e5dap+0, false, +- 0x1.00000000000007fff5207e5da08p+0, false, +- false, +- 0x1.00000000000007fff5207e5da073p+0, false, +- 0x1.00000000000007fff5207e5da073p+0, false, +- 0x1.00000000000007fff5207e5da073p+0, false, +- 0x1.00000000000007fff5207e5da074p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ false, ++ 0x1.00000000000007fff5207e5dap+0, false, false, ++ 0x1.00000000000007fff5207e5da08p+0, false, false, ++ 0x1.00000000000007fff5207e5dap+0, false, false, ++ 0x1.00000000000007fff5207e5da08p+0, false, false, ++ false, ++ 0x1.00000000000007fff5207e5da073p+0, false, false, ++ 0x1.00000000000007fff5207e5da073p+0, false, false, ++ 0x1.00000000000007fff5207e5da073p+0, false, false, ++ 0x1.00000000000007fff5207e5da074p+0, false, false), + TEST ("1.00000000000000011101", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- false, +- 0x1.00000000000007ffc5e73c447b8p+0, false, +- 0x1.00000000000007ffc5e73c447cp+0, false, +- 0x1.00000000000007ffc5e73c447b8p+0, false, +- 0x1.00000000000007ffc5e73c447cp+0, false, +- false, +- 0x1.00000000000007ffc5e73c447befp+0, false, +- 0x1.00000000000007ffc5e73c447befp+0, false, +- 0x1.00000000000007ffc5e73c447befp+0, false, +- 0x1.00000000000007ffc5e73c447bfp+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ false, ++ 0x1.00000000000007ffc5e73c447b8p+0, false, false, ++ 0x1.00000000000007ffc5e73c447cp+0, false, false, ++ 0x1.00000000000007ffc5e73c447b8p+0, false, false, ++ 0x1.00000000000007ffc5e73c447cp+0, false, false, ++ false, ++ 0x1.00000000000007ffc5e73c447befp+0, false, false, ++ 0x1.00000000000007ffc5e73c447befp+0, false, false, ++ 0x1.00000000000007ffc5e73c447befp+0, false, false, ++ 0x1.00000000000007ffc5e73c447bfp+0, false, false), + TEST ("1.0000000000000001111", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.0000000000000802p+0, false, +- false, +- 0x1.00000000000008016eea8f26c48p+0, false, +- 0x1.00000000000008016eea8f26c48p+0, false, +- 0x1.00000000000008016eea8f26c48p+0, false, +- 0x1.00000000000008016eea8f26c5p+0, false, +- false, +- 0x1.00000000000008016eea8f26c495p+0, false, +- 0x1.00000000000008016eea8f26c496p+0, false, +- 0x1.00000000000008016eea8f26c495p+0, false, +- 0x1.00000000000008016eea8f26c496p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.0000000000000802p+0, false, false, ++ false, ++ 0x1.00000000000008016eea8f26c48p+0, false, false, ++ 0x1.00000000000008016eea8f26c48p+0, false, false, ++ 0x1.00000000000008016eea8f26c48p+0, false, false, ++ 0x1.00000000000008016eea8f26c5p+0, false, false, ++ false, ++ 0x1.00000000000008016eea8f26c495p+0, false, false, ++ 0x1.00000000000008016eea8f26c496p+0, false, false, ++ 0x1.00000000000008016eea8f26c495p+0, false, false, ++ 0x1.00000000000008016eea8f26c496p+0, false, false), + TEST ("1.000000000000000111", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000007fep+0, false, +- 0x1.00000000000008p+0, false, +- false, +- 0x1.00000000000007ff96adfa2b57p+0, false, +- 0x1.00000000000007ff96adfa2b578p+0, false, +- 0x1.00000000000007ff96adfa2b57p+0, false, +- 0x1.00000000000007ff96adfa2b578p+0, false, +- false, +- 0x1.00000000000007ff96adfa2b576ap+0, false, +- 0x1.00000000000007ff96adfa2b576bp+0, false, +- 0x1.00000000000007ff96adfa2b576ap+0, false, +- 0x1.00000000000007ff96adfa2b576bp+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000007fep+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ false, ++ 0x1.00000000000007ff96adfa2b57p+0, false, false, ++ 0x1.00000000000007ff96adfa2b578p+0, false, false, ++ 0x1.00000000000007ff96adfa2b57p+0, false, false, ++ 0x1.00000000000007ff96adfa2b578p+0, false, false, ++ false, ++ 0x1.00000000000007ff96adfa2b576ap+0, false, false, ++ 0x1.00000000000007ff96adfa2b576bp+0, false, false, ++ 0x1.00000000000007ff96adfa2b576ap+0, false, false, ++ 0x1.00000000000007ff96adfa2b576bp+0, false, false), + TEST ("1.00000000000000011", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.00000000000007ecp+0, false, +- 0x1.00000000000007eep+0, false, +- 0x1.00000000000007ecp+0, false, +- 0x1.00000000000007eep+0, false, +- false, +- 0x1.00000000000007ecp+0, false, +- 0x1.00000000000007eep+0, false, +- 0x1.00000000000007ecp+0, false, +- 0x1.00000000000007eep+0, false, +- false, +- 0x1.00000000000007ed24502859138p+0, false, +- 0x1.00000000000007ed24502859138p+0, false, +- 0x1.00000000000007ed24502859138p+0, false, +- 0x1.00000000000007ed2450285914p+0, false, +- false, +- 0x1.00000000000007ed2450285913bfp+0, false, +- 0x1.00000000000007ed2450285913bfp+0, false, +- 0x1.00000000000007ed2450285913bfp+0, false, +- 0x1.00000000000007ed2450285913cp+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.00000000000007ecp+0, false, false, ++ 0x1.00000000000007eep+0, false, false, ++ 0x1.00000000000007ecp+0, false, false, ++ 0x1.00000000000007eep+0, false, false, ++ false, ++ 0x1.00000000000007ecp+0, false, false, ++ 0x1.00000000000007eep+0, false, false, ++ 0x1.00000000000007ecp+0, false, false, ++ 0x1.00000000000007eep+0, false, false, ++ false, ++ 0x1.00000000000007ed24502859138p+0, false, false, ++ 0x1.00000000000007ed24502859138p+0, false, false, ++ 0x1.00000000000007ed24502859138p+0, false, false, ++ 0x1.00000000000007ed2450285914p+0, false, false, ++ false, ++ 0x1.00000000000007ed2450285913bfp+0, false, false, ++ 0x1.00000000000007ed2450285913bfp+0, false, false, ++ 0x1.00000000000007ed2450285913bfp+0, false, false, ++ 0x1.00000000000007ed2450285913cp+0, false, false), + TEST ("1.0000000000000001", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1.0000000000000734p+0, false, +- 0x1.0000000000000734p+0, false, +- 0x1.0000000000000734p+0, false, +- 0x1.0000000000000736p+0, false, +- false, +- 0x1.0000000000000734p+0, false, +- 0x1.0000000000000734p+0, false, +- 0x1.0000000000000734p+0, false, +- 0x1.0000000000000736p+0, false, +- false, +- 0x1.0000000000000734aca5f6226fp+0, false, +- 0x1.0000000000000734aca5f6226fp+0, false, +- 0x1.0000000000000734aca5f6226fp+0, false, +- 0x1.0000000000000734aca5f6226f8p+0, false, +- false, +- 0x1.0000000000000734aca5f6226f0ap+0, false, +- 0x1.0000000000000734aca5f6226f0bp+0, false, +- 0x1.0000000000000734aca5f6226f0ap+0, false, +- 0x1.0000000000000734aca5f6226f0bp+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1.0000000000000734p+0, false, false, ++ 0x1.0000000000000734p+0, false, false, ++ 0x1.0000000000000734p+0, false, false, ++ 0x1.0000000000000736p+0, false, false, ++ false, ++ 0x1.0000000000000734p+0, false, false, ++ 0x1.0000000000000734p+0, false, false, ++ 0x1.0000000000000734p+0, false, false, ++ 0x1.0000000000000736p+0, false, false, ++ false, ++ 0x1.0000000000000734aca5f6226fp+0, false, false, ++ 0x1.0000000000000734aca5f6226fp+0, false, false, ++ 0x1.0000000000000734aca5f6226fp+0, false, false, ++ 0x1.0000000000000734aca5f6226f8p+0, false, false, ++ false, ++ 0x1.0000000000000734aca5f6226f0ap+0, false, false, ++ 0x1.0000000000000734aca5f6226f0bp+0, false, false, ++ 0x1.0000000000000734aca5f6226f0ap+0, false, false, ++ 0x1.0000000000000734aca5f6226f0bp+0, false, false), + TEST ("3929201589819414e-25", + false, +- 0x1.b0053p-32, false, +- 0x1.b00532p-32, false, +- 0x1.b0053p-32, false, +- 0x1.b00532p-32, false, +- false, +- 0x1.b005314e2421ep-32, false, +- 0x1.b005314e2421ep-32, false, +- 0x1.b005314e2421ep-32, false, +- 0x1.b005314e2421fp-32, false, +- false, +- 0x1.b005314e2421e7fep-32, false, +- 0x1.b005314e2421e8p-32, false, +- 0x1.b005314e2421e7fep-32, false, +- 0x1.b005314e2421e8p-32, false, +- false, +- 0x1.b005314e2421e7fep-32, false, +- 0x1.b005314e2421e8p-32, false, +- 0x1.b005314e2421e7fep-32, false, +- 0x1.b005314e2421e8p-32, false, +- false, +- 0x1.b005314e2421e7ffb472840c5ap-32, false, +- 0x1.b005314e2421e7ffb472840c5a8p-32, false, +- 0x1.b005314e2421e7ffb472840c5ap-32, false, +- 0x1.b005314e2421e7ffb472840c5a8p-32, false, +- false, +- 0x1.b005314e2421e7ffb472840c5a6ep-32, false, +- 0x1.b005314e2421e7ffb472840c5a6fp-32, false, +- 0x1.b005314e2421e7ffb472840c5a6ep-32, false, +- 0x1.b005314e2421e7ffb472840c5a6fp-32, false), ++ 0x1.b0053p-32, false, false, ++ 0x1.b00532p-32, false, false, ++ 0x1.b0053p-32, false, false, ++ 0x1.b00532p-32, false, false, ++ false, ++ 0x1.b005314e2421ep-32, false, false, ++ 0x1.b005314e2421ep-32, false, false, ++ 0x1.b005314e2421ep-32, false, false, ++ 0x1.b005314e2421fp-32, false, false, ++ false, ++ 0x1.b005314e2421e7fep-32, false, false, ++ 0x1.b005314e2421e8p-32, false, false, ++ 0x1.b005314e2421e7fep-32, false, false, ++ 0x1.b005314e2421e8p-32, false, false, ++ false, ++ 0x1.b005314e2421e7fep-32, false, false, ++ 0x1.b005314e2421e8p-32, false, false, ++ 0x1.b005314e2421e7fep-32, false, false, ++ 0x1.b005314e2421e8p-32, false, false, ++ false, ++ 0x1.b005314e2421e7ffb472840c5ap-32, false, false, ++ 0x1.b005314e2421e7ffb472840c5a8p-32, false, false, ++ 0x1.b005314e2421e7ffb472840c5ap-32, false, false, ++ 0x1.b005314e2421e7ffb472840c5a8p-32, false, false, ++ false, ++ 0x1.b005314e2421e7ffb472840c5a6ep-32, false, false, ++ 0x1.b005314e2421e7ffb472840c5a6fp-32, false, false, ++ 0x1.b005314e2421e7ffb472840c5a6ep-32, false, false, ++ 0x1.b005314e2421e7ffb472840c5a6fp-32, false, false), + TEST ("0.0000000000000000000000000000000000000000000021019476964872" + "256063855943749348741969203929128147736576356024258346866240" + "28790902229957282543182373046875", + false, +- 0x8p-152, false, +- 0x1p-148, false, +- 0x8p-152, false, +- 0x1p-148, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false), ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false), + TEST ("1.00000005960464477539062499", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000000fffffffp+0, false, +- 0x1.000001p+0, false, +- 0x1.000000fffffffp+0, false, +- 0x1.000001p+0, false, +- false, +- 0x1.000000fffffffffep+0, false, +- 0x1.000001p+0, false, +- 0x1.000000fffffffffep+0, false, +- 0x1.000001p+0, false, +- false, +- 0x1.000000fffffffffep+0, false, +- 0x1.000001p+0, false, +- 0x1.000000fffffffffep+0, false, +- 0x1.000001p+0, false, +- false, +- 0x1.000000fffffffffffffffce7b78p+0, false, +- 0x1.000000fffffffffffffffce7b8p+0, false, +- 0x1.000000fffffffffffffffce7b78p+0, false, +- 0x1.000000fffffffffffffffce7b8p+0, false, +- false, +- 0x1.000000fffffffffffffffce7b7e7p+0, false, +- 0x1.000000fffffffffffffffce7b7e7p+0, false, +- 0x1.000000fffffffffffffffce7b7e7p+0, false, +- 0x1.000000fffffffffffffffce7b7e8p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000000fffffffp+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000000fffffffp+0, false, false, ++ 0x1.000001p+0, false, false, ++ false, ++ 0x1.000000fffffffffep+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000000fffffffffep+0, false, false, ++ 0x1.000001p+0, false, false, ++ false, ++ 0x1.000000fffffffffep+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000000fffffffffep+0, false, false, ++ 0x1.000001p+0, false, false, ++ false, ++ 0x1.000000fffffffffffffffce7b78p+0, false, false, ++ 0x1.000000fffffffffffffffce7b8p+0, false, false, ++ 0x1.000000fffffffffffffffce7b78p+0, false, false, ++ 0x1.000000fffffffffffffffce7b8p+0, false, false, ++ false, ++ 0x1.000000fffffffffffffffce7b7e7p+0, false, false, ++ 0x1.000000fffffffffffffffce7b7e7p+0, false, false, ++ 0x1.000000fffffffffffffffce7b7e7p+0, false, false, ++ 0x1.000000fffffffffffffffce7b7e8p+0, false, false), + TEST ("1.000000059604644775390625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- true, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- true, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- true, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- true, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ true, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ true, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ true, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ true, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false), + TEST ("1.00000005960464477539062501", + false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000001p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000000002p+0, false, +- false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.000001p+0, false, +- 0x1.0000010000000002p+0, false, +- false, +- 0x1.00000100000000000000031848p+0, false, +- 0x1.00000100000000000000031848p+0, false, +- 0x1.00000100000000000000031848p+0, false, +- 0x1.000001000000000000000318488p+0, false, +- false, +- 0x1.0000010000000000000003184818p+0, false, +- 0x1.0000010000000000000003184819p+0, false, +- 0x1.0000010000000000000003184818p+0, false, +- 0x1.0000010000000000000003184819p+0, false), ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000001p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.000001p+0, false, false, ++ 0x1.0000010000000002p+0, false, false, ++ false, ++ 0x1.00000100000000000000031848p+0, false, false, ++ 0x1.00000100000000000000031848p+0, false, false, ++ 0x1.00000100000000000000031848p+0, false, false, ++ 0x1.000001000000000000000318488p+0, false, false, ++ false, ++ 0x1.0000010000000000000003184818p+0, false, false, ++ 0x1.0000010000000000000003184819p+0, false, false, ++ 0x1.0000010000000000000003184818p+0, false, false, ++ 0x1.0000010000000000000003184819p+0, false, false), + TEST ("1.00000011920928955078125", + true, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false), ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false), + TEST ("1.00000017881393432617187499", + false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000002p+0, false, +- 0x1.000004p+0, false, +- false, +- 0x1.000002fffffffp+0, false, +- 0x1.000003p+0, false, +- 0x1.000002fffffffp+0, false, +- 0x1.000003p+0, false, +- false, +- 0x1.000002fffffffffep+0, false, +- 0x1.000003p+0, false, +- 0x1.000002fffffffffep+0, false, +- 0x1.000003p+0, false, +- false, +- 0x1.000002fffffffffep+0, false, +- 0x1.000003p+0, false, +- 0x1.000002fffffffffep+0, false, +- 0x1.000003p+0, false, +- false, +- 0x1.000002fffffffffffffffce7b78p+0, false, +- 0x1.000002fffffffffffffffce7b8p+0, false, +- 0x1.000002fffffffffffffffce7b78p+0, false, +- 0x1.000002fffffffffffffffce7b8p+0, false, +- false, +- 0x1.000002fffffffffffffffce7b7e7p+0, false, +- 0x1.000002fffffffffffffffce7b7e7p+0, false, +- 0x1.000002fffffffffffffffce7b7e7p+0, false, +- 0x1.000002fffffffffffffffce7b7e8p+0, false), ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000004p+0, false, false, ++ false, ++ 0x1.000002fffffffp+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000002fffffffp+0, false, false, ++ 0x1.000003p+0, false, false, ++ false, ++ 0x1.000002fffffffffep+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000002fffffffffep+0, false, false, ++ 0x1.000003p+0, false, false, ++ false, ++ 0x1.000002fffffffffep+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000002fffffffffep+0, false, false, ++ 0x1.000003p+0, false, false, ++ false, ++ 0x1.000002fffffffffffffffce7b78p+0, false, false, ++ 0x1.000002fffffffffffffffce7b8p+0, false, false, ++ 0x1.000002fffffffffffffffce7b78p+0, false, false, ++ 0x1.000002fffffffffffffffce7b8p+0, false, false, ++ false, ++ 0x1.000002fffffffffffffffce7b7e7p+0, false, false, ++ 0x1.000002fffffffffffffffce7b7e7p+0, false, false, ++ 0x1.000002fffffffffffffffce7b7e7p+0, false, false, ++ 0x1.000002fffffffffffffffce7b7e8p+0, false, false), + TEST ("1.000000178813934326171875", + false, +- 0x1.000002p+0, false, +- 0x1.000004p+0, false, +- 0x1.000002p+0, false, +- 0x1.000004p+0, false, +- true, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- true, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- true, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- true, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- true, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false), ++ 0x1.000002p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000004p+0, false, false, ++ true, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ true, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ true, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ true, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ true, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false), + TEST ("1.00000017881393432617187501", + false, +- 0x1.000002p+0, false, +- 0x1.000004p+0, false, +- 0x1.000002p+0, false, +- 0x1.000004p+0, false, +- false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.0000030000001p+0, false, +- false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.0000030000000002p+0, false, +- false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.000003p+0, false, +- 0x1.0000030000000002p+0, false, +- false, +- 0x1.00000300000000000000031848p+0, false, +- 0x1.00000300000000000000031848p+0, false, +- 0x1.00000300000000000000031848p+0, false, +- 0x1.000003000000000000000318488p+0, false, +- false, +- 0x1.0000030000000000000003184818p+0, false, +- 0x1.0000030000000000000003184819p+0, false, +- 0x1.0000030000000000000003184818p+0, false, +- 0x1.0000030000000000000003184819p+0, false), ++ 0x1.000002p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000002p+0, false, false, ++ 0x1.000004p+0, false, false, ++ false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.0000030000001p+0, false, false, ++ false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.0000030000000002p+0, false, false, ++ false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.000003p+0, false, false, ++ 0x1.0000030000000002p+0, false, false, ++ false, ++ 0x1.00000300000000000000031848p+0, false, false, ++ 0x1.00000300000000000000031848p+0, false, false, ++ 0x1.00000300000000000000031848p+0, false, false, ++ 0x1.000003000000000000000318488p+0, false, false, ++ false, ++ 0x1.0000030000000000000003184818p+0, false, false, ++ 0x1.0000030000000000000003184819p+0, false, false, ++ 0x1.0000030000000000000003184818p+0, false, false, ++ 0x1.0000030000000000000003184819p+0, false, false), + TEST ("1.0000002384185791015625", + true, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- true, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- true, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- true, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- true, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- true, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false, +- 0x1.000004p+0, false), ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ true, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ true, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ true, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ true, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ true, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false, ++ 0x1.000004p+0, false, false), + TEST ("1.08420217248550443400745280086994171142578125e-19", + true, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- true, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- true, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- true, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- true, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- true, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false), ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ true, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ true, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ true, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ true, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ true, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false), + TEST ("1.0842022371089897897127399001987457793916291848290711641311" + "645507812499e-19", + false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2.000004p-64, false, +- false, +- 0x2.000001ffffffep-64, false, +- 0x2.000002p-64, false, +- 0x2.000001ffffffep-64, false, +- 0x2.000002p-64, false, +- false, +- 0x2.000001fffffffffcp-64, false, +- 0x2.000002p-64, false, +- 0x2.000001fffffffffcp-64, false, +- 0x2.000002p-64, false, +- false, +- 0x2.000001fffffffffcp-64, false, +- 0x2.000002p-64, false, +- 0x2.000001fffffffffcp-64, false, +- 0x2.000002p-64, false, +- false, +- 0x2.000001ffffffffffffffffffffp-64, false, +- 0x2.000002p-64, false, +- 0x2.000001ffffffffffffffffffffp-64, false, +- 0x2.000002p-64, false, +- false, +- 0x2.000001fffffffffffffffffffffep-64, false, +- 0x2.000002p-64, false, +- 0x2.000001fffffffffffffffffffffep-64, false, +- 0x2.000002p-64, false), ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2.000004p-64, false, false, ++ false, ++ 0x2.000001ffffffep-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000001ffffffep-64, false, false, ++ 0x2.000002p-64, false, false, ++ false, ++ 0x2.000001fffffffffcp-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000001fffffffffcp-64, false, false, ++ 0x2.000002p-64, false, false, ++ false, ++ 0x2.000001fffffffffcp-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000001fffffffffcp-64, false, false, ++ 0x2.000002p-64, false, false, ++ false, ++ 0x2.000001ffffffffffffffffffffp-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000001ffffffffffffffffffffp-64, false, false, ++ 0x2.000002p-64, false, false, ++ false, ++ 0x2.000001fffffffffffffffffffffep-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000001fffffffffffffffffffffep-64, false, false, ++ 0x2.000002p-64, false, false), + TEST ("1.0842022371089897897127399001987457793916291848290711641311" + "6455078125e-19", + false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2p-64, false, +- 0x2.000004p-64, false, +- true, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- true, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- true, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- true, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- true, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false), ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2.000004p-64, false, false, ++ true, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ true, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ true, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ true, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ true, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false), + TEST ("1.0842022371089897897127399001987457793916291848290711641311" + "645507812501e-19", + false, +- 0x2p-64, false, +- 0x2.000004p-64, false, +- 0x2p-64, false, +- 0x2.000004p-64, false, +- false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.0000020000002p-64, false, +- false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.0000020000000004p-64, false, +- false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.0000020000000004p-64, false, +- false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.00000200000000000000000001p-64, false, +- false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.000002p-64, false, +- 0x2.0000020000000000000000000002p-64, false), ++ 0x2p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2p-64, false, false, ++ 0x2.000004p-64, false, false, ++ false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.0000020000002p-64, false, false, ++ false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.0000020000000004p-64, false, false, ++ false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.0000020000000004p-64, false, false, ++ false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.00000200000000000000000001p-64, false, false, ++ false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.000002p-64, false, false, ++ 0x2.0000020000000000000000000002p-64, false, false), + TEST ("1.0842023017324751454180269995275498473574771196581423282623" + "291015625e-19", + true, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- true, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- true, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- true, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- true, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- true, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false), ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ true, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ true, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ true, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ true, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ true, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false), + TEST ("1.0842023663559605011233140988563539153233250544872134923934" + "936523437499e-19", + false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000004p-64, false, +- 0x2.000008p-64, false, +- false, +- 0x2.000005ffffffep-64, false, +- 0x2.000006p-64, false, +- 0x2.000005ffffffep-64, false, +- 0x2.000006p-64, false, +- false, +- 0x2.000005fffffffffcp-64, false, +- 0x2.000006p-64, false, +- 0x2.000005fffffffffcp-64, false, +- 0x2.000006p-64, false, +- false, +- 0x2.000005fffffffffcp-64, false, +- 0x2.000006p-64, false, +- 0x2.000005fffffffffcp-64, false, +- 0x2.000006p-64, false, +- false, +- 0x2.000005ffffffffffffffffffffp-64, false, +- 0x2.000006p-64, false, +- 0x2.000005ffffffffffffffffffffp-64, false, +- 0x2.000006p-64, false, +- false, +- 0x2.000005fffffffffffffffffffffep-64, false, +- 0x2.000006p-64, false, +- 0x2.000005fffffffffffffffffffffep-64, false, +- 0x2.000006p-64, false), ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000008p-64, false, false, ++ false, ++ 0x2.000005ffffffep-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000005ffffffep-64, false, false, ++ 0x2.000006p-64, false, false, ++ false, ++ 0x2.000005fffffffffcp-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000005fffffffffcp-64, false, false, ++ 0x2.000006p-64, false, false, ++ false, ++ 0x2.000005fffffffffcp-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000005fffffffffcp-64, false, false, ++ 0x2.000006p-64, false, false, ++ false, ++ 0x2.000005ffffffffffffffffffffp-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000005ffffffffffffffffffffp-64, false, false, ++ 0x2.000006p-64, false, false, ++ false, ++ 0x2.000005fffffffffffffffffffffep-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000005fffffffffffffffffffffep-64, false, false, ++ 0x2.000006p-64, false, false), + TEST ("1.0842023663559605011233140988563539153233250544872134923934" + "9365234375e-19", + false, +- 0x2.000004p-64, false, +- 0x2.000008p-64, false, +- 0x2.000004p-64, false, +- 0x2.000008p-64, false, +- true, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- true, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- true, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- true, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- true, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false), ++ 0x2.000004p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000008p-64, false, false, ++ true, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ true, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ true, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ true, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ true, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false), + TEST ("1.0842023663559605011233140988563539153233250544872134923934" + "936523437501e-19", + false, +- 0x2.000004p-64, false, +- 0x2.000008p-64, false, +- 0x2.000004p-64, false, +- 0x2.000008p-64, false, +- false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.0000060000002p-64, false, +- false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.0000060000000004p-64, false, +- false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.0000060000000004p-64, false, +- false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.00000600000000000000000001p-64, false, +- false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.000006p-64, false, +- 0x2.0000060000000000000000000002p-64, false), ++ 0x2.000004p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000004p-64, false, false, ++ 0x2.000008p-64, false, false, ++ false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.0000060000002p-64, false, false, ++ false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.0000060000000004p-64, false, false, ++ false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.0000060000000004p-64, false, false, ++ false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.00000600000000000000000001p-64, false, false, ++ false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.000006p-64, false, false, ++ 0x2.0000060000000000000000000002p-64, false, false), + TEST ("1.0842024309794458568286011981851579832891729893162846565246" + "58203125e-19", + true, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- true, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- true, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- true, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- true, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- true, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false, +- 0x2.000008p-64, false), ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ true, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ true, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ true, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ true, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ true, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false, ++ 0x2.000008p-64, false, false), + TEST ("7.5231638452626400509999138382223723380394595633413601376560" + "1092018187046051025390625e-37", + true, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- true, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- true, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- true, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- true, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- true, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false), ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ true, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ true, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ true, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ true, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ true, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false), + TEST ("7.5231642936781486349413765338158389908126215730251815381410" + "578824437213052434003657253924757242202758789062499e-37", + false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1.000002p-120, false, +- false, +- 0x1.000000fffffffp-120, false, +- 0x1.000001p-120, false, +- 0x1.000000fffffffp-120, false, +- 0x1.000001p-120, false, +- false, +- 0x1.000000fffffffffep-120, false, +- 0x1.000001p-120, false, +- 0x1.000000fffffffffep-120, false, +- 0x1.000001p-120, false, +- false, +- 0x1.000000fffffffffep-120, false, +- 0x1.000001p-120, false, +- 0x1.000000fffffffffep-120, false, +- 0x1.000001p-120, false, +- false, +- 0x1.000000ffffffffffffffffffff8p-120, false, +- 0x1.000001p-120, false, +- 0x1.000000ffffffffffffffffffff8p-120, false, +- 0x1.000001p-120, false, +- false, +- 0x1.000000ffffffffffffffffffffffp-120, false, +- 0x1.000001p-120, false, +- 0x1.000000ffffffffffffffffffffffp-120, false, +- 0x1.000001p-120, false), ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1.000002p-120, false, false, ++ false, ++ 0x1.000000fffffffp-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000000fffffffp-120, false, false, ++ 0x1.000001p-120, false, false, ++ false, ++ 0x1.000000fffffffffep-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000000fffffffffep-120, false, false, ++ 0x1.000001p-120, false, false, ++ false, ++ 0x1.000000fffffffffep-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000000fffffffffep-120, false, false, ++ 0x1.000001p-120, false, false, ++ false, ++ 0x1.000000ffffffffffffffffffff8p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000000ffffffffffffffffffff8p-120, false, false, ++ 0x1.000001p-120, false, false, ++ false, ++ 0x1.000000ffffffffffffffffffffffp-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000000ffffffffffffffffffffffp-120, false, false, ++ 0x1.000001p-120, false, false), + TEST ("7.5231642936781486349413765338158389908126215730251815381410" + "5788244372130524340036572539247572422027587890625e-37", + false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1p-120, false, +- 0x1.000002p-120, false, +- true, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- true, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- true, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- true, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- true, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false), ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1.000002p-120, false, false, ++ true, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ true, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ true, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ true, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ true, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false), + TEST ("7.5231642936781486349413765338158389908126215730251815381410" + "578824437213052434003657253924757242202758789062501e-37", + false, +- 0x1p-120, false, +- 0x1.000002p-120, false, +- 0x1p-120, false, +- 0x1.000002p-120, false, +- false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.0000010000001p-120, false, +- false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.0000010000000002p-120, false, +- false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.0000010000000002p-120, false, +- false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001000000000000000000008p-120, false, +- false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.000001p-120, false, +- 0x1.0000010000000000000000000001p-120, false), ++ 0x1p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1p-120, false, false, ++ 0x1.000002p-120, false, false, ++ false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.0000010000001p-120, false, false, ++ false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.0000010000000002p-120, false, false, ++ false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.0000010000000002p-120, false, false, ++ false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001000000000000000000008p-120, false, false, ++ false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.000001p-120, false, false, ++ 0x1.0000010000000000000000000001p-120, false, false), + TEST ("7.5231647420936572188828392294093056435857835827090029386261" + "048447055721499765468252007849514484405517578125e-37", + true, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- true, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- true, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- true, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- true, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- true, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false), ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ true, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ true, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ true, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ true, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ true, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false), + TEST ("7.5231651905091658028243019250027722963589455923928243391111" + "518069674229947096932846761774271726608276367187499e-37", + false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000002p-120, false, +- 0x1.000004p-120, false, +- false, +- 0x1.000002fffffffp-120, false, +- 0x1.000003p-120, false, +- 0x1.000002fffffffp-120, false, +- 0x1.000003p-120, false, +- false, +- 0x1.000002fffffffffep-120, false, +- 0x1.000003p-120, false, +- 0x1.000002fffffffffep-120, false, +- 0x1.000003p-120, false, +- false, +- 0x1.000002fffffffffep-120, false, +- 0x1.000003p-120, false, +- 0x1.000002fffffffffep-120, false, +- 0x1.000003p-120, false, +- false, +- 0x1.000002ffffffffffffffffffff8p-120, false, +- 0x1.000003p-120, false, +- 0x1.000002ffffffffffffffffffff8p-120, false, +- 0x1.000003p-120, false, +- false, +- 0x1.000002ffffffffffffffffffffffp-120, false, +- 0x1.000003p-120, false, +- 0x1.000002ffffffffffffffffffffffp-120, false, +- 0x1.000003p-120, false), ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000004p-120, false, false, ++ false, ++ 0x1.000002fffffffp-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000002fffffffp-120, false, false, ++ 0x1.000003p-120, false, false, ++ false, ++ 0x1.000002fffffffffep-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000002fffffffffep-120, false, false, ++ 0x1.000003p-120, false, false, ++ false, ++ 0x1.000002fffffffffep-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000002fffffffffep-120, false, false, ++ 0x1.000003p-120, false, false, ++ false, ++ 0x1.000002ffffffffffffffffffff8p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000002ffffffffffffffffffff8p-120, false, false, ++ 0x1.000003p-120, false, false, ++ false, ++ 0x1.000002ffffffffffffffffffffffp-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000002ffffffffffffffffffffffp-120, false, false, ++ 0x1.000003p-120, false, false), + TEST ("7.5231651905091658028243019250027722963589455923928243391111" + "5180696742299470969328467617742717266082763671875e-37", + false, +- 0x1.000002p-120, false, +- 0x1.000004p-120, false, +- 0x1.000002p-120, false, +- 0x1.000004p-120, false, +- true, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- true, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- true, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- true, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- true, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false), ++ 0x1.000002p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000004p-120, false, false, ++ true, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ true, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ true, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ true, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ true, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false), + TEST ("7.5231651905091658028243019250027722963589455923928243391111" + "518069674229947096932846761774271726608276367187501e-37", + false, +- 0x1.000002p-120, false, +- 0x1.000004p-120, false, +- 0x1.000002p-120, false, +- 0x1.000004p-120, false, +- false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.0000030000001p-120, false, +- false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.0000030000000002p-120, false, +- false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.0000030000000002p-120, false, +- false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003000000000000000000008p-120, false, +- false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.000003p-120, false, +- 0x1.0000030000000000000000000001p-120, false), ++ 0x1.000002p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000002p-120, false, false, ++ 0x1.000004p-120, false, false, ++ false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.0000030000001p-120, false, false, ++ false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.0000030000000002p-120, false, false, ++ false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.0000030000000002p-120, false, false, ++ false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003000000000000000000008p-120, false, false, ++ false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.000003p-120, false, false, ++ 0x1.0000030000000000000000000001p-120, false, false), + TEST ("7.5231656389246743867657646205962389491321076020766457395961" + "98769229273839442839744151569902896881103515625e-37", + true, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- true, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- true, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- true, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- true, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- true, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false, +- 0x1.000004p-120, false), ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ true, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ true, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ true, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ true, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ true, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false, ++ 0x1.000004p-120, false, false), + TEST ("340282356779733661637539395458142568447.999", + false, +- 0xf.fffffp+124, false, +- 0xf.fffffp+124, false, +- 0xf.fffffp+124, false, +- INF, true, +- false, +- 0xf.fffff7ffffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff7ffffff8p+124, false, +- 0xf.fffff8p+124, false, +- false, +- 0xf.fffff7fffffffffp+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff7fffffffffp+124, false, +- 0xf.fffff8p+124, false, +- false, +- 0xf.fffff7fffffffffp+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff7fffffffffp+124, false, +- 0xf.fffff8p+124, false, +- false, +- 0xf.fffff7fffffffffffffffffffcp+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff7fffffffffffffffffffcp+124, false, +- 0xf.fffff8p+124, false, +- false, +- 0xf.fffff7fffffffffffffffffffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff7fffffffffffffffffffff8p+124, false, +- 0xf.fffff8p+124, false), ++ 0xf.fffffp+124, false, false, ++ 0xf.fffffp+124, false, false, ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffff7ffffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff7ffffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ false, ++ 0xf.fffff7fffffffffp+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff7fffffffffp+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ false, ++ 0xf.fffff7fffffffffp+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff7fffffffffp+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ false, ++ 0xf.fffff7fffffffffffffffffffcp+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff7fffffffffffffffffffcp+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ false, ++ 0xf.fffff7fffffffffffffffffffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff7fffffffffffffffffffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false), + TEST ("340282356779733661637539395458142568448", + false, +- 0xf.fffffp+124, false, +- INF, true, +- 0xf.fffffp+124, false, +- INF, true, +- true, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- true, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- true, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- true, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- true, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false), ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ true, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ true, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ true, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ true, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ true, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false), + TEST ("340282356779733661637539395458142568448.001", + false, +- 0xf.fffffp+124, false, +- INF, true, +- 0xf.fffffp+124, false, +- INF, true, +- false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff80000008p+124, false, +- false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8000000001p+124, false, +- false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8000000001p+124, false, +- false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff800000000000000000004p+124, false, +- false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff8p+124, false, +- 0xf.fffff80000000000000000000008p+124, false), ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff80000008p+124, false, false, ++ false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8000000001p+124, false, false, ++ false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8000000001p+124, false, false, ++ false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff800000000000000000004p+124, false, false, ++ false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff8p+124, false, false, ++ 0xf.fffff80000000000000000000008p+124, false, false), + TEST ("-340282356779733661637539395458142568447.999", + false, +- -INF, true, +- -0xf.fffffp+124, false, +- -0xf.fffffp+124, false, +- -0xf.fffffp+124, false, +- false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff7ffffff8p+124, false, +- -0xf.fffff7ffffff8p+124, false, +- false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff7fffffffffp+124, false, +- -0xf.fffff7fffffffffp+124, false, +- false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff7fffffffffp+124, false, +- -0xf.fffff7fffffffffp+124, false, +- false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff7fffffffffffffffffffcp+124, false, +- -0xf.fffff7fffffffffffffffffffcp+124, false, +- false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff7fffffffffffffffffffff8p+124, false, +- -0xf.fffff7fffffffffffffffffffff8p+124, false), ++ -INF, true, false, ++ -0xf.fffffp+124, false, false, ++ -0xf.fffffp+124, false, false, ++ -0xf.fffffp+124, false, false, ++ false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff7ffffff8p+124, false, false, ++ -0xf.fffff7ffffff8p+124, false, false, ++ false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff7fffffffffp+124, false, false, ++ -0xf.fffff7fffffffffp+124, false, false, ++ false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff7fffffffffp+124, false, false, ++ -0xf.fffff7fffffffffp+124, false, false, ++ false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff7fffffffffffffffffffcp+124, false, false, ++ -0xf.fffff7fffffffffffffffffffcp+124, false, false, ++ false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff7fffffffffffffffffffff8p+124, false, false, ++ -0xf.fffff7fffffffffffffffffffff8p+124, false, false), + TEST ("-340282356779733661637539395458142568448", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, false, +- -0xf.fffffp+124, false, +- true, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- true, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- true, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- true, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- true, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, false, false, ++ -0xf.fffffp+124, false, false, ++ true, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ true, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ true, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ true, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ true, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false), + TEST ("-340282356779733661637539395458142568448.001", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, false, +- -0xf.fffffp+124, false, +- false, +- -0xf.fffff80000008p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- false, +- -0xf.fffff8000000001p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- false, +- -0xf.fffff8000000001p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- false, +- -0xf.fffff800000000000000000004p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- false, +- -0xf.fffff80000000000000000000008p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false, +- -0xf.fffff8p+124, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, false, false, ++ -0xf.fffffp+124, false, false, ++ false, ++ -0xf.fffff80000008p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ false, ++ -0xf.fffff8000000001p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ false, ++ -0xf.fffff8000000001p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ false, ++ -0xf.fffff800000000000000000004p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ false, ++ -0xf.fffff80000000000000000000008p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false, ++ -0xf.fffff8p+124, false, false), + TEST ("179769313486231580793728971405303415079934132710037826936173" + "778980444968292764750946649017977587207096330286416692887910" + "946555547851940402630657488671505820681908902000708383676273" +@@ -1855,35 +1855,35 @@ static const struct test tests[] = { + "936475292719074168444365510704342711559699508093042880177904" + "174497791.999", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, false, +- 0xf.ffffffffffff8p+1020, false, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- false, +- 0xf.ffffffffffffbffp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffbffp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- false, +- 0xf.ffffffffffffbffp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffbffp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- false, +- 0xf.ffffffffffffbffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffbffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, true, +- false, +- 0xf.ffffffffffffbffffffffffffff8p+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffbffffffffffffff8p+1020, false, +- 0xf.ffffffffffffcp+1020, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffffbffp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffbffp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ false, ++ 0xf.ffffffffffffbffp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffbffp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ false, ++ 0xf.ffffffffffffbffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffbffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ false, ++ 0xf.ffffffffffffbffffffffffffff8p+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffbffffffffffffff8p+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false), + TEST ("179769313486231580793728971405303415079934132710037826936173" + "778980444968292764750946649017977587207096330286416692887910" + "946555547851940402630657488671505820681908902000708383676273" +@@ -1891,35 +1891,35 @@ static const struct test tests[] = { + "936475292719074168444365510704342711559699508093042880177904" + "174497792", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- true, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- true, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- false, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffcp+1020, true, +- true, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ true, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ true, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ true, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false), + TEST ("179769313486231580793728971405303415079934132710037826936173" + "778980444968292764750946649017977587207096330286416692887910" + "946555547851940402630657488671505820681908902000708383676273" +@@ -1927,35 +1927,35 @@ static const struct test tests[] = { + "936475292719074168444365510704342711559699508093042880177904" + "174497792.001", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffc01p+1020, false, +- false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffc01p+1020, false, +- false, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffcp+1020, true, +- 0xf.ffffffffffffc0000000000004p+1020, true, +- false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffcp+1020, false, +- 0xf.ffffffffffffc000000000000008p+1020, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffc01p+1020, false, false, ++ false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffc01p+1020, false, false, ++ false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffcp+1020, true, false, ++ 0xf.ffffffffffffc0000000000004p+1020, true, false, ++ false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffcp+1020, false, false, ++ 0xf.ffffffffffffc000000000000008p+1020, false, false), + TEST ("-17976931348623158079372897140530341507993413271003782693617" + "377898044496829276475094664901797758720709633028641669288791" + "094655554785194040263065748867150582068190890200070838367627" +@@ -1963,35 +1963,35 @@ static const struct test tests[] = { + "493647529271907416844436551070434271155969950809304288017790" + "4174497791.999", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -0xf.ffffffffffff8p+1020, false, +- -0xf.ffffffffffff8p+1020, false, +- -0xf.ffffffffffff8p+1020, false, +- false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffbffp+1020, false, +- -0xf.ffffffffffffbffp+1020, false, +- false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffbffp+1020, false, +- -0xf.ffffffffffffbffp+1020, false, +- false, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffbffffffffffffcp+1020, false, +- -0xf.ffffffffffffbffffffffffffcp+1020, false, +- false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffbffffffffffffff8p+1020, false, +- -0xf.ffffffffffffbffffffffffffff8p+1020, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffbffp+1020, false, false, ++ -0xf.ffffffffffffbffp+1020, false, false, ++ false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffbffp+1020, false, false, ++ -0xf.ffffffffffffbffp+1020, false, false, ++ false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffbffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffbffffffffffffcp+1020, false, false, ++ false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffbffffffffffffff8p+1020, false, false, ++ -0xf.ffffffffffffbffffffffffffff8p+1020, false, false), + TEST ("-17976931348623158079372897140530341507993413271003782693617" + "377898044496829276475094664901797758720709633028641669288791" + "094655554785194040263065748867150582068190890200070838367627" +@@ -1999,35 +1999,35 @@ static const struct test tests[] = { + "493647529271907416844436551070434271155969950809304288017790" + "4174497792", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, false, +- -0xf.ffffffffffff8p+1020, false, +- true, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- true, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- false, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- true, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ true, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ true, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ true, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false), + TEST ("-17976931348623158079372897140530341507993413271003782693617" + "377898044496829276475094664901797758720709633028641669288791" + "094655554785194040263065748867150582068190890200070838367627" +@@ -2035,35 +2035,35 @@ static const struct test tests[] = { + "493647529271907416844436551070434271155969950809304288017790" + "4174497792.001", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, false, +- -0xf.ffffffffffff8p+1020, false, +- false, +- -0xf.ffffffffffffc01p+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- false, +- -0xf.ffffffffffffc01p+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- false, +- -0xf.ffffffffffffc0000000000004p+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- -0xf.ffffffffffffcp+1020, true, +- false, +- -0xf.ffffffffffffc000000000000008p+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false, +- -0xf.ffffffffffffcp+1020, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ false, ++ -0xf.ffffffffffffc01p+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ false, ++ -0xf.ffffffffffffc01p+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ false, ++ -0xf.ffffffffffffc0000000000004p+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ -0xf.ffffffffffffcp+1020, true, false, ++ false, ++ -0xf.ffffffffffffc000000000000008p+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false, ++ -0xf.ffffffffffffcp+1020, false, false), + TEST ("118973149535723176505351158982948866796625400469556721895649" + "927756249918185172720476044944290457046138433056764616744328" + "666255526748948793023632513609765434237723241753648908036202" +@@ -2148,35 +2148,35 @@ static const struct test tests[] = { + "578031503869424406179027994752890226443351619365453243328968" + "8740976918527.999", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- 0xf.fffffffffffffffp+16380, false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- 0xf.fffffffffffffffp+16380, false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffff7fffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff7fffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffff7fffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff7fffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false), + TEST ("118973149535723176505351158982948866796625400469556721895649" + "927756249918185172720476044944290457046138433056764616744328" + "666255526748948793023632513609765434237723241753648908036202" +@@ -2261,35 +2261,35 @@ static const struct test tests[] = { + "578031503869424406179027994752890226443351619365453243328968" + "8740976918528", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- true, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ true, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false), + TEST ("118973149535723176505351158982948866796625400469556721895649" + "927756249918185172720476044944290457046138433056764616744328" + "666255526748948793023632513609765434237723241753648908036202" +@@ -2374,35 +2374,35 @@ static const struct test tests[] = { + "578031503869424406179027994752890226443351619365453243328968" + "8740976918528.001", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff8p+16380, false, +- 0xf.fffffffffffffff8000000000008p+16380, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffff8000000000008p+16380, false, false), + TEST ("-11897314953572317650535115898294886679662540046955672189564" + "992775624991818517272047604494429045704613843305676461674432" + "866625552674894879302363251360976543423772324175364890803620" +@@ -2487,35 +2487,35 @@ static const struct test tests[] = { + "557803150386942440617902799475289022644335161936545324332896" + "88740976918527.999", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff7fffffffffff8p+16380, false, +- -0xf.fffffffffffffff7fffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff7fffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff7fffffffffff8p+16380, false, false), + TEST ("-11897314953572317650535115898294886679662540046955672189564" + "992775624991818517272047604494429045704613843305676461674432" + "866625552674894879302363251360976543423772324175364890803620" +@@ -2600,35 +2600,35 @@ static const struct test tests[] = { + "557803150386942440617902799475289022644335161936545324332896" + "88740976918528", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- true, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ true, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false), + TEST ("-11897314953572317650535115898294886679662540046955672189564" + "992775624991818517272047604494429045704613843305676461674432" + "866625552674894879302363251360976543423772324175364890803620" +@@ -2713,35 +2713,35 @@ static const struct test tests[] = { + "557803150386942440617902799475289022644335161936545324332896" + "88740976918528.001", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -0xf.fffffffffffffff8000000000008p+16380, false, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff8p+16380, false, +- -0xf.fffffffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -0xf.fffffffffffffff8000000000008p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffff8p+16380, false, false), + TEST ("118973149535723176508575932662800707347995686986910214150118" + "685272271246896789803961473130416053705672050873552479421805" + "932646640744124594447361172514341324846716679654551308018400" +@@ -2826,35 +2826,35 @@ static const struct test tests[] = { + "972233447491583165728635513802591543441145939539353470970452" + "5536550715391.999", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false), + TEST ("118973149535723176508575932662800707347995686986910214150118" + "685272271246896789803961473130416053705672050873552479421805" + "932646640744124594447361172514341324846716679654551308018400" +@@ -2939,35 +2939,35 @@ static const struct test tests[] = { + "972233447491583165728635513802591543441145939539353470970452" + "5536550715392", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false), + TEST ("118973149535723176508575932662800707347995686986910214150118" + "685272271246896789803961473130416053705672050873552479421805" + "932646640744124594447361172514341324846716679654551308018400" +@@ -3052,35 +3052,35 @@ static const struct test tests[] = { + "972233447491583165728635513802591543441145939539353470970452" + "5536550715392.001", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false), + TEST ("-11897314953572317650857593266280070734799568698691021415011" + "868527227124689678980396147313041605370567205087355247942180" + "593264664074412459444736117251434132484671667965455130801840" +@@ -3165,35 +3165,35 @@ static const struct test tests[] = { + "097223344749158316572863551380259154344114593953935347097045" + "25536550715391.999", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -INF, true, +- -0xf.fffffffffffffffffffffffffff8p+16380, false, +- -0xf.fffffffffffffffffffffffffff8p+16380, false, +- -0xf.fffffffffffffffffffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false), + TEST ("-11897314953572317650857593266280070734799568698691021415011" + "868527227124689678980396147313041605370567205087355247942180" + "593264664074412459444736117251434132484671667965455130801840" +@@ -3278,35 +3278,35 @@ static const struct test tests[] = { + "097223344749158316572863551380259154344114593953935347097045" + "25536550715392", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffff8p+16380, false, +- -0xf.fffffffffffffffffffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false), + TEST ("-11897314953572317650857593266280070734799568698691021415011" + "868527227124689678980396147313041605370567205087355247942180" + "593264664074412459444736117251434132484671667965455130801840" +@@ -3391,419 +3391,419 @@ static const struct test tests[] = { + "097223344749158316572863551380259154344114593953935347097045" + "25536550715392.001", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffff8p+16380, false, +- -0xf.fffffffffffffffffffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false), + TEST ("2.1019476964872256063855943749348741969203929128147736576356" + "0242583468662402879090222995728254318237304687499e-45", + false, +- 0x8p-152, false, +- 0x8p-152, false, +- 0x8p-152, false, +- 0x1p-148, false, +- false, +- 0xb.ffffffffffff8p-152, false, +- 0xcp-152, false, +- 0xb.ffffffffffff8p-152, false, +- 0xcp-152, false, +- false, +- 0xb.fffffffffffffffp-152, false, +- 0xcp-152, false, +- 0xb.fffffffffffffffp-152, false, +- 0xcp-152, false, +- false, +- 0xb.fffffffffffffffp-152, false, +- 0xcp-152, false, +- 0xb.fffffffffffffffp-152, false, +- 0xcp-152, false, +- false, +- 0xb.fffffffffffffffffffffffffcp-152, false, +- 0xcp-152, false, +- 0xb.fffffffffffffffffffffffffcp-152, false, +- 0xcp-152, false, +- false, +- 0xb.fffffffffffffffffffffffffff8p-152, false, +- 0xcp-152, false, +- 0xb.fffffffffffffffffffffffffff8p-152, false, +- 0xcp-152, false), ++ 0x8p-152, false, true, ++ 0x8p-152, false, true, ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ false, ++ 0xb.ffffffffffff8p-152, false, false, ++ 0xcp-152, false, false, ++ 0xb.ffffffffffff8p-152, false, false, ++ 0xcp-152, false, false, ++ false, ++ 0xb.fffffffffffffffp-152, false, false, ++ 0xcp-152, false, false, ++ 0xb.fffffffffffffffp-152, false, false, ++ 0xcp-152, false, false, ++ false, ++ 0xb.fffffffffffffffp-152, false, false, ++ 0xcp-152, false, false, ++ 0xb.fffffffffffffffp-152, false, false, ++ 0xcp-152, false, false, ++ false, ++ 0xb.fffffffffffffffffffffffffcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xb.fffffffffffffffffffffffffcp-152, false, false, ++ 0xcp-152, false, false, ++ false, ++ 0xb.fffffffffffffffffffffffffff8p-152, false, false, ++ 0xcp-152, false, false, ++ 0xb.fffffffffffffffffffffffffff8p-152, false, false, ++ 0xcp-152, false, false), + TEST ("2.1019476964872256063855943749348741969203929128147736576356" + "02425834686624028790902229957282543182373046875e-45", + false, +- 0x8p-152, false, +- 0x1p-148, false, +- 0x8p-152, false, +- 0x1p-148, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- true, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false), ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ true, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false), + TEST ("2.1019476964872256063855943749348741969203929128147736576356" + "0242583468662402879090222995728254318237304687501e-45", + false, +- 0x8p-152, false, +- 0x1p-148, false, +- 0x8p-152, false, +- 0x1p-148, false, +- false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xc.0000000000008p-152, false, +- false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xc.000000000000001p-152, false, +- false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xc.000000000000001p-152, false, +- false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xc.00000000000000000000000004p-152, false, +- false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xcp-152, false, +- 0xc.0000000000000000000000000008p-152, false), ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ 0x8p-152, false, true, ++ 0x1p-148, false, true, ++ false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xc.0000000000008p-152, false, false, ++ false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xc.000000000000001p-152, false, false, ++ false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xc.000000000000001p-152, false, false, ++ false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xc.00000000000000000000000004p-152, false, false, ++ false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xcp-152, false, false, ++ 0xc.0000000000000000000000000008p-152, false, false), + TEST ("-2.101947696487225606385594374934874196920392912814773657635" + "60242583468662402879090222995728254318237304687499e-45", + false, +- -0x1p-148, false, +- -0x8p-152, false, +- -0x8p-152, false, +- -0x8p-152, false, +- false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xb.ffffffffffff8p-152, false, +- -0xb.ffffffffffff8p-152, false, +- false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xb.fffffffffffffffp-152, false, +- -0xb.fffffffffffffffp-152, false, +- false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xb.fffffffffffffffp-152, false, +- -0xb.fffffffffffffffp-152, false, +- false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xb.fffffffffffffffffffffffffcp-152, false, +- -0xb.fffffffffffffffffffffffffcp-152, false, +- false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xb.fffffffffffffffffffffffffff8p-152, false, +- -0xb.fffffffffffffffffffffffffff8p-152, false), ++ -0x1p-148, false, true, ++ -0x8p-152, false, true, ++ -0x8p-152, false, true, ++ -0x8p-152, false, true, ++ false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xb.ffffffffffff8p-152, false, false, ++ -0xb.ffffffffffff8p-152, false, false, ++ false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xb.fffffffffffffffp-152, false, false, ++ -0xb.fffffffffffffffp-152, false, false, ++ false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xb.fffffffffffffffp-152, false, false, ++ -0xb.fffffffffffffffp-152, false, false, ++ false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xb.fffffffffffffffffffffffffcp-152, false, false, ++ -0xb.fffffffffffffffffffffffffcp-152, false, false, ++ false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xb.fffffffffffffffffffffffffff8p-152, false, false, ++ -0xb.fffffffffffffffffffffffffff8p-152, false, false), + TEST ("-2.101947696487225606385594374934874196920392912814773657635" + "602425834686624028790902229957282543182373046875e-45", + false, +- -0x1p-148, false, +- -0x1p-148, false, +- -0x8p-152, false, +- -0x8p-152, false, +- true, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- true, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- true, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- true, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- true, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false), ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ -0x8p-152, false, true, ++ -0x8p-152, false, true, ++ true, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ true, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ true, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ true, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ true, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false), + TEST ("-2.101947696487225606385594374934874196920392912814773657635" + "60242583468662402879090222995728254318237304687501e-45", + false, +- -0x1p-148, false, +- -0x1p-148, false, +- -0x8p-152, false, +- -0x8p-152, false, +- false, +- -0xc.0000000000008p-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- false, +- -0xc.000000000000001p-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- false, +- -0xc.000000000000001p-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- false, +- -0xc.00000000000000000000000004p-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- false, +- -0xc.0000000000000000000000000008p-152, false, +- -0xcp-152, false, +- -0xcp-152, false, +- -0xcp-152, false), ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ -0x8p-152, false, true, ++ -0x8p-152, false, true, ++ false, ++ -0xc.0000000000008p-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ false, ++ -0xc.000000000000001p-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ false, ++ -0xc.000000000000001p-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ false, ++ -0xc.00000000000000000000000004p-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ false, ++ -0xc.0000000000000000000000000008p-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false, ++ -0xcp-152, false, false), + TEST ("3.5032461608120426773093239582247903282006548546912894293926" + "7070972447770671465150371659547090530395507812499e-45", + false, +- 0x1p-148, false, +- 0x1p-148, false, +- 0x1p-148, false, +- 0x1.8p-148, false, +- false, +- 0x1.3ffffffffffffp-148, false, +- 0x1.4p-148, false, +- 0x1.3ffffffffffffp-148, false, +- 0x1.4p-148, false, +- false, +- 0x1.3ffffffffffffffep-148, false, +- 0x1.4p-148, false, +- 0x1.3ffffffffffffffep-148, false, +- 0x1.4p-148, false, +- false, +- 0x1.3ffffffffffffffep-148, false, +- 0x1.4p-148, false, +- 0x1.3ffffffffffffffep-148, false, +- 0x1.4p-148, false, +- false, +- 0x1.3fffffffffffffffffffffffff8p-148, false, +- 0x1.4p-148, false, +- 0x1.3fffffffffffffffffffffffff8p-148, false, +- 0x1.4p-148, false, +- false, +- 0x1.3fffffffffffffffffffffffffffp-148, false, +- 0x1.4p-148, false, +- 0x1.3fffffffffffffffffffffffffffp-148, false, +- 0x1.4p-148, false), ++ 0x1p-148, false, true, ++ 0x1p-148, false, true, ++ 0x1p-148, false, true, ++ 0x1.8p-148, false, true, ++ false, ++ 0x1.3ffffffffffffp-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.3ffffffffffffp-148, false, false, ++ 0x1.4p-148, false, false, ++ false, ++ 0x1.3ffffffffffffffep-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.3ffffffffffffffep-148, false, false, ++ 0x1.4p-148, false, false, ++ false, ++ 0x1.3ffffffffffffffep-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.3ffffffffffffffep-148, false, false, ++ 0x1.4p-148, false, false, ++ false, ++ 0x1.3fffffffffffffffffffffffff8p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.3fffffffffffffffffffffffff8p-148, false, false, ++ 0x1.4p-148, false, false, ++ false, ++ 0x1.3fffffffffffffffffffffffffffp-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.3fffffffffffffffffffffffffffp-148, false, false, ++ 0x1.4p-148, false, false), + TEST ("3.5032461608120426773093239582247903282006548546912894293926" + "70709724477706714651503716595470905303955078125e-45", + false, +- 0x1p-148, false, +- 0x1p-148, false, +- 0x1p-148, false, +- 0x1.8p-148, false, +- true, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- true, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- true, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- true, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- true, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false), ++ 0x1p-148, false, true, ++ 0x1p-148, false, true, ++ 0x1p-148, false, true, ++ 0x1.8p-148, false, true, ++ true, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ true, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ true, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ true, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ true, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false), + TEST ("3.5032461608120426773093239582247903282006548546912894293926" + "7070972447770671465150371659547090530395507812501e-45", + false, +- 0x1p-148, false, +- 0x1.8p-148, false, +- 0x1p-148, false, +- 0x1.8p-148, false, +- false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4000000000001p-148, false, +- false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4000000000000002p-148, false, +- false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4000000000000002p-148, false, +- false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.400000000000000000000000008p-148, false, +- false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4p-148, false, +- 0x1.4000000000000000000000000001p-148, false), ++ 0x1p-148, false, true, ++ 0x1.8p-148, false, true, ++ 0x1p-148, false, true, ++ 0x1.8p-148, false, true, ++ false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4000000000001p-148, false, false, ++ false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4000000000000002p-148, false, false, ++ false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4000000000000002p-148, false, false, ++ false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.400000000000000000000000008p-148, false, false, ++ false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4p-148, false, false, ++ 0x1.4000000000000000000000000001p-148, false, false), + TEST ("-3.503246160812042677309323958224790328200654854691289429392" + "67070972447770671465150371659547090530395507812499e-45", + false, +- -0x1.8p-148, false, +- -0x1p-148, false, +- -0x1p-148, false, +- -0x1p-148, false, +- false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.3ffffffffffffp-148, false, +- -0x1.3ffffffffffffp-148, false, +- false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.3ffffffffffffffep-148, false, +- -0x1.3ffffffffffffffep-148, false, +- false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.3ffffffffffffffep-148, false, +- -0x1.3ffffffffffffffep-148, false, +- false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.3fffffffffffffffffffffffff8p-148, false, +- -0x1.3fffffffffffffffffffffffff8p-148, false, +- false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.3fffffffffffffffffffffffffffp-148, false, +- -0x1.3fffffffffffffffffffffffffffp-148, false), ++ -0x1.8p-148, false, true, ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.3ffffffffffffp-148, false, false, ++ -0x1.3ffffffffffffp-148, false, false, ++ false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.3ffffffffffffffep-148, false, false, ++ -0x1.3ffffffffffffffep-148, false, false, ++ false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.3ffffffffffffffep-148, false, false, ++ -0x1.3ffffffffffffffep-148, false, false, ++ false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.3fffffffffffffffffffffffff8p-148, false, false, ++ -0x1.3fffffffffffffffffffffffff8p-148, false, false, ++ false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.3fffffffffffffffffffffffffffp-148, false, false, ++ -0x1.3fffffffffffffffffffffffffffp-148, false, false), + TEST ("-3.503246160812042677309323958224790328200654854691289429392" + "670709724477706714651503716595470905303955078125e-45", + false, +- -0x1.8p-148, false, +- -0x1p-148, false, +- -0x1p-148, false, +- -0x1p-148, false, +- true, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- true, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- true, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- true, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- true, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false), ++ -0x1.8p-148, false, true, ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ true, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ true, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ true, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ true, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ true, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false), + TEST ("-3.503246160812042677309323958224790328200654854691289429392" + "67070972447770671465150371659547090530395507812501e-45", + false, +- -0x1.8p-148, false, +- -0x1.8p-148, false, +- -0x1p-148, false, +- -0x1p-148, false, +- false, +- -0x1.4000000000001p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- false, +- -0x1.4000000000000002p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- false, +- -0x1.4000000000000002p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- false, +- -0x1.400000000000000000000000008p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- false, +- -0x1.4000000000000000000000000001p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false, +- -0x1.4p-148, false), ++ -0x1.8p-148, false, true, ++ -0x1.8p-148, false, true, ++ -0x1p-148, false, true, ++ -0x1p-148, false, true, ++ false, ++ -0x1.4000000000001p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ false, ++ -0x1.4000000000000002p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ false, ++ -0x1.4000000000000002p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ false, ++ -0x1.400000000000000000000000008p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ false, ++ -0x1.4000000000000000000000000001p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false, ++ -0x1.4p-148, false, false), + TEST ("7.4109846876186981626485318930233205854758970392148714663837" + "852375101326090531312779794975454245398856969484704316857659" + "638998506553390969459816219401617281718945106978546710679176" +@@ -3818,35 +3818,35 @@ static const struct test tests[] = { + "337560846003984904972149117463085539556354188641513168478436" + "31308023759629577398300170898437499e-324", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x4p-1076, false, +- 0x4p-1076, false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- false, +- 0x5.fffffffffffffff8p-1076, false, +- 0x6p-1076, false, +- 0x5.fffffffffffffff8p-1076, false, +- 0x6p-1076, false, +- false, +- 0x5.fffffffffffffff8p-1076, false, +- 0x6p-1076, false, +- 0x5.fffffffffffffff8p-1076, false, +- 0x6p-1076, false, +- false, +- 0x4p-1076, false, +- 0x4p-1076, false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- false, +- 0x5.fffffffffffffffffffffffffffcp-1076, false, +- 0x6p-1076, false, +- 0x5.fffffffffffffffffffffffffffcp-1076, false, +- 0x6p-1076, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x4p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ false, ++ 0x5.fffffffffffffff8p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x5.fffffffffffffff8p-1076, false, false, ++ 0x6p-1076, false, false, ++ false, ++ 0x5.fffffffffffffff8p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x5.fffffffffffffff8p-1076, false, false, ++ 0x6p-1076, false, false, ++ false, ++ 0x4p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ false, ++ 0x5.fffffffffffffffffffffffffffcp-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x5.fffffffffffffffffffffffffffcp-1076, false, false, ++ 0x6p-1076, false, false), + TEST ("7.4109846876186981626485318930233205854758970392148714663837" + "852375101326090531312779794975454245398856969484704316857659" + "638998506553390969459816219401617281718945106978546710679176" +@@ -3861,35 +3861,35 @@ static const struct test tests[] = { + "337560846003984904972149117463085539556354188641513168478436" + "313080237596295773983001708984375e-324", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- true, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- true, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- true, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ true, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ true, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ false, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ true, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false), + TEST ("7.4109846876186981626485318930233205854758970392148714663837" + "852375101326090531312779794975454245398856969484704316857659" + "638998506553390969459816219401617281718945106978546710679176" +@@ -3904,35 +3904,35 @@ static const struct test tests[] = { + "337560846003984904972149117463085539556354188641513168478436" + "31308023759629577398300170898437501e-324", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6.0000000000000008p-1076, false, +- false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6.0000000000000008p-1076, false, +- false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- 0x4p-1076, false, +- 0x8p-1076, false, +- false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6p-1076, false, +- 0x6.0000000000000000000000000004p-1076, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6.0000000000000008p-1076, false, false, ++ false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6.0000000000000008p-1076, false, false, ++ false, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ 0x4p-1076, false, true, ++ 0x8p-1076, false, true, ++ false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6p-1076, false, false, ++ 0x6.0000000000000000000000000004p-1076, false, false), + TEST ("-7.410984687618698162648531893023320585475897039214871466383" + "785237510132609053131277979497545424539885696948470431685765" + "963899850655339096945981621940161728171894510697854671067917" +@@ -3947,35 +3947,35 @@ static const struct test tests[] = { + "433756084600398490497214911746308553955635418864151316847843" + "631308023759629577398300170898437499e-324", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x5.fffffffffffffff8p-1076, false, +- -0x5.fffffffffffffff8p-1076, false, +- false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x5.fffffffffffffff8p-1076, false, +- -0x5.fffffffffffffff8p-1076, false, +- false, +- -0x8p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x5.fffffffffffffffffffffffffffcp-1076, false, +- -0x5.fffffffffffffffffffffffffffcp-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x5.fffffffffffffff8p-1076, false, false, ++ -0x5.fffffffffffffff8p-1076, false, false, ++ false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x5.fffffffffffffff8p-1076, false, false, ++ -0x5.fffffffffffffff8p-1076, false, false, ++ false, ++ -0x8p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x5.fffffffffffffffffffffffffffcp-1076, false, false, ++ -0x5.fffffffffffffffffffffffffffcp-1076, false, false), + TEST ("-7.410984687618698162648531893023320585475897039214871466383" + "785237510132609053131277979497545424539885696948470431685765" + "963899850655339096945981621940161728171894510697854671067917" +@@ -3990,35 +3990,35 @@ static const struct test tests[] = { + "433756084600398490497214911746308553955635418864151316847843" + "6313080237596295773983001708984375e-324", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-1076, false, +- -0x8p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- true, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- true, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- false, +- -0x8p-1076, false, +- -0x8p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- true, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-1076, false, true, ++ -0x8p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ true, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ true, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ false, ++ -0x8p-1076, false, true, ++ -0x8p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ true, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false), + TEST ("-7.410984687618698162648531893023320585475897039214871466383" + "785237510132609053131277979497545424539885696948470431685765" + "963899850655339096945981621940161728171894510697854671067917" +@@ -4033,35 +4033,35 @@ static const struct test tests[] = { + "433756084600398490497214911746308553955635418864151316847843" + "631308023759629577398300170898437501e-324", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-1076, false, +- -0x8p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- false, +- -0x6.0000000000000008p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- false, +- -0x6.0000000000000008p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- false, +- -0x8p-1076, false, +- -0x8p-1076, false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- false, +- -0x6.0000000000000000000000000004p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false, +- -0x6p-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-1076, false, true, ++ -0x8p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ false, ++ -0x6.0000000000000008p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ false, ++ -0x6.0000000000000008p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ false, ++ -0x8p-1076, false, true, ++ -0x8p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ false, ++ -0x6.0000000000000000000000000004p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false, ++ -0x6p-1076, false, false), + TEST ("5.4677992978237119037926089004291297245985762235403450155814" + "707305425575329500966052143410629387408077958710210208052966" + "529504784489330482549602621133847135082257338717668975178538" +@@ -4255,35 +4255,35 @@ static const struct test tests[] = { + "866268925981702690270202829595794350800918257913991744455922" + "683343374046671669930219650268554687499e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x8p-16448, false, +- 0x8p-16448, false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- false, +- 0x8p-16448, false, +- 0xcp-16448, false, +- 0x8p-16448, false, +- 0xcp-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0xb.fffffffffffcp-16448, false, +- 0xcp-16448, false, +- 0xb.fffffffffffcp-16448, false, +- 0xcp-16448, 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, ++ 0x8p-16448, false, true, ++ 0x8p-16448, false, true, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ false, ++ 0x8p-16448, false, true, ++ 0xcp-16448, false, true, ++ 0x8p-16448, false, true, ++ 0xcp-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0xb.fffffffffffcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xb.fffffffffffcp-16448, false, true, ++ 0xcp-16448, false, true), + TEST ("5.4677992978237119037926089004291297245985762235403450155814" + "707305425575329500966052143410629387408077958710210208052966" + "529504784489330482549602621133847135082257338717668975178538" +@@ -4477,35 +4477,35 @@ static const struct test tests[] = { + "866268925981702690270202829595794350800918257913991744455922" + "6833433740466716699302196502685546875e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- true, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, 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, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ true, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false), + TEST ("5.4677992978237119037926089004291297245985762235403450155814" + "707305425575329500966052143410629387408077958710210208052966" + "529504784489330482549602621133847135082257338717668975178538" +@@ -4699,35 +4699,35 @@ static const struct test tests[] = { + "866268925981702690270202829595794350800918257913991744455922" + "683343374046671669930219650268554687501e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0x1p-16444, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xc.000000000004p-16448, 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, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ false, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0x1p-16444, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xc.000000000004p-16448, false, true), + TEST ("-5.467799297823711903792608900429129724598576223540345015581" + "470730542557532950096605214341062938740807795871021020805296" + "652950478448933048254960262113384713508225733871766897517853" +@@ -4921,35 +4921,35 @@ static const struct test tests[] = { + "386626892598170269027020282959579435080091825791399174445592" + "2683343374046671669930219650268554687499e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x1p-16444, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xb.fffffffffffcp-16448, false, +- -0xb.fffffffffffcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ false, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xb.fffffffffffcp-16448, false, true, ++ -0xb.fffffffffffcp-16448, false, true), + TEST ("-5.467799297823711903792608900429129724598576223540345015581" + "470730542557532950096605214341062938740807795871021020805296" + "652950478448933048254960262113384713508225733871766897517853" +@@ -5143,35 +5143,35 @@ static const struct test tests[] = { + "386626892598170269027020282959579435080091825791399174445592" + "26833433740466716699302196502685546875e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x1p-16444, false, +- -0x1p-16444, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- true, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0x1p-16444, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ true, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false), + TEST ("-5.467799297823711903792608900429129724598576223540345015581" + "470730542557532950096605214341062938740807795871021020805296" + "652950478448933048254960262113384713508225733871766897517853" +@@ -5365,35 +5365,35 @@ static const struct test tests[] = { + "386626892598170269027020282959579435080091825791399174445592" + "2683343374046671669930219650268554687501e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x1p-16444, false, +- -0x1p-16444, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- false, +- -0x1p-16444, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0xc.000000000004p-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0x1p-16444, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0xc.000000000004p-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true), + TEST ("5.4677992978237119037926089004291297245985762235403450155814" + "707305425575329500966052143410629387408077958710210208052966" + "529504784489330482549602621133847135082257338717668975178538" +@@ -5587,35 +5587,35 @@ static const struct test tests[] = { + "866268925981702690270202829595794350800918257913991744455922" + "683343374046671669930219650268554687499e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x8p-16448, false, +- 0x8p-16448, false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- false, +- 0x8p-16448, false, +- 0xcp-16448, false, +- 0x8p-16448, false, +- 0xcp-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0xb.fffffffffffcp-16448, false, +- 0xcp-16448, false, +- 0xb.fffffffffffcp-16448, false, +- 0xcp-16448, 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, ++ 0x8p-16448, false, true, ++ 0x8p-16448, false, true, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ false, ++ 0x8p-16448, false, true, ++ 0xcp-16448, false, true, ++ 0x8p-16448, false, true, ++ 0xcp-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0xb.fffffffffffcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xb.fffffffffffcp-16448, false, true, ++ 0xcp-16448, false, true), + TEST ("5.4677992978237119037926089004291297245985762235403450155814" + "707305425575329500966052143410629387408077958710210208052966" + "529504784489330482549602621133847135082257338717668975178538" +@@ -5809,35 +5809,35 @@ static const struct test tests[] = { + "866268925981702690270202829595794350800918257913991744455922" + "6833433740466716699302196502685546875e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- true, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, 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, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ true, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false, ++ 0xcp-16448, false, false), + TEST ("5.4677992978237119037926089004291297245985762235403450155814" + "707305425575329500966052143410629387408077958710210208052966" + "529504784489330482549602621133847135082257338717668975178538" +@@ -6031,35 +6031,35 @@ static const struct test tests[] = { + "866268925981702690270202829595794350800918257913991744455922" + "683343374046671669930219650268554687501e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- 0x8p-16448, false, +- 0x1p-16444, false, +- false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0x1p-16444, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xcp-16448, false, +- 0xc.000000000004p-16448, 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, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ 0x8p-16448, false, true, ++ 0x1p-16444, false, true, ++ false, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0x1p-16444, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xcp-16448, false, true, ++ 0xc.000000000004p-16448, false, true), + TEST ("-5.467799297823711903792608900429129724598576223540345015581" + "470730542557532950096605214341062938740807795871021020805296" + "652950478448933048254960262113384713508225733871766897517853" +@@ -6253,35 +6253,35 @@ static const struct test tests[] = { + "386626892598170269027020282959579435080091825791399174445592" + "2683343374046671669930219650268554687499e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x1p-16444, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xb.fffffffffffcp-16448, false, +- -0xb.fffffffffffcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ false, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xb.fffffffffffcp-16448, false, true, ++ -0xb.fffffffffffcp-16448, false, true), + TEST ("-5.467799297823711903792608900429129724598576223540345015581" + "470730542557532950096605214341062938740807795871021020805296" + "652950478448933048254960262113384713508225733871766897517853" +@@ -6475,35 +6475,35 @@ static const struct test tests[] = { + "386626892598170269027020282959579435080091825791399174445592" + "26833433740466716699302196502685546875e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x1p-16444, false, +- -0x1p-16444, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- true, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0x1p-16444, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ true, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false, ++ -0xcp-16448, false, false), + TEST ("-5.467799297823711903792608900429129724598576223540345015581" + "470730542557532950096605214341062938740807795871021020805296" + "652950478448933048254960262113384713508225733871766897517853" +@@ -6697,630 +6697,630 @@ static const struct test tests[] = { + "386626892598170269027020282959579435080091825791399174445592" + "2683343374046671669930219650268554687501e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x1p-16444, false, +- -0x1p-16444, false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- false, +- -0x1p-16444, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0xc.000000000004p-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false, +- -0xcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0x1p-16444, false, true, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ false, ++ -0x1p-16444, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0xc.000000000004p-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true, ++ -0xcp-16448, false, true), + TEST ("-0x0.7p-149", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- true, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- true, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- true, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- true, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false, +- -0x3.8p-152, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ true, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ true, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ true, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ true, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false, ++ -0x3.8p-152, false, false), + TEST ("-0x0.7p-1074", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- true, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false, +- -0x1.cp-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ true, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false, ++ -0x1.cp-1076, false, false), + TEST ("-0x0.7p-16445", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x3.8p-16448, false, +- -0x3.8p-16448, false, +- -0x3.8p-16448, false, +- -0x3.8p-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x3.8p-16448, false, false, ++ -0x3.8p-16448, false, false, ++ -0x3.8p-16448, false, false, ++ -0x3.8p-16448, false, false), + TEST ("-0x0.7p-16494", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16496, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16496, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true), + TEST ("0x1p-150", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false), + TEST ("0x1p-1075", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- true, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, 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, ++ true, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ true, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false), + TEST ("0x1p-16446", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- true, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ true, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false), + TEST ("0x1p-16495", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16496, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16496, false, true), + TEST ("-0x1p-150", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false), + TEST ("-0x1p-1075", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- true, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ true, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false), + TEST ("-0x1p-16446", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false), + TEST ("-0x1p-16495", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16496, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16496, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true), + TEST (".70064923216240853546186479164495807e-45", + false, +- 0x0p+0, false, +- 0x8p-152, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000004p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000000008p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000000008p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.00000000000000000000000002p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000000000000000000004p-152, false), ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000004p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000000008p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000000008p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.00000000000000000000000002p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000000000000000000004p-152, false, false), + TEST ("7.0064923216240853546186479164495806564013097093825788587853" + "4141944895541342930300743319094181060791015624e-46", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x3.ffffffffffffep-152, false, +- 0x4p-152, false, +- 0x3.ffffffffffffep-152, false, +- 0x4p-152, false, +- false, +- 0x3.fffffffffffffffcp-152, false, +- 0x4p-152, false, +- 0x3.fffffffffffffffcp-152, false, +- 0x4p-152, false, +- false, +- 0x3.fffffffffffffffcp-152, false, +- 0x4p-152, false, +- 0x3.fffffffffffffffcp-152, false, +- 0x4p-152, false, +- false, +- 0x3.ffffffffffffffffffffffffffp-152, false, +- 0x4p-152, false, +- 0x3.ffffffffffffffffffffffffffp-152, false, +- 0x4p-152, false, +- false, +- 0x3.fffffffffffffffffffffffffffep-152, false, +- 0x4p-152, false, +- 0x3.fffffffffffffffffffffffffffep-152, false, +- 0x4p-152, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x3.ffffffffffffep-152, false, false, ++ 0x4p-152, false, false, ++ 0x3.ffffffffffffep-152, false, false, ++ 0x4p-152, false, false, ++ false, ++ 0x3.fffffffffffffffcp-152, false, false, ++ 0x4p-152, false, false, ++ 0x3.fffffffffffffffcp-152, false, false, ++ 0x4p-152, false, false, ++ false, ++ 0x3.fffffffffffffffcp-152, false, false, ++ 0x4p-152, false, false, ++ 0x3.fffffffffffffffcp-152, false, false, ++ 0x4p-152, false, false, ++ false, ++ 0x3.ffffffffffffffffffffffffffp-152, false, false, ++ 0x4p-152, false, false, ++ 0x3.ffffffffffffffffffffffffffp-152, false, false, ++ 0x4p-152, false, false, ++ false, ++ 0x3.fffffffffffffffffffffffffffep-152, false, false, ++ 0x4p-152, false, false, ++ 0x3.fffffffffffffffffffffffffffep-152, false, false, ++ 0x4p-152, false, false), + TEST ("7.0064923216240853546186479164495806564013097093825788587853" + "4141944895541342930300743319094181060791015625e-46", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- true, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ true, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false), + TEST ("7.0064923216240853546186479164495806564013097093825788587853" + "4141944895541342930300743319094181060791015626e-46", + false, +- 0x0p+0, false, +- 0x8p-152, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000004p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000000008p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000000008p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.00000000000000000000000002p-152, false, +- false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4p-152, false, +- 0x4.0000000000000000000000000004p-152, false), ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000004p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000000008p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000000008p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.00000000000000000000000002p-152, false, false, ++ false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4p-152, false, false, ++ 0x4.0000000000000000000000000004p-152, false, false), + TEST ("-7.006492321624085354618647916449580656401309709382578858785" + "34141944895541342930300743319094181060791015624e-46", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x3.ffffffffffffep-152, false, +- -0x3.ffffffffffffep-152, false, +- false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x3.fffffffffffffffcp-152, false, +- -0x3.fffffffffffffffcp-152, false, +- false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x3.fffffffffffffffcp-152, false, +- -0x3.fffffffffffffffcp-152, false, +- false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x3.ffffffffffffffffffffffffffp-152, false, +- -0x3.ffffffffffffffffffffffffffp-152, false, +- false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x3.fffffffffffffffffffffffffffep-152, false, +- -0x3.fffffffffffffffffffffffffffep-152, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x3.ffffffffffffep-152, false, false, ++ -0x3.ffffffffffffep-152, false, false, ++ false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x3.fffffffffffffffcp-152, false, false, ++ -0x3.fffffffffffffffcp-152, false, false, ++ false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x3.fffffffffffffffcp-152, false, false, ++ -0x3.fffffffffffffffcp-152, false, false, ++ false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x3.ffffffffffffffffffffffffffp-152, false, false, ++ -0x3.ffffffffffffffffffffffffffp-152, false, false, ++ false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x3.fffffffffffffffffffffffffffep-152, false, false, ++ -0x3.fffffffffffffffffffffffffffep-152, false, false), + TEST ("-7.006492321624085354618647916449580656401309709382578858785" + "34141944895541342930300743319094181060791015625e-46", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- true, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ true, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false), + TEST ("-7.006492321624085354618647916449580656401309709382578858785" + "34141944895541342930300743319094181060791015626e-46", + false, +- -0x8p-152, false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4.0000000000004p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- false, +- -0x4.0000000000000008p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- false, +- -0x4.0000000000000008p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- false, +- -0x4.00000000000000000000000002p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- false, +- -0x4.0000000000000000000000000004p-152, false, +- -0x4p-152, false, +- -0x4p-152, false, +- -0x4p-152, false), ++ -0x8p-152, false, true, ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4.0000000000004p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ false, ++ -0x4.0000000000000008p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ false, ++ -0x4.0000000000000008p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ false, ++ -0x4.00000000000000000000000002p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ false, ++ -0x4.0000000000000000000000000004p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false, ++ -0x4p-152, false, false), + TEST ("2.4703282292062327208828439643411068618252990130716238221279" + "284125033775363510437593264991818081799618989828234772285886" + "546332835517796989819938739800539093906315035659515570226392" +@@ -7335,35 +7335,35 @@ static const struct test tests[] = { + "779186948667994968324049705821028513185451396213837722826145" + "437693412532098591327667236328124e-324", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x1.fffffffffffffffep-1076, false, +- 0x2p-1076, false, +- 0x1.fffffffffffffffep-1076, false, +- 0x2p-1076, false, +- false, +- 0x1.fffffffffffffffep-1076, false, +- 0x2p-1076, false, +- 0x1.fffffffffffffffep-1076, false, +- 0x2p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x1.ffffffffffffffffffffffffffffp-1076, false, +- 0x2p-1076, false, +- 0x1.ffffffffffffffffffffffffffffp-1076, false, +- 0x2p-1076, 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.fffffffffffffffep-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x1.fffffffffffffffep-1076, false, false, ++ 0x2p-1076, false, false, ++ false, ++ 0x1.fffffffffffffffep-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x1.fffffffffffffffep-1076, false, false, ++ 0x2p-1076, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x1.ffffffffffffffffffffffffffffp-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x1.ffffffffffffffffffffffffffffp-1076, false, false, ++ 0x2p-1076, false, false), + TEST ("2.4703282292062327208828439643411068618252990130716238221279" + "284125033775363510437593264991818081799618989828234772285886" + "546332835517796989819938739800539093906315035659515570226392" +@@ -7378,35 +7378,35 @@ static const struct test tests[] = { + "779186948667994968324049705821028513185451396213837722826145" + "437693412532098591327667236328125e-324", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- true, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, 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, ++ true, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ true, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false), + TEST ("2.4703282292062327208828439643411068618252990130716238221279" + "284125033775363510437593264991818081799618989828234772285886" + "546332835517796989819938739800539093906315035659515570226392" +@@ -7421,35 +7421,35 @@ static const struct test tests[] = { + "779186948667994968324049705821028513185451396213837722826145" + "437693412532098591327667236328126e-324", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x4p-1076, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2.0000000000000004p-1076, false, +- false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2.0000000000000004p-1076, false, +- false, +- 0x0p+0, false, +- 0x4p-1076, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2p-1076, false, +- 0x2.0000000000000000000000000002p-1076, false), ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-152, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2.0000000000000004p-1076, false, false, ++ false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2.0000000000000004p-1076, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2p-1076, false, false, ++ 0x2.0000000000000000000000000002p-1076, false, false), + TEST ("-2.470328229206232720882843964341106861825299013071623822127" + "928412503377536351043759326499181808179961898982823477228588" + "654633283551779698981993873980053909390631503565951557022639" +@@ -7464,35 +7464,35 @@ static const struct test tests[] = { + "477918694866799496832404970582102851318545139621383772282614" + "5437693412532098591327667236328124e-324", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x1.fffffffffffffffep-1076, false, +- -0x1.fffffffffffffffep-1076, false, +- false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x1.fffffffffffffffep-1076, false, +- -0x1.fffffffffffffffep-1076, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x1.ffffffffffffffffffffffffffffp-1076, false, +- -0x1.ffffffffffffffffffffffffffffp-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x1.fffffffffffffffep-1076, false, false, ++ -0x1.fffffffffffffffep-1076, false, false, ++ false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x1.fffffffffffffffep-1076, false, false, ++ -0x1.fffffffffffffffep-1076, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x1.ffffffffffffffffffffffffffffp-1076, false, false, ++ -0x1.ffffffffffffffffffffffffffffp-1076, false, false), + TEST ("-2.470328229206232720882843964341106861825299013071623822127" + "928412503377536351043759326499181808179961898982823477228588" + "654633283551779698981993873980053909390631503565951557022639" +@@ -7507,35 +7507,35 @@ static const struct test tests[] = { + "477918694866799496832404970582102851318545139621383772282614" + "5437693412532098591327667236328125e-324", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- true, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ true, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false), + TEST ("-2.470328229206232720882843964341106861825299013071623822127" + "928412503377536351043759326499181808179961898982823477228588" + "654633283551779698981993873980053909390631503565951557022639" +@@ -7550,35 +7550,35 @@ static const struct test tests[] = { + "477918694866799496832404970582102851318545139621383772282614" + "5437693412532098591327667236328126e-324", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x2.0000000000000004p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- false, +- -0x2.0000000000000004p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- false, +- -0x4p-1076, false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x2.0000000000000000000000000002p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false, +- -0x2p-1076, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x2.0000000000000004p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ false, ++ -0x2.0000000000000004p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x2.0000000000000000000000000002p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false, ++ -0x2p-1076, false, false), + TEST ("1.8225997659412373012642029668097099081995254078467816718604" + "902435141858443166988684047803543129136025986236736736017655" + "509834928163110160849867540377949045027419112905889658392846" +@@ -7772,35 +7772,35 @@ static const struct test tests[] = { + "622089641993900896756734276531931450266972752637997248151974" + "2277811246822238899767398834228515624e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x4p-16448, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x3.fffffffffffcp-16448, false, +- 0x4p-16448, false, +- 0x3.fffffffffffcp-16448, false, +- 0x4p-16448, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x3.fffffffffffcp-16448, false, true, ++ 0x4p-16448, false, true, ++ 0x3.fffffffffffcp-16448, false, true, ++ 0x4p-16448, false, true), + TEST ("1.8225997659412373012642029668097099081995254078467816718604" + "902435141858443166988684047803543129136025986236736736017655" + "509834928163110160849867540377949045027419112905889658392846" +@@ -7994,35 +7994,35 @@ static const struct test tests[] = { + "622089641993900896756734276531931450266972752637997248151974" + "2277811246822238899767398834228515625e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- true, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ true, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false, ++ 0x4p-16448, false, false), + TEST ("1.8225997659412373012642029668097099081995254078467816718604" + "902435141858443166988684047803543129136025986236736736017655" + "509834928163110160849867540377949045027419112905889658392846" +@@ -8216,35 +8216,35 @@ static const struct test tests[] = { + "622089641993900896756734276531931450266972752637997248151974" + "2277811246822238899767398834228515626e-4951", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x8p-16448, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4p-16448, false, +- 0x4.000000000004p-16448, 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, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x4p-16448, false, true, ++ 0x4p-16448, false, true, ++ 0x4p-16448, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x4p-16448, false, true, ++ 0x4p-16448, false, true, ++ 0x4p-16448, false, true, ++ 0x4.000000000004p-16448, false, true), + TEST ("-1.822599765941237301264202966809709908199525407846781671860" + "490243514185844316698868404780354312913602598623673673601765" + "550983492816311016084986754037794904502741911290588965839284" +@@ -8438,35 +8438,35 @@ static const struct test tests[] = { + "462208964199390089675673427653193145026697275263799724815197" + "42277811246822238899767398834228515624e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x3.fffffffffffcp-16448, false, +- -0x3.fffffffffffcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x3.fffffffffffcp-16448, false, true, ++ -0x3.fffffffffffcp-16448, false, true), + TEST ("-1.822599765941237301264202966809709908199525407846781671860" + "490243514185844316698868404780354312913602598623673673601765" + "550983492816311016084986754037794904502741911290588965839284" +@@ -8660,35 +8660,35 @@ static const struct test tests[] = { + "462208964199390089675673427653193145026697275263799724815197" + "42277811246822238899767398834228515625e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false, ++ -0x4p-16448, false, false), + TEST ("-1.822599765941237301264202966809709908199525407846781671860" + "490243514185844316698868404780354312913602598623673673601765" + "550983492816311016084986754037794904502741911290588965839284" +@@ -8882,35 +8882,35 @@ static const struct test tests[] = { + "462208964199390089675673427653193145026697275263799724815197" + "42277811246822238899767398834228515626e-4951", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4.000000000004p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x4p-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4.000000000004p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true), + TEST ("9.1129988297061865063210148340485495409976270392339083593024" + "512175709292215834943420239017715645680129931183683680088277" + "549174640815550804249337701889745225137095564529448291964230" +@@ -9104,35 +9104,35 @@ static const struct test tests[] = { + "110448209969504483783671382659657251334863763189986240759871" + "1389056234111194498836994171142578124e-4952", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x1.fffffffffffcp-16448, false, +- 0x2p-16448, false, +- 0x1.fffffffffffcp-16448, false, +- 0x2p-16448, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x1.fffffffffffcp-16448, false, true, ++ 0x2p-16448, false, true, ++ 0x1.fffffffffffcp-16448, false, true, ++ 0x2p-16448, false, true), + TEST ("9.1129988297061865063210148340485495409976270392339083593024" + "512175709292215834943420239017715645680129931183683680088277" + "549174640815550804249337701889745225137095564529448291964230" +@@ -9326,35 +9326,35 @@ static const struct test tests[] = { + "110448209969504483783671382659657251334863763189986240759871" + "1389056234111194498836994171142578125e-4952", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- true, +- 0x2p-16448, false, +- 0x2p-16448, false, +- 0x2p-16448, false, +- 0x2p-16448, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ true, ++ 0x2p-16448, false, false, ++ 0x2p-16448, false, false, ++ 0x2p-16448, false, false, ++ 0x2p-16448, false, false), + TEST ("9.1129988297061865063210148340485495409976270392339083593024" + "512175709292215834943420239017715645680129931183683680088277" + "549174640815550804249337701889745225137095564529448291964230" +@@ -9548,35 +9548,35 @@ static const struct test tests[] = { + "110448209969504483783671382659657251334863763189986240759871" + "1389056234111194498836994171142578126e-4952", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x4p-16448, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x2p-16448, false, +- 0x2p-16448, false, +- 0x2p-16448, false, +- 0x2.000000000004p-16448, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x2p-16448, false, true, ++ 0x2p-16448, false, true, ++ 0x2p-16448, false, true, ++ 0x2.000000000004p-16448, false, true), + TEST ("-9.112998829706186506321014834048549540997627039233908359302" + "451217570929221583494342023901771564568012993118368368008827" + "754917464081555080424933770188974522513709556452944829196423" +@@ -9770,35 +9770,35 @@ static const struct test tests[] = { + "311044820996950448378367138265965725133486376318998624075987" + "11389056234111194498836994171142578124e-4952", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x2p-16448, false, +- -0x2p-16448, false, +- -0x1.fffffffffffcp-16448, false, +- -0x1.fffffffffffcp-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x2p-16448, false, true, ++ -0x2p-16448, false, true, ++ -0x1.fffffffffffcp-16448, false, true, ++ -0x1.fffffffffffcp-16448, false, true), + TEST ("-9.112998829706186506321014834048549540997627039233908359302" + "451217570929221583494342023901771564568012993118368368008827" + "754917464081555080424933770188974522513709556452944829196423" +@@ -9992,35 +9992,35 @@ static const struct test tests[] = { + "311044820996950448378367138265965725133486376318998624075987" + "11389056234111194498836994171142578125e-4952", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- true, +- -0x2p-16448, false, +- -0x2p-16448, false, +- -0x2p-16448, false, +- -0x2p-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ true, ++ -0x2p-16448, false, false, ++ -0x2p-16448, false, false, ++ -0x2p-16448, false, false, ++ -0x2p-16448, false, false), + TEST ("-9.112998829706186506321014834048549540997627039233908359302" + "451217570929221583494342023901771564568012993118368368008827" + "754917464081555080424933770188974522513709556452944829196423" +@@ -10214,35 +10214,35 @@ static const struct test tests[] = { + "311044820996950448378367138265965725133486376318998624075987" + "11389056234111194498836994171142578126e-4952", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x2.000000000004p-16448, false, +- -0x2p-16448, false, +- -0x2p-16448, false, +- -0x2p-16448, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x2.000000000004p-16448, false, true, ++ -0x2p-16448, false, true, ++ -0x2p-16448, false, true, ++ -0x2p-16448, false, true), + TEST ("3.2375875597190125554622194791138232762497846690173405048449" + "421945985197700620596855088357456383249701279390707384240598" + "382936099431912710233425550359863089915213963553756674672083" +@@ -10437,35 +10437,35 @@ static const struct test tests[] = { + "182358152808745703724362178773168996492870519432472065091133" + "11767578124e-4966", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16496, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16496, false, true), + TEST ("3.2375875597190125554622194791138232762497846690173405048449" + "421945985197700620596855088357456383249701279390707384240598" + "382936099431912710233425550359863089915213963553756674672083" +@@ -10660,35 +10660,35 @@ static const struct test tests[] = { + "182358152808745703724362178773168996492870519432472065091133" + "11767578125e-4966", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16496, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16496, false, true), + TEST ("3.2375875597190125554622194791138232762497846690173405048449" + "421945985197700620596855088357456383249701279390707384240598" + "382936099431912710233425550359863089915213963553756674672083" +@@ -10883,35 +10883,35 @@ static const struct test tests[] = { + "182358152808745703724362178773168996492870519432472065091133" + "11767578126e-4966", + false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-152, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x8p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-16448, false, +- false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x0p+0, false, +- 0x4p-1076, false, +- false, +- 0x0p+0, false, +- 0x4p-16496, false, +- 0x0p+0, false, +- 0x4p-16496, 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, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x8p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16448, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x0p+0, false, true, ++ 0x4p-1076, false, true, ++ false, ++ 0x0p+0, false, true, ++ 0x4p-16496, false, true, ++ 0x0p+0, false, true, ++ 0x4p-16496, false, true), + TEST ("-3.237587559719012555462219479113823276249784669017340504844" + "942194598519770062059685508835745638324970127939070738424059" + "838293609943191271023342555035986308991521396355375667467208" +@@ -11106,35 +11106,35 @@ static const struct test tests[] = { + "218235815280874570372436217877316899649287051943247206509113" + "311767578124e-4966", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16496, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16496, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true), + TEST ("-3.237587559719012555462219479113823276249784669017340504844" + "942194598519770062059685508835745638324970127939070738424059" + "838293609943191271023342555035986308991521396355375667467208" +@@ -11329,35 +11329,35 @@ static const struct test tests[] = { + "218235815280874570372436217877316899649287051943247206509113" + "311767578125e-4966", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16496, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16496, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true), + TEST ("-3.237587559719012555462219479113823276249784669017340504844" + "942194598519770062059685508835745638324970127939070738424059" + "838293609943191271023342555035986308991521396355375667467208" +@@ -11552,66 +11552,66 @@ static const struct test tests[] = { + "218235815280874570372436217877316899649287051943247206509113" + "311767578126e-4966", + false, +- -0x8p-152, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x8p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16448, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-1076, false, +- -0x0p+0, false, +- -0x0p+0, false, +- -0x0p+0, false, +- false, +- -0x4p-16496, false, +- -0x4p-16496, false, +- -0x0p+0, false, +- -0x0p+0, false), ++ -0x8p-152, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x8p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16448, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-1076, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true, ++ false, ++ -0x4p-16496, false, true, ++ -0x4p-16496, false, true, ++ -0x0p+0, false, true, ++ -0x0p+0, false, true), + TEST ("340282366920938463463374607431768211455", + false, +- 0xf.fffffp+124, false, +- INF, true, +- 0xf.fffffp+124, false, +- INF, true, +- false, +- 0xf.ffffffffffff8p+124, false, +- 0x1p+128, false, +- 0xf.ffffffffffff8p+124, false, +- 0x1p+128, false, +- false, +- 0xf.fffffffffffffffp+124, false, +- 0x1p+128, false, +- 0xf.fffffffffffffffp+124, false, +- 0x1p+128, false, +- false, +- 0xf.fffffffffffffffp+124, false, +- 0x1p+128, false, +- 0xf.fffffffffffffffp+124, false, +- 0x1p+128, false, +- false, +- 0xf.fffffffffffffffffffffffffcp+124, false, +- 0x1p+128, false, +- 0xf.fffffffffffffffffffffffffcp+124, false, +- 0x1p+128, false, +- false, +- 0xf.fffffffffffffffffffffffffff8p+124, false, +- 0x1p+128, false, +- 0xf.fffffffffffffffffffffffffff8p+124, false, +- 0x1p+128, false), ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ 0xf.fffffp+124, false, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+124, false, false, ++ 0x1p+128, false, false, ++ 0xf.ffffffffffff8p+124, false, false, ++ 0x1p+128, false, false, ++ false, ++ 0xf.fffffffffffffffp+124, false, false, ++ 0x1p+128, false, false, ++ 0xf.fffffffffffffffp+124, false, false, ++ 0x1p+128, false, false, ++ false, ++ 0xf.fffffffffffffffp+124, false, false, ++ 0x1p+128, false, false, ++ 0xf.fffffffffffffffp+124, false, false, ++ 0x1p+128, false, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+124, false, false, ++ 0x1p+128, false, false, ++ 0xf.fffffffffffffffffffffffffcp+124, false, false, ++ 0x1p+128, false, false, ++ false, ++ 0xf.fffffffffffffffffffffffffff8p+124, false, false, ++ 0x1p+128, false, false, ++ 0xf.fffffffffffffffffffffffffff8p+124, false, false, ++ 0x1p+128, false, false), + TEST ("179769313486231590772930519078902473361797697894230657273430" + "081157732675805500963132708477322407536021120113879871393357" + "658789768814416622492847430639474124377767893424865485276302" +@@ -11619,35 +11619,35 @@ static const struct test tests[] = { + "540827237163350510684586298239947245938479716304835356329624" + "224137215", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- 0xf.ffffffffffff8p+1020, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+1020, false, +- 0x1p+1024, false, +- 0xf.fffffffffffffffp+1020, false, +- 0x1p+1024, false, +- false, +- 0xf.fffffffffffffffp+1020, false, +- 0x1p+1024, false, +- 0xf.fffffffffffffffp+1020, false, +- 0x1p+1024, false, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffff8p+1020, false, +- 0x1p+1024, false, +- 0xf.fffffffffffffffffffffffffff8p+1020, false, +- 0x1p+1024, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+1020, false, false, ++ 0x1p+1024, false, false, ++ 0xf.fffffffffffffffp+1020, false, false, ++ 0x1p+1024, false, false, ++ false, ++ 0xf.fffffffffffffffp+1020, false, false, ++ 0x1p+1024, false, false, ++ 0xf.fffffffffffffffp+1020, false, false, ++ 0x1p+1024, false, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffff8p+1020, false, false, ++ 0x1p+1024, false, false, ++ 0xf.fffffffffffffffffffffffffff8p+1020, false, false, ++ 0x1p+1024, false, false), + TEST ("118973149535723176508575932662800713076344468709651023747267" + "482123326135818048368690448859547261203991511543748483930925" + "889766738130868742627452469834156500608087163436600489752214" +@@ -11732,66 +11732,66 @@ static const struct test tests[] = { + "047398248889922809181821393428829567971736994315246044702729" + "0669964066815", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- 0xf.fffffffffffffffp+16380, false, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true, +- 0xf.fffffffffffffffffffffffffff8p+16380, false, +- INF, true), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffp+16380, false, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ INF, true, false), + TEST ("-340282366920938463463374607431768211455", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, false, +- -0xf.fffffp+124, false, +- false, +- -0x1p+128, false, +- -0x1p+128, false, +- -0xf.ffffffffffff8p+124, false, +- -0xf.ffffffffffff8p+124, false, +- false, +- -0x1p+128, false, +- -0x1p+128, false, +- -0xf.fffffffffffffffp+124, false, +- -0xf.fffffffffffffffp+124, false, +- false, +- -0x1p+128, false, +- -0x1p+128, false, +- -0xf.fffffffffffffffp+124, false, +- -0xf.fffffffffffffffp+124, false, +- false, +- -0x1p+128, false, +- -0x1p+128, false, +- -0xf.fffffffffffffffffffffffffcp+124, false, +- -0xf.fffffffffffffffffffffffffcp+124, false, +- false, +- -0x1p+128, false, +- -0x1p+128, false, +- -0xf.fffffffffffffffffffffffffff8p+124, false, +- -0xf.fffffffffffffffffffffffffff8p+124, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, false, false, ++ -0xf.fffffp+124, false, false, ++ false, ++ -0x1p+128, false, false, ++ -0x1p+128, false, false, ++ -0xf.ffffffffffff8p+124, false, false, ++ -0xf.ffffffffffff8p+124, false, false, ++ false, ++ -0x1p+128, false, false, ++ -0x1p+128, false, false, ++ -0xf.fffffffffffffffp+124, false, false, ++ -0xf.fffffffffffffffp+124, false, false, ++ false, ++ -0x1p+128, false, false, ++ -0x1p+128, false, false, ++ -0xf.fffffffffffffffp+124, false, false, ++ -0xf.fffffffffffffffp+124, false, false, ++ false, ++ -0x1p+128, false, false, ++ -0x1p+128, false, false, ++ -0xf.fffffffffffffffffffffffffcp+124, false, false, ++ -0xf.fffffffffffffffffffffffffcp+124, false, false, ++ false, ++ -0x1p+128, false, false, ++ -0x1p+128, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+124, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+124, false, false), + TEST ("-17976931348623159077293051907890247336179769789423065727343" + "008115773267580550096313270847732240753602112011387987139335" + "765878976881441662249284743063947412437776789342486548527630" +@@ -11799,35 +11799,35 @@ static const struct test tests[] = { + "054082723716335051068458629823994724593847971630483535632962" + "4224137215", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, false, +- -0xf.ffffffffffff8p+1020, false, +- false, +- -0x1p+1024, false, +- -0x1p+1024, false, +- -0xf.fffffffffffffffp+1020, false, +- -0xf.fffffffffffffffp+1020, false, +- false, +- -0x1p+1024, false, +- -0x1p+1024, false, +- -0xf.fffffffffffffffp+1020, false, +- -0xf.fffffffffffffffp+1020, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -0x1p+1024, false, +- -0x1p+1024, false, +- -0xf.fffffffffffffffffffffffffff8p+1020, false, +- -0xf.fffffffffffffffffffffffffff8p+1020, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ -0xf.ffffffffffff8p+1020, false, false, ++ false, ++ -0x1p+1024, false, false, ++ -0x1p+1024, false, false, ++ -0xf.fffffffffffffffp+1020, false, false, ++ -0xf.fffffffffffffffp+1020, false, false, ++ false, ++ -0x1p+1024, false, false, ++ -0x1p+1024, false, false, ++ -0xf.fffffffffffffffp+1020, false, false, ++ -0xf.fffffffffffffffp+1020, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -0x1p+1024, false, false, ++ -0x1p+1024, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+1020, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+1020, false, false), + TEST ("-11897314953572317650857593266280071307634446870965102374726" + "748212332613581804836869044885954726120399151154374848393092" + "588976673813086874262745246983415650060808716343660048975221" +@@ -11912,3529 +11912,3529 @@ static const struct test tests[] = { + "904739824888992280918182139342882956797173699431524604470272" + "90669964066815", + false, +- -INF, true, +- -INF, true, +- -0xf.fffffp+124, true, +- -0xf.fffffp+124, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.ffffffffffff8p+1020, true, +- -0xf.ffffffffffff8p+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffp+16380, false, +- -0xf.fffffffffffffffp+16380, false, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- -0xf.fffffffffffffffffffffffffcp+1020, true, +- false, +- -INF, true, +- -INF, true, +- -0xf.fffffffffffffffffffffffffff8p+16380, false, +- -0xf.fffffffffffffffffffffffffff8p+16380, false), ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffp+124, true, false, ++ -0xf.fffffp+124, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ -0xf.ffffffffffff8p+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ -0xf.fffffffffffffffp+16380, false, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ -0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ false, ++ -INF, true, false, ++ -INF, true, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false, ++ -0xf.fffffffffffffffffffffffffff8p+16380, false, false), + TEST ("+0x.80000000000000000000000000000001p1025", + false, +- 0xf.fffffp+124, true, +- INF, true, +- 0xf.fffffp+124, true, +- INF, true, +- false, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- 0xf.ffffffffffff8p+1020, true, +- INF, true, +- false, +- 0x1p+1024, false, +- 0x1p+1024, false, +- 0x1p+1024, false, +- 0x1.0000000000000002p+1024, false, +- false, +- 0x1p+1024, false, +- 0x1p+1024, false, +- 0x1p+1024, false, +- 0x1.0000000000000002p+1024, false, +- false, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- 0xf.fffffffffffffffffffffffffcp+1020, true, +- INF, true, +- false, +- 0x1p+1024, false, +- 0x1p+1024, false, +- 0x1p+1024, false, +- 0x1.0000000000000000000000000001p+1024, false), ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ 0xf.fffffp+124, true, false, ++ INF, true, false, ++ false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ 0xf.ffffffffffff8p+1020, true, false, ++ INF, true, false, ++ false, ++ 0x1p+1024, false, false, ++ 0x1p+1024, false, false, ++ 0x1p+1024, false, false, ++ 0x1.0000000000000002p+1024, false, false, ++ false, ++ 0x1p+1024, false, false, ++ 0x1p+1024, false, false, ++ 0x1p+1024, false, false, ++ 0x1.0000000000000002p+1024, false, false, ++ false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ 0xf.fffffffffffffffffffffffffcp+1020, true, false, ++ INF, true, false, ++ false, ++ 0x1p+1024, false, false, ++ 0x1p+1024, false, false, ++ 0x1p+1024, false, false, ++ 0x1.0000000000000000000000000001p+1024, false, false), + TEST ("1.5", + true, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- true, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- true, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- true, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- true, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- true, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false, +- 0x1.8p+0, false), ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ true, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ true, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ true, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ true, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ true, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false, ++ 0x1.8p+0, false, false), + TEST ("1.25", + true, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- true, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- true, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- true, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- true, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- true, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false, +- 0x1.4p+0, false), ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ true, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ true, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ true, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ true, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ true, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false, ++ 0x1.4p+0, false, false), + TEST ("1.125", + true, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- true, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- true, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- true, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- true, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- true, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false, +- 0x1.2p+0, false), ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ true, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ true, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ true, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ true, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ true, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false, ++ 0x1.2p+0, false, false), + TEST ("1.0625", + true, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- true, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- true, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- true, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- true, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- true, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false, +- 0x1.1p+0, false), ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ true, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ true, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ true, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ true, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ true, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false, ++ 0x1.1p+0, false, false), + TEST ("1.03125", + true, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- true, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- true, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- true, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- true, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- true, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false, +- 0x1.08p+0, false), ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ true, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ true, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ true, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ true, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ true, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false, ++ 0x1.08p+0, false, false), + TEST ("1.015625", + true, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- true, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- true, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- true, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- true, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- true, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false, +- 0x1.04p+0, false), ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ true, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ true, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ true, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ true, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ true, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false, ++ 0x1.04p+0, false, false), + TEST ("1.0078125", + true, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- true, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- true, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- true, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- true, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- true, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false, +- 0x1.02p+0, false), ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ true, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ true, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ true, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ true, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ true, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false, ++ 0x1.02p+0, false, false), + TEST ("1.00390625", + true, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- true, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- true, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- true, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- true, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- true, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false, +- 0x1.01p+0, false), ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ true, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ true, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ true, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ true, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ true, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false, ++ 0x1.01p+0, false, false), + TEST ("1.001953125", + true, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- true, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- true, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- true, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- true, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- true, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false, +- 0x1.008p+0, false), ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ true, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ true, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ true, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ true, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ true, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false, ++ 0x1.008p+0, false, false), + TEST ("1.0009765625", + true, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- true, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- true, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- true, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- true, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- true, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false, +- 0x1.004p+0, false), ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ true, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ true, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ true, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ true, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ true, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false, ++ 0x1.004p+0, false, false), + TEST ("1.00048828125", + true, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- true, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- true, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- true, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- true, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- true, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false, +- 0x1.002p+0, false), ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ true, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ true, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ true, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ true, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ true, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false, ++ 0x1.002p+0, false, false), + TEST ("1.000244140625", + true, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- true, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- true, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- true, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- true, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- true, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false, +- 0x1.001p+0, false), ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ true, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ true, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ true, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ true, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ true, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false, ++ 0x1.001p+0, false, false), + TEST ("1.0001220703125", + true, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- true, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- true, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- true, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- true, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- true, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false, +- 0x1.0008p+0, false), ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ true, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ true, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ true, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ true, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ true, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false, ++ 0x1.0008p+0, false, false), + TEST ("1.00006103515625", + true, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- true, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- true, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- true, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- true, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- true, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false, +- 0x1.0004p+0, false), ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ true, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ true, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ true, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ true, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ true, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false, ++ 0x1.0004p+0, false, false), + TEST ("1.000030517578125", + true, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- true, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- true, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- true, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- true, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- true, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false, +- 0x1.0002p+0, false), ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ true, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ true, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ true, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ true, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ true, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false, ++ 0x1.0002p+0, false, false), + TEST ("1.0000152587890625", + true, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- true, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- true, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- true, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- true, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- true, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false, +- 0x1.0001p+0, false), ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ true, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ true, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ true, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ true, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ true, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false, ++ 0x1.0001p+0, false, false), + TEST ("1.00000762939453125", + true, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- true, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- true, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- true, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- true, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- true, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false, +- 0x1.00008p+0, false), ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ true, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ true, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ true, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ true, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ true, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false, ++ 0x1.00008p+0, false, false), + TEST ("1.000003814697265625", + true, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- true, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- true, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- true, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- true, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- true, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false, +- 0x1.00004p+0, false), ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ true, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ true, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ true, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ true, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ true, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false, ++ 0x1.00004p+0, false, false), + TEST ("1.0000019073486328125", + true, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- true, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- true, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- true, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- true, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- true, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false, +- 0x1.00002p+0, false), ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ true, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ true, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ true, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ true, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ true, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false, ++ 0x1.00002p+0, false, false), + TEST ("1.00000095367431640625", + true, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- true, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- true, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- true, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- true, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- true, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false, +- 0x1.00001p+0, false), ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ true, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ true, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ true, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ true, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ true, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false, ++ 0x1.00001p+0, false, false), + TEST ("1.000000476837158203125", + true, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- true, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- true, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- true, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- true, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- true, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false, +- 0x1.000008p+0, false), ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ true, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ true, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ true, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ true, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ true, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false, ++ 0x1.000008p+0, false, false), + TEST ("1.0000000298023223876953125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- true, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- true, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- true, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- true, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false, +- 0x1.0000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ true, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ true, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ true, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ true, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false, ++ 0x1.0000008p+0, false, false), + TEST ("1.00000001490116119384765625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- true, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- true, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- true, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- true, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false, +- 0x1.0000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ true, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ true, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ true, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ true, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false, ++ 0x1.0000004p+0, false, false), + TEST ("1.000000007450580596923828125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- true, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- true, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- true, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- true, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false, +- 0x1.0000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ true, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ true, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ true, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ true, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false, ++ 0x1.0000002p+0, false, false), + TEST ("1.0000000037252902984619140625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- true, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- true, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- true, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- true, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false, +- 0x1.0000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ true, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ true, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ true, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ true, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false, ++ 0x1.0000001p+0, false, false), + TEST ("1.00000000186264514923095703125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- true, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- true, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- true, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- true, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false, +- 0x1.00000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ true, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ true, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ true, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ true, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false, ++ 0x1.00000008p+0, false, false), + TEST ("1.000000000931322574615478515625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- true, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- true, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- true, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- true, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false, +- 0x1.00000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ true, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ true, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ true, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ true, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false, ++ 0x1.00000004p+0, false, false), + TEST ("1.0000000004656612873077392578125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- true, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- true, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- true, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- true, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false, +- 0x1.00000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ true, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ true, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ true, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ true, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false, ++ 0x1.00000002p+0, false, false), + TEST ("1.00000000023283064365386962890625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- true, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- true, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- true, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- true, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false, +- 0x1.00000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ true, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ true, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ true, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ true, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false, ++ 0x1.00000001p+0, false, false), + TEST ("1.000000000116415321826934814453125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- true, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- true, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- true, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- true, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false, +- 0x1.000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ true, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ true, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ true, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ true, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false, ++ 0x1.000000008p+0, false, false), + TEST ("1.0000000000582076609134674072265625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- true, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- true, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- true, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- true, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false, +- 0x1.000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ true, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ true, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ true, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ true, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false, ++ 0x1.000000004p+0, false, false), + TEST ("1.00000000002910383045673370361328125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- true, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- true, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- true, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- true, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false, +- 0x1.000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ true, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ true, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ true, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ true, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false, ++ 0x1.000000002p+0, false, false), + TEST ("1.000000000014551915228366851806640625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- true, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- true, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- true, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- true, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false, +- 0x1.000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ true, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ true, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ true, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ true, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false, ++ 0x1.000000001p+0, false, false), + TEST ("1.0000000000072759576141834259033203125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- true, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- true, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- true, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- true, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false, +- 0x1.0000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ true, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ true, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ true, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ true, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false, ++ 0x1.0000000008p+0, false, false), + TEST ("1.00000000000363797880709171295166015625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- true, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- true, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- true, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- true, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false, +- 0x1.0000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ true, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ true, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ true, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ true, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false, ++ 0x1.0000000004p+0, false, false), + TEST ("1.000000000001818989403545856475830078125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- true, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- true, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- true, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- true, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false, +- 0x1.0000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ true, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ true, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ true, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ true, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false, ++ 0x1.0000000002p+0, false, false), + TEST ("1.0000000000009094947017729282379150390625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- true, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- true, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- true, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- true, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false, +- 0x1.0000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ true, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ true, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ true, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ true, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false, ++ 0x1.0000000001p+0, false, false), + TEST ("1.00000000000045474735088646411895751953125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- true, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- true, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- true, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- true, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false, +- 0x1.00000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ true, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ true, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ true, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ true, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false, ++ 0x1.00000000008p+0, false, false), + TEST ("1.000000000000227373675443232059478759765625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- true, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- true, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- true, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- true, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false, +- 0x1.00000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ true, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ true, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ true, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ true, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false, ++ 0x1.00000000004p+0, false, false), + TEST ("1.0000000000001136868377216160297393798828125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- true, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- true, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- true, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- true, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false, +- 0x1.00000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ true, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ true, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ true, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ true, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false, ++ 0x1.00000000002p+0, false, false), + TEST ("1.00000000000005684341886080801486968994140625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- true, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- true, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- true, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- true, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false, +- 0x1.00000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ true, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ true, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ true, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ true, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false, ++ 0x1.00000000001p+0, false, false), + TEST ("1.000000000000028421709430404007434844970703125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- true, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- true, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- true, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- true, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false, +- 0x1.000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ true, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ true, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ true, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ true, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false, ++ 0x1.000000000008p+0, false, false), + TEST ("1.0000000000000142108547152020037174224853515625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- true, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- true, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- true, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- true, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false, +- 0x1.000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ true, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ true, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ true, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ true, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false, ++ 0x1.000000000004p+0, false, false), + TEST ("1.00000000000000710542735760100185871124267578125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- true, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- true, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- true, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- true, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false, +- 0x1.000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ true, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ true, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ true, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ true, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false, ++ 0x1.000000000002p+0, false, false), + TEST ("1.000000000000003552713678800500929355621337890625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- true, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- true, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- true, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- true, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false, +- 0x1.000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ true, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ true, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ true, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ true, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false, ++ 0x1.000000000001p+0, false, false), + TEST ("1.0000000000000017763568394002504646778106689453125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- true, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- true, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- true, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- true, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false, +- 0x1.0000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ true, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ true, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ true, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ true, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false, ++ 0x1.0000000000008p+0, false, false), + TEST ("1.00000000000000088817841970012523233890533447265625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- true, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- true, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- true, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- true, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false, +- 0x1.0000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ true, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ true, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ true, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ true, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false, ++ 0x1.0000000000004p+0, false, false), + TEST ("1.000000000000000444089209850062616169452667236328125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- true, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- true, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- true, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- true, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false, +- 0x1.0000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ true, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ true, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ true, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ true, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false, ++ 0x1.0000000000002p+0, false, false), + TEST ("1.0000000000000002220446049250313080847263336181640625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- true, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false, +- 0x1.0000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ true, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ 0x1.0000000000001p+0, false, false), + TEST ("1.00000000000000011102230246251565404236316680908203125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- true, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- true, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- true, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false, +- 0x1.00000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ true, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ true, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ true, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false, ++ 0x1.00000000000008p+0, false, false), + TEST ("1.000000000000000055511151231257827021181583404541015625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- true, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- true, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- true, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false, +- 0x1.00000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ true, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ true, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ true, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false, ++ 0x1.00000000000004p+0, false, false), + TEST ("1.0000000000000000277555756156289135105907917022705078125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- true, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- true, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- true, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false, +- 0x1.00000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ true, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ true, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ true, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false, ++ 0x1.00000000000002p+0, false, false), + TEST ("1.00000000000000001387778780781445675529539585113525390625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- true, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- true, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- true, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false, +- 0x1.00000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ true, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ true, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ true, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false, ++ 0x1.00000000000001p+0, false, false), + TEST ("1.000000000000000006938893903907228377647697925567626953125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- true, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- true, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- true, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false, +- 0x1.000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false, ++ 0x1.000000000000008p+0, false, false), + TEST ("1.0000000000000000034694469519536141888238489627838134765625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- true, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- true, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- true, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false, +- 0x1.000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ true, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ true, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ true, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false, ++ 0x1.000000000000004p+0, false, false), + TEST ("1.0000000000000000017347234759768070944119244813919067382812" + "5", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- true, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- true, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- true, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false, +- 0x1.000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false, ++ 0x1.000000000000002p+0, false, false), + TEST ("1.0000000000000000008673617379884035472059622406959533691406" + "25", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- true, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- true, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- true, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false, +- 0x1.000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ true, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ true, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ true, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false, ++ 0x1.000000000000001p+0, false, false), + TEST ("1.0000000000000000004336808689942017736029811203479766845703" + "125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- true, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- true, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- true, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false, +- 0x1.0000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false, ++ 0x1.0000000000000008p+0, false, false), + TEST ("1.0000000000000000002168404344971008868014905601739883422851" + "5625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- true, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- true, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- true, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false, +- 0x1.0000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ true, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ true, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ true, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false, ++ 0x1.0000000000000004p+0, false, false), + TEST ("1.0000000000000000001084202172485504434007452800869941711425" + "78125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- true, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false, +- 0x1.0000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ 0x1.0000000000000002p+0, false, false), + TEST ("1.0000000000000000000542101086242752217003726400434970855712" + "890625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000001p+0, false, +- 0x1.0000000000000001p+0, false, +- 0x1.0000000000000001p+0, false, +- 0x1.0000000000000001p+0, false, +- true, +- 0x1.0000000000000001p+0, false, +- 0x1.0000000000000001p+0, false, +- 0x1.0000000000000001p+0, false, +- 0x1.0000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000001p+0, false, false, ++ 0x1.0000000000000001p+0, false, false, ++ 0x1.0000000000000001p+0, false, false, ++ 0x1.0000000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000001p+0, false, false, ++ 0x1.0000000000000001p+0, false, false, ++ 0x1.0000000000000001p+0, false, false, ++ 0x1.0000000000000001p+0, false, false), + TEST ("1.0000000000000000000271050543121376108501863200217485427856" + "4453125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000008p+0, false, +- 0x1.00000000000000008p+0, false, +- 0x1.00000000000000008p+0, false, +- 0x1.00000000000000008p+0, false, +- true, +- 0x1.00000000000000008p+0, false, +- 0x1.00000000000000008p+0, false, +- 0x1.00000000000000008p+0, false, +- 0x1.00000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000008p+0, false, false, ++ 0x1.00000000000000008p+0, false, false, ++ 0x1.00000000000000008p+0, false, false, ++ 0x1.00000000000000008p+0, false, false, ++ true, ++ 0x1.00000000000000008p+0, false, false, ++ 0x1.00000000000000008p+0, false, false, ++ 0x1.00000000000000008p+0, false, false, ++ 0x1.00000000000000008p+0, false, false), + TEST ("1.0000000000000000000135525271560688054250931600108742713928" + "22265625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000004p+0, false, +- 0x1.00000000000000004p+0, false, +- 0x1.00000000000000004p+0, false, +- 0x1.00000000000000004p+0, false, +- true, +- 0x1.00000000000000004p+0, false, +- 0x1.00000000000000004p+0, false, +- 0x1.00000000000000004p+0, false, +- 0x1.00000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000004p+0, false, false, ++ 0x1.00000000000000004p+0, false, false, ++ 0x1.00000000000000004p+0, false, false, ++ 0x1.00000000000000004p+0, false, false, ++ true, ++ 0x1.00000000000000004p+0, false, false, ++ 0x1.00000000000000004p+0, false, false, ++ 0x1.00000000000000004p+0, false, false, ++ 0x1.00000000000000004p+0, false, false), + TEST ("1.0000000000000000000067762635780344027125465800054371356964" + "111328125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000002p+0, false, +- 0x1.00000000000000002p+0, false, +- 0x1.00000000000000002p+0, false, +- 0x1.00000000000000002p+0, false, +- true, +- 0x1.00000000000000002p+0, false, +- 0x1.00000000000000002p+0, false, +- 0x1.00000000000000002p+0, false, +- 0x1.00000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000002p+0, false, false, ++ 0x1.00000000000000002p+0, false, false, ++ 0x1.00000000000000002p+0, false, false, ++ 0x1.00000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000002p+0, false, false, ++ 0x1.00000000000000002p+0, false, false, ++ 0x1.00000000000000002p+0, false, false, ++ 0x1.00000000000000002p+0, false, false), + TEST ("1.0000000000000000000033881317890172013562732900027185678482" + "0556640625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000001p+0, false, +- 0x1.00000000000000001p+0, false, +- 0x1.00000000000000001p+0, false, +- 0x1.00000000000000001p+0, false, +- true, +- 0x1.00000000000000001p+0, false, +- 0x1.00000000000000001p+0, false, +- 0x1.00000000000000001p+0, false, +- 0x1.00000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000001p+0, false, false, ++ 0x1.00000000000000001p+0, false, false, ++ 0x1.00000000000000001p+0, false, false, ++ 0x1.00000000000000001p+0, false, false, ++ true, ++ 0x1.00000000000000001p+0, false, false, ++ 0x1.00000000000000001p+0, false, false, ++ 0x1.00000000000000001p+0, false, false, ++ 0x1.00000000000000001p+0, false, false), + TEST ("1.0000000000000000000016940658945086006781366450013592839241" + "02783203125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000008p+0, false, +- 0x1.000000000000000008p+0, false, +- 0x1.000000000000000008p+0, false, +- 0x1.000000000000000008p+0, false, +- true, +- 0x1.000000000000000008p+0, false, +- 0x1.000000000000000008p+0, false, +- 0x1.000000000000000008p+0, false, +- 0x1.000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000008p+0, false, false, ++ 0x1.000000000000000008p+0, false, false, ++ 0x1.000000000000000008p+0, false, false, ++ 0x1.000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000008p+0, false, false, ++ 0x1.000000000000000008p+0, false, false, ++ 0x1.000000000000000008p+0, false, false, ++ 0x1.000000000000000008p+0, false, false), + TEST ("1.0000000000000000000008470329472543003390683225006796419620" + "513916015625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000004p+0, false, +- 0x1.000000000000000004p+0, false, +- 0x1.000000000000000004p+0, false, +- 0x1.000000000000000004p+0, false, +- true, +- 0x1.000000000000000004p+0, false, +- 0x1.000000000000000004p+0, false, +- 0x1.000000000000000004p+0, false, +- 0x1.000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000004p+0, false, false, ++ 0x1.000000000000000004p+0, false, false, ++ 0x1.000000000000000004p+0, false, false, ++ 0x1.000000000000000004p+0, false, false, ++ true, ++ 0x1.000000000000000004p+0, false, false, ++ 0x1.000000000000000004p+0, false, false, ++ 0x1.000000000000000004p+0, false, false, ++ 0x1.000000000000000004p+0, false, false), + TEST ("1.0000000000000000000004235164736271501695341612503398209810" + "2569580078125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000002p+0, false, +- 0x1.000000000000000002p+0, false, +- 0x1.000000000000000002p+0, false, +- 0x1.000000000000000002p+0, false, +- true, +- 0x1.000000000000000002p+0, false, +- 0x1.000000000000000002p+0, false, +- 0x1.000000000000000002p+0, false, +- 0x1.000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000002p+0, false, false, ++ 0x1.000000000000000002p+0, false, false, ++ 0x1.000000000000000002p+0, false, false, ++ 0x1.000000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000002p+0, false, false, ++ 0x1.000000000000000002p+0, false, false, ++ 0x1.000000000000000002p+0, false, false, ++ 0x1.000000000000000002p+0, false, false), + TEST ("1.0000000000000000000002117582368135750847670806251699104905" + "12847900390625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000001p+0, false, +- 0x1.000000000000000001p+0, false, +- 0x1.000000000000000001p+0, false, +- 0x1.000000000000000001p+0, false, +- true, +- 0x1.000000000000000001p+0, false, +- 0x1.000000000000000001p+0, false, +- 0x1.000000000000000001p+0, false, +- 0x1.000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000001p+0, false, false, ++ 0x1.000000000000000001p+0, false, false, ++ 0x1.000000000000000001p+0, false, false, ++ 0x1.000000000000000001p+0, false, false, ++ true, ++ 0x1.000000000000000001p+0, false, false, ++ 0x1.000000000000000001p+0, false, false, ++ 0x1.000000000000000001p+0, false, false, ++ 0x1.000000000000000001p+0, false, false), + TEST ("1.0000000000000000000001058791184067875423835403125849552452" + "564239501953125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000008p+0, false, +- 0x1.0000000000000000008p+0, false, +- 0x1.0000000000000000008p+0, false, +- 0x1.0000000000000000008p+0, false, +- true, +- 0x1.0000000000000000008p+0, false, +- 0x1.0000000000000000008p+0, false, +- 0x1.0000000000000000008p+0, false, +- 0x1.0000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000008p+0, false, false, ++ 0x1.0000000000000000008p+0, false, false, ++ 0x1.0000000000000000008p+0, false, false, ++ 0x1.0000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000008p+0, false, false, ++ 0x1.0000000000000000008p+0, false, false, ++ 0x1.0000000000000000008p+0, false, false, ++ 0x1.0000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000529395592033937711917701562924776226" + "2821197509765625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000004p+0, false, +- 0x1.0000000000000000004p+0, false, +- 0x1.0000000000000000004p+0, false, +- 0x1.0000000000000000004p+0, false, +- true, +- 0x1.0000000000000000004p+0, false, +- 0x1.0000000000000000004p+0, false, +- 0x1.0000000000000000004p+0, false, +- 0x1.0000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000004p+0, false, false, ++ 0x1.0000000000000000004p+0, false, false, ++ 0x1.0000000000000000004p+0, false, false, ++ 0x1.0000000000000000004p+0, false, false, ++ true, ++ 0x1.0000000000000000004p+0, false, false, ++ 0x1.0000000000000000004p+0, false, false, ++ 0x1.0000000000000000004p+0, false, false, ++ 0x1.0000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000264697796016968855958850781462388113" + "14105987548828125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000002p+0, false, +- 0x1.0000000000000000002p+0, false, +- 0x1.0000000000000000002p+0, false, +- 0x1.0000000000000000002p+0, false, +- true, +- 0x1.0000000000000000002p+0, false, +- 0x1.0000000000000000002p+0, false, +- 0x1.0000000000000000002p+0, false, +- 0x1.0000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000002p+0, false, false, ++ 0x1.0000000000000000002p+0, false, false, ++ 0x1.0000000000000000002p+0, false, false, ++ 0x1.0000000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000002p+0, false, false, ++ 0x1.0000000000000000002p+0, false, false, ++ 0x1.0000000000000000002p+0, false, false, ++ 0x1.0000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000132348898008484427979425390731194056" + "570529937744140625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000001p+0, false, +- 0x1.0000000000000000001p+0, false, +- 0x1.0000000000000000001p+0, false, +- 0x1.0000000000000000001p+0, false, +- true, +- 0x1.0000000000000000001p+0, false, +- 0x1.0000000000000000001p+0, false, +- 0x1.0000000000000000001p+0, false, +- 0x1.0000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000001p+0, false, false, ++ 0x1.0000000000000000001p+0, false, false, ++ 0x1.0000000000000000001p+0, false, false, ++ 0x1.0000000000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000000001p+0, false, false, ++ 0x1.0000000000000000001p+0, false, false, ++ 0x1.0000000000000000001p+0, false, false, ++ 0x1.0000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000066174449004242213989712695365597028" + "2852649688720703125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000008p+0, false, +- 0x1.00000000000000000008p+0, false, +- 0x1.00000000000000000008p+0, false, +- 0x1.00000000000000000008p+0, false, +- true, +- 0x1.00000000000000000008p+0, false, +- 0x1.00000000000000000008p+0, false, +- 0x1.00000000000000000008p+0, false, +- 0x1.00000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000008p+0, false, false, ++ 0x1.00000000000000000008p+0, false, false, ++ 0x1.00000000000000000008p+0, false, false, ++ 0x1.00000000000000000008p+0, false, false, ++ true, ++ 0x1.00000000000000000008p+0, false, false, ++ 0x1.00000000000000000008p+0, false, false, ++ 0x1.00000000000000000008p+0, false, false, ++ 0x1.00000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000033087224502121106994856347682798514" + "14263248443603515625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000004p+0, false, +- 0x1.00000000000000000004p+0, false, +- 0x1.00000000000000000004p+0, false, +- 0x1.00000000000000000004p+0, false, +- true, +- 0x1.00000000000000000004p+0, false, +- 0x1.00000000000000000004p+0, false, +- 0x1.00000000000000000004p+0, false, +- 0x1.00000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000004p+0, false, false, ++ 0x1.00000000000000000004p+0, false, false, ++ 0x1.00000000000000000004p+0, false, false, ++ 0x1.00000000000000000004p+0, false, false, ++ true, ++ 0x1.00000000000000000004p+0, false, false, ++ 0x1.00000000000000000004p+0, false, false, ++ 0x1.00000000000000000004p+0, false, false, ++ 0x1.00000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000016543612251060553497428173841399257" + "071316242218017578125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000002p+0, false, +- 0x1.00000000000000000002p+0, false, +- 0x1.00000000000000000002p+0, false, +- 0x1.00000000000000000002p+0, false, +- true, +- 0x1.00000000000000000002p+0, false, +- 0x1.00000000000000000002p+0, false, +- 0x1.00000000000000000002p+0, false, +- 0x1.00000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000002p+0, false, false, ++ 0x1.00000000000000000002p+0, false, false, ++ 0x1.00000000000000000002p+0, false, false, ++ 0x1.00000000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000002p+0, false, false, ++ 0x1.00000000000000000002p+0, false, false, ++ 0x1.00000000000000000002p+0, false, false, ++ 0x1.00000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000008271806125530276748714086920699628" + "5356581211090087890625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000001p+0, false, +- 0x1.00000000000000000001p+0, false, +- 0x1.00000000000000000001p+0, false, +- 0x1.00000000000000000001p+0, false, +- true, +- 0x1.00000000000000000001p+0, false, +- 0x1.00000000000000000001p+0, false, +- 0x1.00000000000000000001p+0, false, +- 0x1.00000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000001p+0, false, false, ++ 0x1.00000000000000000001p+0, false, false, ++ 0x1.00000000000000000001p+0, false, false, ++ 0x1.00000000000000000001p+0, false, false, ++ true, ++ 0x1.00000000000000000001p+0, false, false, ++ 0x1.00000000000000000001p+0, false, false, ++ 0x1.00000000000000000001p+0, false, false, ++ 0x1.00000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000004135903062765138374357043460349814" + "26782906055450439453125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000008p+0, false, +- 0x1.000000000000000000008p+0, false, +- 0x1.000000000000000000008p+0, false, +- 0x1.000000000000000000008p+0, false, +- true, +- 0x1.000000000000000000008p+0, false, +- 0x1.000000000000000000008p+0, false, +- 0x1.000000000000000000008p+0, false, +- 0x1.000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000008p+0, false, false, ++ 0x1.000000000000000000008p+0, false, false, ++ 0x1.000000000000000000008p+0, false, false, ++ 0x1.000000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000000008p+0, false, false, ++ 0x1.000000000000000000008p+0, false, false, ++ 0x1.000000000000000000008p+0, false, false, ++ 0x1.000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000002067951531382569187178521730174907" + "133914530277252197265625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000004p+0, false, +- 0x1.000000000000000000004p+0, false, +- 0x1.000000000000000000004p+0, false, +- 0x1.000000000000000000004p+0, false, +- true, +- 0x1.000000000000000000004p+0, false, +- 0x1.000000000000000000004p+0, false, +- 0x1.000000000000000000004p+0, false, +- 0x1.000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000004p+0, false, false, ++ 0x1.000000000000000000004p+0, false, false, ++ 0x1.000000000000000000004p+0, false, false, ++ 0x1.000000000000000000004p+0, false, false, ++ true, ++ 0x1.000000000000000000004p+0, false, false, ++ 0x1.000000000000000000004p+0, false, false, ++ 0x1.000000000000000000004p+0, false, false, ++ 0x1.000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000001033975765691284593589260865087453" + "5669572651386260986328125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000002p+0, false, +- 0x1.000000000000000000002p+0, false, +- 0x1.000000000000000000002p+0, false, +- 0x1.000000000000000000002p+0, false, +- true, +- 0x1.000000000000000000002p+0, false, +- 0x1.000000000000000000002p+0, false, +- 0x1.000000000000000000002p+0, false, +- 0x1.000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000002p+0, false, false, ++ 0x1.000000000000000000002p+0, false, false, ++ 0x1.000000000000000000002p+0, false, false, ++ 0x1.000000000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000002p+0, false, false, ++ 0x1.000000000000000000002p+0, false, false, ++ 0x1.000000000000000000002p+0, false, false, ++ 0x1.000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000516987882845642296794630432543726" + "78347863256931304931640625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000001p+0, false, +- 0x1.000000000000000000001p+0, false, +- 0x1.000000000000000000001p+0, false, +- 0x1.000000000000000000001p+0, false, +- true, +- 0x1.000000000000000000001p+0, false, +- 0x1.000000000000000000001p+0, false, +- 0x1.000000000000000000001p+0, false, +- 0x1.000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000001p+0, false, false, ++ 0x1.000000000000000000001p+0, false, false, ++ 0x1.000000000000000000001p+0, false, false, ++ 0x1.000000000000000000001p+0, false, false, ++ true, ++ 0x1.000000000000000000001p+0, false, false, ++ 0x1.000000000000000000001p+0, false, false, ++ 0x1.000000000000000000001p+0, false, false, ++ 0x1.000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000258493941422821148397315216271863" + "391739316284656524658203125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000008p+0, false, +- 0x1.0000000000000000000008p+0, false, +- 0x1.0000000000000000000008p+0, false, +- 0x1.0000000000000000000008p+0, false, +- true, +- 0x1.0000000000000000000008p+0, false, +- 0x1.0000000000000000000008p+0, false, +- 0x1.0000000000000000000008p+0, false, +- 0x1.0000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000129246970711410574198657608135931" + "6958696581423282623291015625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000004p+0, false, +- 0x1.0000000000000000000004p+0, false, +- 0x1.0000000000000000000004p+0, false, +- 0x1.0000000000000000000004p+0, false, +- true, +- 0x1.0000000000000000000004p+0, false, +- 0x1.0000000000000000000004p+0, false, +- 0x1.0000000000000000000004p+0, false, +- 0x1.0000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000004p+0, false, false, ++ true, ++ 0x1.0000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000064623485355705287099328804067965" + "84793482907116413116455078125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000002p+0, false, +- 0x1.0000000000000000000002p+0, false, +- 0x1.0000000000000000000002p+0, false, +- 0x1.0000000000000000000002p+0, false, +- true, +- 0x1.0000000000000000000002p+0, false, +- 0x1.0000000000000000000002p+0, false, +- 0x1.0000000000000000000002p+0, false, +- 0x1.0000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000032311742677852643549664402033982" + "923967414535582065582275390625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000001p+0, false, +- 0x1.0000000000000000000001p+0, false, +- 0x1.0000000000000000000001p+0, false, +- 0x1.0000000000000000000001p+0, false, +- true, +- 0x1.0000000000000000000001p+0, false, +- 0x1.0000000000000000000001p+0, false, +- 0x1.0000000000000000000001p+0, false, +- 0x1.0000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000016155871338926321774832201016991" + "4619837072677910327911376953125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000008p+0, false, +- 0x1.00000000000000000000008p+0, false, +- 0x1.00000000000000000000008p+0, false, +- 0x1.00000000000000000000008p+0, false, +- true, +- 0x1.00000000000000000000008p+0, false, +- 0x1.00000000000000000000008p+0, false, +- 0x1.00000000000000000000008p+0, false, +- 0x1.00000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000008p+0, false, false, ++ true, ++ 0x1.00000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000008077935669463160887416100508495" + "73099185363389551639556884765625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000004p+0, false, +- 0x1.00000000000000000000004p+0, false, +- 0x1.00000000000000000000004p+0, false, +- 0x1.00000000000000000000004p+0, false, +- true, +- 0x1.00000000000000000000004p+0, false, +- 0x1.00000000000000000000004p+0, false, +- 0x1.00000000000000000000004p+0, false, +- 0x1.00000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000004p+0, false, false, ++ true, ++ 0x1.00000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000004038967834731580443708050254247" + "865495926816947758197784423828125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000002p+0, false, +- 0x1.00000000000000000000002p+0, false, +- 0x1.00000000000000000000002p+0, false, +- 0x1.00000000000000000000002p+0, false, +- true, +- 0x1.00000000000000000000002p+0, false, +- 0x1.00000000000000000000002p+0, false, +- 0x1.00000000000000000000002p+0, false, +- 0x1.00000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000002019483917365790221854025127123" + "9327479634084738790988922119140625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000001p+0, false, +- 0x1.00000000000000000000001p+0, false, +- 0x1.00000000000000000000001p+0, false, +- 0x1.00000000000000000000001p+0, false, +- true, +- 0x1.00000000000000000000001p+0, false, +- 0x1.00000000000000000000001p+0, false, +- 0x1.00000000000000000000001p+0, false, +- 0x1.00000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000001p+0, false, false, ++ true, ++ 0x1.00000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000001009741958682895110927012563561" + "96637398170423693954944610595703125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000000008p+0, false, +- 0x1.000000000000000000000008p+0, false, +- 0x1.000000000000000000000008p+0, false, +- 0x1.000000000000000000000008p+0, false, +- true, +- 0x1.000000000000000000000008p+0, false, +- 0x1.000000000000000000000008p+0, false, +- 0x1.000000000000000000000008p+0, false, +- 0x1.000000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000000504870979341447555463506281780" + "983186990852118469774723052978515625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000000004p+0, false, +- 0x1.000000000000000000000004p+0, false, +- 0x1.000000000000000000000004p+0, false, +- 0x1.000000000000000000000004p+0, false, +- true, +- 0x1.000000000000000000000004p+0, false, +- 0x1.000000000000000000000004p+0, false, +- 0x1.000000000000000000000004p+0, false, +- 0x1.000000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000004p+0, false, false, ++ true, ++ 0x1.000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000000252435489670723777731753140890" + "4915934954260592348873615264892578125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000000002p+0, false, +- 0x1.000000000000000000000002p+0, false, +- 0x1.000000000000000000000002p+0, false, +- 0x1.000000000000000000000002p+0, false, +- true, +- 0x1.000000000000000000000002p+0, false, +- 0x1.000000000000000000000002p+0, false, +- 0x1.000000000000000000000002p+0, false, +- 0x1.000000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000000126217744835361888865876570445" + "24579674771302961744368076324462890625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000000001p+0, false, +- 0x1.000000000000000000000001p+0, false, +- 0x1.000000000000000000000001p+0, false, +- 0x1.000000000000000000000001p+0, false, +- true, +- 0x1.000000000000000000000001p+0, false, +- 0x1.000000000000000000000001p+0, false, +- 0x1.000000000000000000000001p+0, false, +- 0x1.000000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000001p+0, false, false, ++ true, ++ 0x1.000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000000063108872417680944432938285222" + "622898373856514808721840381622314453125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000000008p+0, false, +- 0x1.0000000000000000000000008p+0, false, +- 0x1.0000000000000000000000008p+0, false, +- 0x1.0000000000000000000000008p+0, false, +- true, +- 0x1.0000000000000000000000008p+0, false, +- 0x1.0000000000000000000000008p+0, false, +- 0x1.0000000000000000000000008p+0, false, +- 0x1.0000000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000000031554436208840472216469142611" + "3114491869282574043609201908111572265625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000000004p+0, false, +- 0x1.0000000000000000000000004p+0, false, +- 0x1.0000000000000000000000004p+0, false, +- 0x1.0000000000000000000000004p+0, false, +- true, +- 0x1.0000000000000000000000004p+0, false, +- 0x1.0000000000000000000000004p+0, false, +- 0x1.0000000000000000000000004p+0, false, +- 0x1.0000000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000004p+0, false, false, ++ true, ++ 0x1.0000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000000015777218104420236108234571305" + "65572459346412870218046009540557861328125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000000002p+0, false, +- 0x1.0000000000000000000000002p+0, false, +- 0x1.0000000000000000000000002p+0, false, +- 0x1.0000000000000000000000002p+0, false, +- true, +- 0x1.0000000000000000000000002p+0, false, +- 0x1.0000000000000000000000002p+0, false, +- 0x1.0000000000000000000000002p+0, false, +- 0x1.0000000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000000007888609052210118054117285652" + "827862296732064351090230047702789306640625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.0000000000000000000000001p+0, false, +- 0x1.0000000000000000000000001p+0, false, +- 0x1.0000000000000000000000001p+0, false, +- 0x1.0000000000000000000000001p+0, false, +- true, +- 0x1.0000000000000000000000001p+0, false, +- 0x1.0000000000000000000000001p+0, false, +- 0x1.0000000000000000000000001p+0, false, +- 0x1.0000000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.0000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000001p+0, false, false, ++ true, ++ 0x1.0000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000000003944304526105059027058642826" + "4139311483660321755451150238513946533203125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000000008p+0, false, +- 0x1.00000000000000000000000008p+0, false, +- 0x1.00000000000000000000000008p+0, false, +- 0x1.00000000000000000000000008p+0, false, +- true, +- 0x1.00000000000000000000000008p+0, false, +- 0x1.00000000000000000000000008p+0, false, +- 0x1.00000000000000000000000008p+0, false, +- 0x1.00000000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000000008p+0, false, false, ++ true, ++ 0x1.00000000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000000008p+0, false, false, ++ 0x1.00000000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000000001972152263052529513529321413" + "20696557418301608777255751192569732666015625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000000004p+0, false, +- 0x1.00000000000000000000000004p+0, false, +- 0x1.00000000000000000000000004p+0, false, +- 0x1.00000000000000000000000004p+0, false, +- true, +- 0x1.00000000000000000000000004p+0, false, +- 0x1.00000000000000000000000004p+0, false, +- 0x1.00000000000000000000000004p+0, false, +- 0x1.00000000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000000004p+0, false, false, ++ true, ++ 0x1.00000000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000000004p+0, false, false, ++ 0x1.00000000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000000000986076131526264756764660706" + "603482787091508043886278755962848663330078125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000000002p+0, false, +- 0x1.00000000000000000000000002p+0, false, +- 0x1.00000000000000000000000002p+0, false, +- 0x1.00000000000000000000000002p+0, false, +- true, +- 0x1.00000000000000000000000002p+0, false, +- 0x1.00000000000000000000000002p+0, false, +- 0x1.00000000000000000000000002p+0, false, +- 0x1.00000000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000000002p+0, false, false, ++ 0x1.00000000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000000000493038065763132378382330353" + "3017413935457540219431393779814243316650390625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.00000000000000000000000001p+0, false, +- 0x1.00000000000000000000000001p+0, false, +- 0x1.00000000000000000000000001p+0, false, +- 0x1.00000000000000000000000001p+0, false, +- true, +- 0x1.00000000000000000000000001p+0, false, +- 0x1.00000000000000000000000001p+0, false, +- 0x1.00000000000000000000000001p+0, false, +- 0x1.00000000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.00000000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000000001p+0, false, false, ++ true, ++ 0x1.00000000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000000001p+0, false, false, ++ 0x1.00000000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000000000246519032881566189191165176" + "65087069677287701097156968899071216583251953125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- true, +- 0x1.000000000000000000000000008p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.000000000000000000000000008p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- 0x1.000000000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ true, ++ 0x1.000000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000000000123259516440783094595582588" + "325435348386438505485784844495356082916259765625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.000000000000000000000000004p+0, false, +- 0x1.000000000000000000000000004p+0, false, +- 0x1.000000000000000000000000004p+0, false, +- 0x1.000000000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000000004p+0, false, false, ++ 0x1.000000000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000000000061629758220391547297791294" + "1627176741932192527428924222476780414581298828125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.000000000000000000000000002p+0, false, +- 0x1.000000000000000000000000002p+0, false, +- 0x1.000000000000000000000000002p+0, false, +- 0x1.000000000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000000002p+0, false, false, ++ 0x1.000000000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000000000030814879110195773648895647" + "08135883709660962637144621112383902072906494140625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.000000000000000000000000001p+0, false, +- 0x1.000000000000000000000000001p+0, false, +- 0x1.000000000000000000000000001p+0, false, +- 0x1.000000000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.000000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000000001p+0, false, false, ++ 0x1.000000000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000000000015407439555097886824447823" + "540679418548304813185723105561919510364532470703125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.0000000000000000000000000008p+0, false, +- 0x1.0000000000000000000000000008p+0, false, +- 0x1.0000000000000000000000000008p+0, false, +- 0x1.0000000000000000000000000008p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000000008p+0, false, false, ++ 0x1.0000000000000000000000000008p+0, false, false), + TEST ("1.0000000000000000000000000000000007703719777548943412223911" + "7703397092741524065928615527809597551822662353515625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.0000000000000000000000000004p+0, false, +- 0x1.0000000000000000000000000004p+0, false, +- 0x1.0000000000000000000000000004p+0, false, +- 0x1.0000000000000000000000000004p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000000004p+0, false, false, ++ 0x1.0000000000000000000000000004p+0, false, false), + TEST ("1.0000000000000000000000000000000003851859888774471706111955" + "88516985463707620329643077639047987759113311767578125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.0000000000000000000000000002p+0, false, +- 0x1.0000000000000000000000000002p+0, false, +- 0x1.0000000000000000000000000002p+0, false, +- 0x1.0000000000000000000000000002p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000000002p+0, false, false, ++ 0x1.0000000000000000000000000002p+0, false, false), + TEST ("1.0000000000000000000000000000000001925929944387235853055977" + "942584927318538101648215388195239938795566558837890625", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- true, +- 0x1.0000000000000000000000000001p+0, false, +- 0x1.0000000000000000000000000001p+0, false, +- 0x1.0000000000000000000000000001p+0, false, +- 0x1.0000000000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ true, ++ 0x1.0000000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000000001p+0, false, false, ++ 0x1.0000000000000000000000000001p+0, false, false), + TEST ("1.0000000000000000000000000000000000962964972193617926527988" + "9712924636592690508241076940976199693977832794189453125", + false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000001p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000002p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.000000000000000000000000008p+0, false, +- false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1p+0, false, +- 0x1.0000000000000000000000000001p+0, false), ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000001p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000002p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.000000000000000000000000008p+0, false, false, ++ false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1p+0, false, false, ++ 0x1.0000000000000000000000000001p+0, false, false), + }; +diff --git a/stdlib/tst-strtod-round-skeleton.c b/stdlib/tst-strtod-round-skeleton.c +index 1ff1977112bda7a8..7b8bc55c254219ed 100644 +--- a/stdlib/tst-strtod-round-skeleton.c ++++ b/stdlib/tst-strtod-round-skeleton.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include "tst-strtod.h" + +@@ -139,16 +140,26 @@ + gen-tst-strtod-round utility to select the appropriately + rounded long double value for a given format. */ + #define TEST(s, \ +- fx, fd, fdo, fn, fno, fz, fzo, fu, fuo, \ +- dx, dd, ddo, dn, dno, dz, dzo, du, duo, \ +- ld64ix, ld64id, ld64ido, ld64in, ld64ino, \ +- ld64iz, ld64izo, ld64iu, ld64iuo, \ +- ld64mx, ld64md, ld64mdo, ld64mn, ld64mno, \ +- ld64mz, ld64mzo, ld64mu, ld64muo, \ +- ld106x, ld106d, ld106do, ld106n, ld106no, \ +- ld106z, ld106zo, ld106u, ld106uo, \ +- ld113x, ld113d, ld113do, ld113n, ld113no, \ +- ld113z, ld113zo, ld113u, ld113uo) \ ++ fx, fd, fdo, fdu, fn, fno, fnu, \ ++ fz, fzo, fzu, fu, fuo, fuu, \ ++ dx, dd, ddo, ddu, dn, dno, dnu, \ ++ dz, dzo, dzu, du, duo, duu, \ ++ ld64ix, ld64id, ld64ido, ld64idu, \ ++ ld64in, ld64ino, ld64inu, \ ++ ld64iz, ld64izo, ld64izu, \ ++ ld64iu, ld64iuo, ld64iuu, \ ++ ld64mx, ld64md, ld64mdo, ld64mdu, \ ++ ld64mn, ld64mno, ld64mnu, \ ++ ld64mz, ld64mzo, ld64mzu, \ ++ ld64mu, ld64muo, ld64muu, \ ++ ld106x, ld106d, ld106do, ld106du, \ ++ ld106n, ld106no, ld106nu, \ ++ ld106z, ld106zo, ld106zu, \ ++ ld106u, ld106uo, ld106uu, \ ++ ld113x, ld113d, ld113do, ld113du, \ ++ ld113n, ld113no, ld113nu, \ ++ ld113z, ld113zo, ld113zu, \ ++ ld113u, ld113uo, ld113uu) \ + { \ + L_ (s), \ + { XNTRY (fx, dx, ld64ix, ld64mx, ld106x, ld113x) }, \ +@@ -163,6 +174,12 @@ + { XNTRY (fdo, ddo, ld64ido, ld64mdo, ld106do, ld113do) }, \ + { XNTRY (fzo, dzo, ld64izo, ld64mzo, ld106zo, ld113zo) }, \ + { XNTRY (fuo, duo, ld64iuo, ld64muo, ld106uo, ld113uo) } \ ++ }, \ ++ { \ ++ { XNTRY (fnu, dnu, ld64inu, ld64mnu, ld106nu, ld113nu) }, \ ++ { XNTRY (fdu, ddu, ld64idu, ld64mdu, ld106du, ld113du) }, \ ++ { XNTRY (fzu, dzu, ld64izu, ld64mzu, ld106zu, ld113zu) }, \ ++ { XNTRY (fuu, duu, ld64iuu, ld64muu, ld106uu, ld113uu) } \ + } \ + } + +@@ -181,11 +198,17 @@ struct test_overflow + STRUCT_FOREACH_FLOAT_BOOL + }; + ++struct test_underflow ++ { ++ STRUCT_FOREACH_FLOAT_BOOL ++ }; ++ + struct test { + const CHAR *s; + struct test_exactness exact; + struct test_results r[4]; + struct test_overflow o[4]; ++ struct test_underflow u[4]; + }; + + /* Include the generated test data. */ +@@ -203,10 +226,14 @@ struct test { + # define FE_OVERFLOW 0 + #endif + ++#ifndef FE_UNDERFLOW ++# define FE_UNDERFLOW 0 ++#endif ++ + #define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \ + { \ + feclearexcept (FE_ALL_EXCEPT); \ +- errno = 0; \ ++ errno = 12345; \ + FTYPE f = STRTO (FSUF) (s, NULL); \ + int new_errno = errno; \ + if (f != expected->FSUF \ +@@ -265,6 +292,40 @@ struct test { + s, new_errno, ERANGE); \ + result = 1; \ + } \ ++ if (FE_UNDERFLOW != 0) \ ++ { \ ++ bool underflow_raised \ ++ = fetestexcept (FE_UNDERFLOW) != 0; \ ++ if (underflow_raised != underflow->FSUF) \ ++ { \ ++ printf (FNPFXS "to" #FSUF \ ++ " (" STRM ") underflow %d " \ ++ "not %d\n", s, underflow_raised, \ ++ underflow->FSUF); \ ++ if (EXCEPTION_TESTS (FTYPE)) \ ++ result = 1; \ ++ else \ ++ printf ("ignoring this exception error\n"); \ ++ } \ ++ } \ ++ if (underflow->FSUF && new_errno != ERANGE) \ ++ { \ ++ printf (FNPFXS "to" #FSUF \ ++ " (" STRM ") left errno == %d," \ ++ " not %d (ERANGE)\n", \ ++ s, new_errno, ERANGE); \ ++ result = 1; \ ++ } \ ++ if (!overflow->FSUF \ ++ && !underflow->FSUF \ ++ && new_errno != 12345) \ ++ { \ ++ printf (FNPFXS "to" #FSUF \ ++ " (" STRM ") set errno == %d," \ ++ " should be unchanged\n", \ ++ s, new_errno); \ ++ result = 1; \ ++ } \ + } \ + } + +@@ -272,6 +333,7 @@ static int + test_in_one_mode (const CHAR *s, const struct test_results *expected, + const struct test_exactness *exact, + const struct test_overflow *overflow, ++ const struct test_underflow *underflow, + const char *mode_name, int rnd_mode) + { + int result = 0; +@@ -307,6 +369,7 @@ do_test (void) + { + result |= test_in_one_mode (tests[i].s, &tests[i].r[modes[0].rnd_i], + &tests[i].exact, &tests[i].o[modes[0].rnd_i], ++ &tests[i].u[modes[0].rnd_i], + modes[0].mode_name, modes[0].rnd_mode); + for (const struct fetestmodes *m = &modes[1]; m->mode_name != NULL; m++) + { +@@ -314,7 +377,9 @@ do_test (void) + { + result |= test_in_one_mode (tests[i].s, &tests[i].r[m->rnd_i], + &tests[i].exact, +- &tests[i].o[m->rnd_i], m->mode_name, ++ &tests[i].o[m->rnd_i], ++ &tests[i].u[m->rnd_i], ++ m->mode_name, + m->rnd_mode); + fesetround (save_round_mode); + } diff --git a/SOURCES/glibc-RHEL-46739-3.patch b/SOURCES/glibc-RHEL-46739-3.patch new file mode 100644 index 0000000..ef8c2ed --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-3.patch @@ -0,0 +1,445 @@ +commit 457622c2fa8f9f7435822d5287a437bc8be8090d +Author: Joseph Myers +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), + }; diff --git a/SOURCES/glibc-RHEL-46739-4.patch b/SOURCES/glibc-RHEL-46739-4.patch new file mode 100644 index 0000000..2d5fa5c --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-4.patch @@ -0,0 +1,598 @@ +commit 3fc063dee01da4f80920a14b7db637c8501d6fd4 +Author: Joseph Myers +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 + #include + +-/* 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 +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 + #include + +-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 + #include + ++#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 + . */ + ++/* Defining _LIBC_TEST ensures long double math functions are ++ declared in the headers. */ ++#define _LIBC_TEST 1 + #include + #include + #include + #include + #include + ++#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 diff --git a/SOURCES/glibc-RHEL-46739-5.patch b/SOURCES/glibc-RHEL-46739-5.patch new file mode 100644 index 0000000..2d193e8 --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-5.patch @@ -0,0 +1,140 @@ +commit be77d5ae417236883c02d3d67c0716e3f669fa41 +Author: Joseph Myers +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 + . */ + ++#define _LIBC_TEST 1 ++#define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include + #include + #include +@@ -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; + } + diff --git a/SOURCES/glibc-RHEL-46739-6.patch b/SOURCES/glibc-RHEL-46739-6.patch new file mode 100644 index 0000000..83514c8 --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-6.patch @@ -0,0 +1,147 @@ +commit 64f62c47e9c350f353336f2df6714e1d48ec50d8 +Author: Joseph Myers +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 + #include + #include + #include +@@ -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 + . */ + ++#include + #include + #include + #include +@@ -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); + diff --git a/SOURCES/glibc-RHEL-46739-7.patch b/SOURCES/glibc-RHEL-46739-7.patch new file mode 100644 index 0000000..a42b32e --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-7.patch @@ -0,0 +1,76 @@ +commit cc3e743fc09ee6fca45767629df9cbcbe1feba82 +Author: Florian Weimer +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 + Reviewed-by: Carlos O'Donell + +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) diff --git a/SOURCES/glibc-RHEL-46739-8.patch b/SOURCES/glibc-RHEL-46739-8.patch new file mode 100644 index 0000000..4f89bfa --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-8.patch @@ -0,0 +1,254 @@ +commit 8de031bcb9adfa736c0caed2c79d10947b8d8f48 +Author: Joseph Myers +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 + #include + +-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 + #include + ++#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 diff --git a/SOURCES/glibc-RHEL-46739-9.patch b/SOURCES/glibc-RHEL-46739-9.patch new file mode 100644 index 0000000..ec6cb19 --- /dev/null +++ b/SOURCES/glibc-RHEL-46739-9.patch @@ -0,0 +1,79 @@ +commit b5d3737b305525315e0c7c93ca49eadc868eabd5 +Author: Joseph Myers +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 + #include + #include + +@@ -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); \ diff --git a/SOURCES/glibc-RHEL-46740.patch b/SOURCES/glibc-RHEL-46740.patch new file mode 100644 index 0000000..af9daae --- /dev/null +++ b/SOURCES/glibc-RHEL-46740.patch @@ -0,0 +1,58 @@ +commit dcad78507433a9a64b8b548b19e110933f8d939a +Author: DJ Delorie +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 diff --git a/SOURCES/glibc-RHEL-46761-1.patch b/SOURCES/glibc-RHEL-46761-1.patch new file mode 100644 index 0000000..b9ad9a0 --- /dev/null +++ b/SOURCES/glibc-RHEL-46761-1.patch @@ -0,0 +1,76 @@ +commit ca6466e8be32369a658035d69542d47603e58a99 +Author: Andreas Schwab +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46761-2.patch b/SOURCES/glibc-RHEL-46761-2.patch new file mode 100644 index 0000000..4fc62b2 --- /dev/null +++ b/SOURCES/glibc-RHEL-46761-2.patch @@ -0,0 +1,183 @@ +Backport of the test case from this commit: + +commit 0d50f477f47ba637b54fb03ac48d769ec4543e8d +Author: Florian Weimer +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 + Tested-by: Carlos O'Donell + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 diff --git a/SOURCES/glibc-RHEL-46761-3.patch b/SOURCES/glibc-RHEL-46761-3.patch new file mode 100644 index 0000000..2766eb6 --- /dev/null +++ b/SOURCES/glibc-RHEL-46761-3.patch @@ -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 +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 + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46761-4.patch b/SOURCES/glibc-RHEL-46761-4.patch new file mode 100644 index 0000000..7c0e958 --- /dev/null +++ b/SOURCES/glibc-RHEL-46761-4.patch @@ -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; + } diff --git a/SOURCES/glibc-RHEL-46761-5.patch b/SOURCES/glibc-RHEL-46761-5.patch new file mode 100644 index 0000000..31ff3f3 --- /dev/null +++ b/SOURCES/glibc-RHEL-46761-5.patch @@ -0,0 +1,120 @@ +commit be7a5468d4f694ee8d052b537141f51af43ca7f2 +Author: Adhemerval Zanella +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 + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-46761-6.patch b/SOURCES/glibc-RHEL-46761-6.patch new file mode 100644 index 0000000..9c72669 --- /dev/null +++ b/SOURCES/glibc-RHEL-46761-6.patch @@ -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 +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-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 diff --git a/SOURCES/glibc-RHEL-46979-1.patch b/SOURCES/glibc-RHEL-46979-1.patch new file mode 100644 index 0000000..2430880 --- /dev/null +++ b/SOURCES/glibc-RHEL-46979-1.patch @@ -0,0 +1,83 @@ +From a65ff76c9a1811dd2396ab45563f645579c0e687 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 27 Oct 2022 11:36:44 +0200 +Subject: ld.so: Export tls_init_tp_called as __rtld_tls_init_tp_called + +This allows the rest of dynamic loader to check whether the TCB +has been set up (and THREAD_GETMEM and THREAD_SETMEM will work). + +Reviewed-by: Siddhesh Poyarekar + +Conflicts: + Regenerated for context changes. + +diff -rup a/elf/rtld.c b/elf/rtld.c +--- a/elf/rtld.c 2024-08-22 17:57:02.000830481 -0400 ++++ b/elf/rtld.c 2024-08-22 17:59:30.666562835 -0400 +@@ -740,7 +740,7 @@ match_version (const char *string, struc + return 0; + } + +-static bool tls_init_tp_called; ++bool __rtld_tls_init_tp_called; + + static void * + init_tls (size_t naudit) +@@ -812,7 +812,7 @@ cannot allocate TLS data structures for + if (__glibc_unlikely (lossage != NULL)) + _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage); + __tls_init_tp (); +- tls_init_tp_called = true; ++ __rtld_tls_init_tp_called = true; + + return tcbp; + } +@@ -2057,7 +2057,7 @@ dl_main (const ElfW(Phdr) *phdr, + an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever + used. Trying to do it lazily is too hairy to try when there could be + multiple threads (from a non-TLS-using libpthread). */ +- bool was_tls_init_tp_called = tls_init_tp_called; ++ bool was_tls_init_tp_called = __rtld_tls_init_tp_called; + if (tcbp == NULL) + tcbp = init_tls (0); + +@@ -2411,7 +2411,7 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_protect_relro (l); + + /* Add object to slot information data if necessasy. */ +- if (l->l_tls_blocksize != 0 && tls_init_tp_called) ++ if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called) + _dl_add_to_slotinfo (l, true); + } + } +@@ -2462,7 +2462,7 @@ dl_main (const ElfW(Phdr) *phdr, + consider_profiling); + + /* Add object to slot information data if necessasy. */ +- if (l->l_tls_blocksize != 0 && tls_init_tp_called) ++ if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called) + _dl_add_to_slotinfo (l, true); + } + rtld_timer_stop (&relocate_time, start); +@@ -2488,7 +2488,7 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_allocate_tls_init (tcbp, true); + + /* And finally install it for the main thread. */ +- if (! tls_init_tp_called) ++ if (! __rtld_tls_init_tp_called) + { + const char *lossage = TLS_INIT_TP (tcbp); + if (__glibc_unlikely (lossage != NULL)) +diff -rup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +--- a/sysdeps/generic/ldsodefs.h 2024-08-22 17:57:02.011830906 -0400 ++++ b/sysdeps/generic/ldsodefs.h 2024-08-22 17:58:10.900487160 -0400 +@@ -1262,6 +1262,9 @@ extern void *_dl_allocate_tls_storage (v + extern void *_dl_allocate_tls_init (void *result, bool main_thread); + rtld_hidden_proto (_dl_allocate_tls_init) + ++/* True if the TCB has been set up. */ ++extern bool __rtld_tls_init_tp_called attribute_hidden; ++ + /* Deallocate memory allocated with _dl_allocate_tls. */ + extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb); + rtld_hidden_proto (_dl_deallocate_tls) diff --git a/SOURCES/glibc-RHEL-46979-2.patch b/SOURCES/glibc-RHEL-46979-2.patch new file mode 100644 index 0000000..0671c4f --- /dev/null +++ b/SOURCES/glibc-RHEL-46979-2.patch @@ -0,0 +1,1030 @@ +From ee1ada1bdb8074de6e1bdc956ab19aef7b6a7872 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 3 Nov 2022 09:39:31 +0100 +Subject: elf: Rework exception handling in the dynamic loader [BZ #25486] + +The old exception handling implementation used function interposition +to replace the dynamic loader implementation (no TLS support) with the +libc implementation (TLS support). This results in problems if the +link order between the dynamic loader and libc is reversed (bug 25486). + +The new implementation moves the entire implementation of the +exception handling functions back into the dynamic loader, using +THREAD_GETMEM and THREAD_SETMEM for thread-local data support. +These depends on Hurd support for these macros, added in commit +b65a82e4e757c1e6cb7073916 ("hurd: Add THREAD_GET/SETMEM/_NC"). + +One small obstacle is that the exception handling facilities are used +before the TCB has been set up, so a check is needed if the TCB is +available. If not, a regular global variable is used to store the +exception handling information. + +Also rename dl-error.c to dl-catch.c, to avoid confusion with the +dlerror function. + +Reviewed-by: Siddhesh Poyarekar + +Conflicts + Rebased due to context changes + +diff -rupN a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2024-08-29 11:28:38.488322915 -0400 ++++ b/elf/Makefile 2024-08-29 11:29:16.773809945 -0400 +@@ -34,7 +34,6 @@ routines = \ + dl-addr \ + dl-addr-obj \ + dl-early_allocate \ +- dl-error \ + dl-iteratephdr \ + dl-libc \ + dl-origin \ +@@ -52,6 +51,7 @@ routines = \ + # profiled libraries. + dl-routines = \ + dl-call-libc-early-init \ ++ dl-catch \ + dl-close \ + dl-debug \ + dl-deps \ +@@ -127,7 +127,6 @@ rtld-routines = \ + dl-diagnostics-cpu \ + dl-diagnostics-kernel \ + dl-environ \ +- dl-error-minimal \ + dl-hwcaps \ + dl-hwcaps-subdirs \ + dl-hwcaps_split \ +diff -rupN a/elf/Versions b/elf/Versions +--- a/elf/Versions 2024-08-29 11:28:36.214234588 -0400 ++++ b/elf/Versions 2024-08-29 11:29:16.778810139 -0400 +@@ -23,10 +23,6 @@ libc { + GLIBC_PRIVATE { + # functions used in other libraries + __libc_early_init; +- +- # Internal error handling support. Interposes the functions in ld.so. +- _dl_signal_exception; _dl_catch_exception; +- _dl_signal_error; _dl_catch_error; + } + } + +@@ -69,10 +65,8 @@ ld { + + # Internal error handling support. + _dl_exception_create; _dl_exception_create_format; _dl_exception_free; +- +- # Internal error handling support. Interposed by libc.so. + _dl_signal_exception; _dl_catch_exception; +- _dl_signal_error; _dl_catch_error; ++ _dl_signal_error; + + # Set value of a tunable. + __tunable_get_val; +diff -rupN a/elf/dl-catch.c b/elf/dl-catch.c +--- a/elf/dl-catch.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/elf/dl-catch.c 2024-08-29 11:29:16.782810295 -0400 +@@ -0,0 +1,261 @@ ++/* Exception handling in the dynamic linker. ++ Copyright (C) 1995-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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* This structure communicates state between _dl_catch_error and ++ _dl_signal_error. */ ++struct rtld_catch ++ { ++ struct dl_exception *exception; /* The exception data is stored there. */ ++ volatile int *errcode; /* Return value of _dl_signal_error. */ ++ jmp_buf env; /* longjmp here on error. */ ++ }; ++ ++/* Multiple threads at once can use the `_dl_catch_error' function. ++ The calls can come from `_dl_map_object_deps', `_dlerror_run', or ++ from any of the libc functionality which loads dynamic objects ++ (NSS, iconv). Therefore we have to be prepared to save the state ++ in thread-local memory. We use THREAD_GETMEM and THREAD_SETMEM ++ instead of ELF TLS because ELF TLS is not available in the dynamic ++ loader. Additionally, the exception handling mechanism must be ++ usable before the TCB has been set up, which is why ++ rtld_catch_notls is used if !__rtld_tls_init_tp_called. This is ++ not needed for static builds, where initialization completes before ++ static dlopen etc. can be called. */ ++ ++#if IS_IN (rtld) ++static struct rtld_catch *rtld_catch_notls; ++#endif ++ ++static struct rtld_catch * ++get_catch (void) ++{ ++#if IS_IN (rtld) ++ if (!__rtld_tls_init_tp_called) ++ return rtld_catch_notls; ++ else ++#endif ++ return THREAD_GETMEM (THREAD_SELF, rtld_catch); ++} ++ ++static void ++set_catch (struct rtld_catch *catch) ++{ ++#if IS_IN (rtld) ++ if (!__rtld_tls_init_tp_called) ++ rtld_catch_notls = catch; ++ else ++#endif ++ THREAD_SETMEM (THREAD_SELF, rtld_catch, catch); ++} ++ ++/* Lossage while resolving the program's own symbols is always fatal. */ ++static void ++__attribute__ ((noreturn)) ++fatal_error (int errcode, const char *objname, const char *occasion, ++ const char *errstring) ++{ ++ char buffer[1024]; ++ _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", ++ RTLD_PROGNAME, ++ occasion ?: N_("error while loading shared libraries"), ++ objname, *objname ? ": " : "", ++ errstring, errcode ? ": " : "", ++ (errcode ++ ? __strerror_r (errcode, buffer, sizeof buffer) ++ : "")); ++} ++ ++void ++_dl_signal_exception (int errcode, struct dl_exception *exception, ++ const char *occasion) ++{ ++ struct rtld_catch *lcatch = get_catch (); ++ if (lcatch != NULL) ++ { ++ *lcatch->exception = *exception; ++ *lcatch->errcode = errcode; ++ ++ /* We do not restore the signal mask because none was saved. */ ++ __longjmp (lcatch->env[0].__jmpbuf, 1); ++ } ++ else ++ fatal_error (errcode, exception->objname, occasion, exception->errstring); ++} ++rtld_hidden_def (_dl_signal_exception) ++ ++void ++_dl_signal_error (int errcode, const char *objname, const char *occation, ++ const char *errstring) ++{ ++ struct rtld_catch *lcatch = get_catch (); ++ ++ if (! errstring) ++ errstring = N_("DYNAMIC LINKER BUG!!!"); ++ ++ if (lcatch != NULL) ++ { ++ _dl_exception_create (lcatch->exception, objname, errstring); ++ *lcatch->errcode = errcode; ++ ++ /* We do not restore the signal mask because none was saved. */ ++ __longjmp (lcatch->env[0].__jmpbuf, 1); ++ } ++ else ++ fatal_error (errcode, objname, occation, errstring); ++} ++rtld_hidden_def (_dl_signal_error) ++ ++#if IS_IN (rtld) ++/* This points to a function which is called when a continuable error is ++ received. Unlike the handling of `catch' this function may return. ++ The arguments will be the `errstring' and `objname'. ++ ++ Since this functionality is not used in normal programs (only in ld.so) ++ we do not care about multi-threaded programs here. We keep this as a ++ global variable. */ ++static receiver_fct receiver; ++ ++void ++_dl_signal_cexception (int errcode, struct dl_exception *exception, ++ const char *occasion) ++{ ++ if (__builtin_expect (GLRO(dl_debug_mask) ++ & ~(DL_DEBUG_STATISTICS), 0)) ++ _dl_debug_printf ("%s: error: %s: %s (%s)\n", ++ exception->objname, occasion, ++ exception->errstring, receiver ? "continued" : "fatal"); ++ ++ if (receiver) ++ { ++ /* We are inside _dl_receive_error. Call the user supplied ++ handler and resume the work. The receiver will still be ++ installed. */ ++ (*receiver) (errcode, exception->objname, exception->errstring); ++ } ++ else ++ _dl_signal_exception (errcode, exception, occasion); ++} ++ ++void ++_dl_signal_cerror (int errcode, const char *objname, const char *occation, ++ const char *errstring) ++{ ++ if (__builtin_expect (GLRO(dl_debug_mask) ++ & ~(DL_DEBUG_STATISTICS), 0)) ++ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation, ++ errstring, receiver ? "continued" : "fatal"); ++ ++ if (receiver) ++ { ++ /* We are inside _dl_receive_error. Call the user supplied ++ handler and resume the work. The receiver will still be ++ installed. */ ++ (*receiver) (errcode, objname, errstring); ++ } ++ else ++ _dl_signal_error (errcode, objname, occation, errstring); ++} ++ ++void ++_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) ++{ ++ struct rtld_catch *old_catch = get_catch (); ++ receiver_fct old_receiver = receiver; ++ ++ /* Set the new values. */ ++ set_catch (NULL); ++ receiver = fct; ++ ++ (*operate) (args); ++ ++ set_catch (old_catch); ++ receiver = old_receiver; ++} ++#endif ++ ++int ++_dl_catch_exception (struct dl_exception *exception, ++ void (*operate) (void *), void *args) ++{ ++ /* If exception is NULL, temporarily disable exception handling. ++ Exceptions during operate (args) are fatal. */ ++ if (exception == NULL) ++ { ++ struct rtld_catch *old_catch = get_catch (); ++ set_catch (NULL); ++ operate (args); ++ /* If we get here, the operation was successful. */ ++ set_catch (old_catch); ++ return 0; ++ } ++ ++ /* We need not handle `receiver' since setting a `catch' is handled ++ before it. */ ++ ++ /* Only this needs to be marked volatile, because it is the only local ++ variable that gets changed between the setjmp invocation and the ++ longjmp call. All others are just set here (before setjmp) and read ++ in _dl_signal_error (before longjmp). */ ++ volatile int errcode; ++ ++ struct rtld_catch c; ++ /* Don't use an initializer since we don't need to clear C.env. */ ++ c.exception = exception; ++ c.errcode = &errcode; ++ ++ struct rtld_catch *old = get_catch (); ++ set_catch (&c); ++ ++ /* Do not save the signal mask. */ ++ if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0) ++ { ++ (*operate) (args); ++ set_catch (old); ++ *exception = (struct dl_exception) { NULL }; ++ return 0; ++ } ++ ++ /* We get here only if we longjmp'd out of OPERATE. ++ _dl_signal_exception has already stored values into ++ *EXCEPTION. */ ++ set_catch (old); ++ return errcode; ++} ++rtld_hidden_def (_dl_catch_exception) ++ ++int ++_dl_catch_error (const char **objname, const char **errstring, ++ bool *mallocedp, void (*operate) (void *), void *args) ++{ ++ struct dl_exception exception; ++ int errorcode = _dl_catch_exception (&exception, operate, args); ++ *objname = exception.objname; ++ *errstring = exception.errstring; ++ *mallocedp = exception.message_buffer == exception.errstring; ++ return errorcode; ++} +diff -rupN a/elf/dl-error-minimal.c b/elf/dl-error-minimal.c +--- a/elf/dl-error-minimal.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/elf/dl-error-minimal.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,23 +0,0 @@ +-/* Error handling for runtime dynamic linker, minimal version. +- Copyright (C) 1995-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 +- . */ +- +-/* This version does lives in ld.so, does not use thread-local data +- and supports _dl_signal_cerror and _dl_receive_error. */ +- +-#define DL_ERROR_BOOTSTRAP 1 +-#include "dl-error-skeleton.c" +diff -rupN a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c +--- a/elf/dl-error-skeleton.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/elf/dl-error-skeleton.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,263 +0,0 @@ +-/* Template for error handling for runtime dynamic linker. +- Copyright (C) 1995-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 +- . */ +- +-/* The following macro needs to be defined before including this +- skeleton file: +- +- DL_ERROR_BOOTSTRAP +- +- If 1, do not use TLS and implement _dl_signal_cerror and +- _dl_receive_error. If 0, TLS is used, and the variants with +- error callbacks are not provided. */ +- +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* This structure communicates state between _dl_catch_error and +- _dl_signal_error. */ +-struct catch +- { +- struct dl_exception *exception; /* The exception data is stored there. */ +- volatile int *errcode; /* Return value of _dl_signal_error. */ +- jmp_buf env; /* longjmp here on error. */ +- }; +- +-/* Multiple threads at once can use the `_dl_catch_error' function. The +- calls can come from `_dl_map_object_deps', `_dlerror_run', or from +- any of the libc functionality which loads dynamic objects (NSS, iconv). +- Therefore we have to be prepared to save the state in thread-local +- memory. */ +-#if !DL_ERROR_BOOTSTRAP +-static __thread struct catch *catch_hook attribute_tls_model_ie; +-#else +-/* The version of this code in ld.so cannot use thread-local variables +- and is used during bootstrap only. */ +-static struct catch *catch_hook; +-#endif +- +-#if DL_ERROR_BOOTSTRAP +-/* This points to a function which is called when an continuable error is +- received. Unlike the handling of `catch' this function may return. +- The arguments will be the `errstring' and `objname'. +- +- Since this functionality is not used in normal programs (only in ld.so) +- we do not care about multi-threaded programs here. We keep this as a +- global variable. */ +-static receiver_fct receiver; +-#endif /* DL_ERROR_BOOTSTRAP */ +- +-/* Lossage while resolving the program's own symbols is always fatal. */ +-static void +-__attribute__ ((noreturn)) +-fatal_error (int errcode, const char *objname, const char *occasion, +- const char *errstring) +-{ +- char buffer[1024]; +- _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", +- RTLD_PROGNAME, +- occasion ?: N_("error while loading shared libraries"), +- objname, *objname ? ": " : "", +- errstring, errcode ? ": " : "", +- (errcode +- ? __strerror_r (errcode, buffer, sizeof buffer) +- : "")); +-} +- +-void +-_dl_signal_exception (int errcode, struct dl_exception *exception, +- const char *occasion) +-{ +- struct catch *lcatch = catch_hook; +- if (lcatch != NULL) +- { +- *lcatch->exception = *exception; +- *lcatch->errcode = errcode; +- +- /* We do not restore the signal mask because none was saved. */ +- __longjmp (lcatch->env[0].__jmpbuf, 1); +- } +- else +- fatal_error (errcode, exception->objname, occasion, exception->errstring); +-} +-libc_hidden_def (_dl_signal_exception) +- +-void +-_dl_signal_error (int errcode, const char *objname, const char *occation, +- const char *errstring) +-{ +- struct catch *lcatch = catch_hook; +- +- if (! errstring) +- errstring = N_("DYNAMIC LINKER BUG!!!"); +- +- if (lcatch != NULL) +- { +- _dl_exception_create (lcatch->exception, objname, errstring); +- *lcatch->errcode = errcode; +- +- /* We do not restore the signal mask because none was saved. */ +- __longjmp (lcatch->env[0].__jmpbuf, 1); +- } +- else +- fatal_error (errcode, objname, occation, errstring); +-} +-libc_hidden_def (_dl_signal_error) +- +- +-#if DL_ERROR_BOOTSTRAP +-void +-_dl_signal_cexception (int errcode, struct dl_exception *exception, +- const char *occasion) +-{ +- if (__builtin_expect (GLRO(dl_debug_mask) +- & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0)) +- _dl_debug_printf ("%s: error: %s: %s (%s)\n", +- exception->objname, occasion, +- exception->errstring, receiver ? "continued" : "fatal"); +- +- if (receiver) +- { +- /* We are inside _dl_receive_error. Call the user supplied +- handler and resume the work. The receiver will still be +- installed. */ +- (*receiver) (errcode, exception->objname, exception->errstring); +- } +- else +- _dl_signal_exception (errcode, exception, occasion); +-} +- +-void +-_dl_signal_cerror (int errcode, const char *objname, const char *occation, +- const char *errstring) +-{ +- if (__builtin_expect (GLRO(dl_debug_mask) +- & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0)) +- _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation, +- errstring, receiver ? "continued" : "fatal"); +- +- if (receiver) +- { +- /* We are inside _dl_receive_error. Call the user supplied +- handler and resume the work. The receiver will still be +- installed. */ +- (*receiver) (errcode, objname, errstring); +- } +- else +- _dl_signal_error (errcode, objname, occation, errstring); +-} +-#endif /* DL_ERROR_BOOTSTRAP */ +- +-int +-_dl_catch_exception (struct dl_exception *exception, +- void (*operate) (void *), void *args) +-{ +- /* If exception is NULL, temporarily disable exception handling. +- Exceptions during operate (args) are fatal. */ +- if (exception == NULL) +- { +- struct catch *const old = catch_hook; +- catch_hook = NULL; +- operate (args); +- /* If we get here, the operation was successful. */ +- catch_hook = old; +- return 0; +- } +- +- /* We need not handle `receiver' since setting a `catch' is handled +- before it. */ +- +- /* Only this needs to be marked volatile, because it is the only local +- variable that gets changed between the setjmp invocation and the +- longjmp call. All others are just set here (before setjmp) and read +- in _dl_signal_error (before longjmp). */ +- volatile int errcode; +- +- struct catch c; +- /* Don't use an initializer since we don't need to clear C.env. */ +- c.exception = exception; +- c.errcode = &errcode; +- +- struct catch *const old = catch_hook; +- catch_hook = &c; +- +- /* Do not save the signal mask. */ +- if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0) +- { +- (*operate) (args); +- catch_hook = old; +- *exception = (struct dl_exception) { NULL }; +- return 0; +- } +- +- /* We get here only if we longjmp'd out of OPERATE. +- _dl_signal_exception has already stored values into +- *EXCEPTION. */ +- catch_hook = old; +- return errcode; +-} +-libc_hidden_def (_dl_catch_exception) +- +-int +-_dl_catch_error (const char **objname, const char **errstring, +- bool *mallocedp, void (*operate) (void *), void *args) +-{ +- struct dl_exception exception; +- int errorcode = _dl_catch_exception (&exception, operate, args); +- *objname = exception.objname; +- *errstring = exception.errstring; +- *mallocedp = exception.message_buffer == exception.errstring; +- return errorcode; +-} +-libc_hidden_def (_dl_catch_error) +- +-#if DL_ERROR_BOOTSTRAP +-void +-_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) +-{ +- struct catch *old_catch = catch_hook; +- receiver_fct old_receiver = receiver; +- +- /* Set the new values. */ +- catch_hook = NULL; +- receiver = fct; +- +- (*operate) (args); +- +- catch_hook = old_catch; +- receiver = old_receiver; +-} +- +-/* Forwarder used for initializing GLRO (_dl_catch_error). */ +-int +-_rtld_catch_error (const char **objname, const char **errstring, +- bool *mallocedp, void (*operate) (void *), +- void *args) +-{ +- /* The reference to _dl_catch_error will eventually be relocated to +- point to the implementation in libc.so. */ +- return _dl_catch_error (objname, errstring, mallocedp, operate, args); +-} +- +-#endif /* DL_ERROR_BOOTSTRAP */ +diff -rupN a/elf/dl-error.c b/elf/dl-error.c +--- a/elf/dl-error.c 2021-08-01 21:33:43.000000000 -0400 ++++ b/elf/dl-error.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,27 +0,0 @@ +-/* Error handling for runtime dynamic linker, full version. +- Copyright (C) 1995-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 +- . */ +- +-/* This implementation lives in libc.so because it uses thread-local +- data, which is not available in ld.so. It interposes the version +- in dl-error-minimal.c after ld.so bootstrap. +- +- The signal/catch mechanism is used by the audit framework, which +- means that even in ld.so, not all errors are fatal. */ +- +-#define DL_ERROR_BOOTSTRAP 0 +-#include "dl-error-skeleton.c" +diff -rupN a/elf/rtld.c b/elf/rtld.c +--- a/elf/rtld.c 2024-08-29 11:28:38.569326061 -0400 ++++ b/elf/rtld.c 2024-08-29 11:29:16.798810916 -0400 +@@ -377,7 +377,7 @@ struct rtld_global_ro _rtld_global_ro at + ._dl_lookup_symbol_x = _dl_lookup_symbol_x, + ._dl_open = _dl_open, + ._dl_close = _dl_close, +- ._dl_catch_error = _rtld_catch_error, ++ ._dl_catch_error = _dl_catch_error, + ._dl_error_free = _dl_error_free, + ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft, + #ifdef HAVE_DL_DISCOVER_OSVERSION +diff -rupN a/nptl/descr.h b/nptl/descr.h +--- a/nptl/descr.h 2024-08-29 11:28:37.858298444 -0400 ++++ b/nptl/descr.h 2024-08-29 11:29:16.801811033 -0400 +@@ -396,6 +396,9 @@ struct pthread + masked.) */ + sigset_t sigmask; + ++ /* Used by the exception handling implementation in the dynamic loader. */ ++ struct rtld_catch *rtld_catch; ++ + /* Indicates whether is a C11 thread created by thrd_creat. */ + bool c11; + +diff -rupN a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +--- a/sysdeps/generic/ldsodefs.h 2024-08-29 11:28:38.571326139 -0400 ++++ b/sysdeps/generic/ldsodefs.h 2024-08-29 11:29:16.805811188 -0400 +@@ -897,13 +897,13 @@ rtld_hidden_proto (_dl_exception_free) + void _dl_signal_exception (int errcode, struct dl_exception *, + const char *occasion) + __attribute__ ((__noreturn__)); +-libc_hidden_proto (_dl_signal_exception) ++rtld_hidden_proto (_dl_signal_exception) + + /* Like _dl_signal_exception, but creates the exception first. */ + extern void _dl_signal_error (int errcode, const char *object, + const char *occasion, const char *errstring) + __attribute__ ((__noreturn__)); +-libc_hidden_proto (_dl_signal_error) ++rtld_hidden_proto (_dl_signal_error) + + /* Like _dl_signal_exception, but may return when called in the + context of _dl_receive_error. This is only used during ld.so +@@ -955,11 +955,7 @@ extern void _dl_receive_error (receiver_ + the returned string is allocated using the libc's malloc. */ + extern int _dl_catch_error (const char **objname, const char **errstring, + bool *mallocedp, void (*operate) (void *), +- void *args); +-libc_hidden_proto (_dl_catch_error) +- +-/* Used for initializing GLRO (_dl_catch_error). */ +-extern __typeof__ (_dl_catch_error) _rtld_catch_error attribute_hidden; ++ void *args) attribute_hidden; + + /* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero. + Otherwise, store a copy of the raised exception in *EXCEPTION, +@@ -968,7 +964,7 @@ extern __typeof__ (_dl_catch_error) _rtl + disabled (so that exceptions are fatal). */ + int _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args); +-libc_hidden_proto (_dl_catch_exception) ++rtld_hidden_proto (_dl_catch_exception) + + /* Open the shared object NAME and map in its segments. + LOADER's DT_RPATH is used in searching for NAME. +diff -rupN a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data +--- a/sysdeps/generic/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/generic/localplt.data 2024-08-29 11:29:16.806811227 -0400 +@@ -6,8 +6,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data +--- a/sysdeps/mach/hurd/i386/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/mach/hurd/i386/localplt.data 2024-08-29 11:29:16.808811305 -0400 +@@ -8,11 +8,6 @@ libc.so: free + REL R_386_GLOB_DAT + libc.so: malloc + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT + libm.so: matherr + REL R_386_GLOB_DAT +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error + REL R_386_GLOB_DAT +-ld.so: _dl_catch_error + REL R_386_GLOB_DAT +-ld.so: _dl_signal_exception + REL R_386_GLOB_DAT +-ld.so: _dl_catch_exception + REL R_386_GLOB_DAT + # The dynamic linker has its own versions of basic functions for initial loading + # of shared libraries. These need to be overriden by libc once loaded. + ld.so: __open ? +diff -rupN a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h +--- a/sysdeps/mach/hurd/i386/tls.h 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/mach/hurd/i386/tls.h 2024-08-29 11:29:16.810811382 -0400 +@@ -48,6 +48,9 @@ typedef struct + compatible with the i386 Linux version. */ + mach_port_t reply_port; /* This thread's reply port. */ + struct hurd_sigstate *_hurd_sigstate; ++ ++ /* Used by the exception handling implementation in the dynamic loader. */ ++ struct rtld_catch *rtld_catch; + } tcbhead_t; + #endif + +diff -rupN a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data +--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data 2024-08-29 11:29:16.810811382 -0400 +@@ -11,8 +11,3 @@ libm.so: matherr + libc.so: __getauxval ? + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data +--- a/sysdeps/unix/sysv/linux/alpha/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/alpha/localplt.data 2024-08-29 11:29:16.810811382 -0400 +@@ -25,8 +25,3 @@ libm.so: matherr + RELA R_ALPHA_GLOB_DAT + libm.so: __atan2 + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr ? +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error + RELA R_ALPHA_GLOB_DAT +-ld.so: _dl_catch_error + RELA R_ALPHA_GLOB_DAT +-ld.so: _dl_signal_exception + RELA R_ALPHA_GLOB_DAT +-ld.so: _dl_catch_exception + RELA R_ALPHA_GLOB_DAT +diff -rupN a/sysdeps/unix/sysv/linux/arc/localplt.data b/sysdeps/unix/sysv/linux/arc/localplt.data +--- a/sysdeps/unix/sysv/linux/arc/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/arc/localplt.data 2024-08-29 11:29:16.814811538 -0400 +@@ -4,8 +4,3 @@ libc.so: calloc + libc.so: free + # At -Os, a struct assignment in libgcc-static pulls this in + libc.so: memcpy ? +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data +--- a/sysdeps/unix/sysv/linux/arm/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/arm/localplt.data 2024-08-29 11:29:16.814811538 -0400 +@@ -6,8 +6,3 @@ libc.so: realloc + libm.so: matherr + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/csky/localplt.data b/sysdeps/unix/sysv/linux/csky/localplt.data +--- a/sysdeps/unix/sysv/linux/csky/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/csky/localplt.data 2024-08-29 11:29:16.814811538 -0400 +@@ -5,8 +5,3 @@ libc.so: calloc + libc.so: free + libc.so: malloc + libc.so: realloc +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data +--- a/sysdeps/unix/sysv/linux/hppa/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/hppa/localplt.data 2024-08-29 11:29:16.814811538 -0400 +@@ -9,8 +9,3 @@ libc.so: __sigsetjmp + libc.so: _IO_funlockfile + libc.so: __errno_location + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data +--- a/sysdeps/unix/sysv/linux/i386/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/i386/localplt.data 2024-08-29 11:29:16.816811615 -0400 +@@ -6,8 +6,3 @@ libc.so: free + REL R_386_GLOB_DAT + libc.so: malloc + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT + libm.so: matherr + REL R_386_GLOB_DAT +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error + REL R_386_GLOB_DAT +-ld.so: _dl_catch_error + REL R_386_GLOB_DAT +-ld.so: _dl_signal_exception + REL R_386_GLOB_DAT +-ld.so: _dl_catch_exception + REL R_386_GLOB_DAT +diff -rupN a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data +--- a/sysdeps/unix/sysv/linux/ia64/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/ia64/localplt.data 2024-08-29 11:29:16.816811615 -0400 +@@ -5,8 +5,3 @@ libc.so: realloc + libm.so: matherr + libm.so: matherrf + libm.so: matherrl +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data 2024-08-29 11:29:16.819811732 -0400 +@@ -4,8 +4,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data 2024-08-29 11:29:16.820811771 -0400 +@@ -5,8 +5,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data +--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data 2024-08-29 11:29:16.822811848 -0400 +@@ -6,8 +6,3 @@ libc.so: realloc + libm.so: matherr + # The dynamic loader needs __tls_get_addr for TLS. + ld.so: __tls_get_addr ? +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data +--- a/sysdeps/unix/sysv/linux/nios2/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/nios2/localplt.data 2024-08-29 11:29:16.825811965 -0400 +@@ -27,8 +27,3 @@ libc.so: __eqdf2 + libc.so: __extendsfdf2 + libc.so: __floatundidf ? + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data 2024-08-29 11:29:16.829812120 -0400 +@@ -4,8 +4,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data 2024-08-29 11:29:16.831812198 -0400 +@@ -35,8 +35,3 @@ libc.so: realloc + libm.so: copysignl ? + libm.so: fabsl + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data 2024-08-29 11:29:16.833812276 -0400 +@@ -3,8 +3,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data +--- a/sysdeps/unix/sysv/linux/riscv/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/riscv/localplt.data 2024-08-29 11:29:16.835812353 -0400 +@@ -6,8 +6,3 @@ libc.so: free + libc.so: malloc + libc.so: memset ? + libc.so: realloc +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data +--- a/sysdeps/unix/sysv/linux/s390/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/s390/localplt.data 2024-08-29 11:29:16.837812431 -0400 +@@ -4,8 +4,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data +--- a/sysdeps/unix/sysv/linux/sh/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/sh/localplt.data 2024-08-29 11:29:16.838812470 -0400 +@@ -11,8 +11,3 @@ libc.so: __errno_location + libm.so: matherr + # Generated by the compiler because there is no trap insn pattern. + libc.so: abort ? +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data 2024-08-29 11:29:16.840812547 -0400 +@@ -18,8 +18,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data 2024-08-29 11:29:16.844812703 -0400 +@@ -17,8 +17,3 @@ libc.so: free + libc.so: malloc + libc.so: realloc + libm.so: matherr +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error +-ld.so: _dl_catch_error +-ld.so: _dl_signal_exception +-ld.so: _dl_catch_exception +diff -rupN a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data +--- a/sysdeps/x86_64/localplt.data 2021-08-01 21:33:43.000000000 -0400 ++++ b/sysdeps/x86_64/localplt.data 2024-08-29 11:29:16.847812819 -0400 +@@ -8,8 +8,3 @@ libc.so: free + RELA R_X86_64_GLOB_DAT + libc.so: malloc + RELA R_X86_64_GLOB_DAT + libc.so: realloc + RELA R_X86_64_GLOB_DAT + libm.so: matherr + RELA R_X86_64_GLOB_DAT +-# The TLS-enabled version of these functions is interposed from libc.so. +-ld.so: _dl_signal_error + RELA R_X86_64_GLOB_DAT +-ld.so: _dl_catch_error + RELA R_X86_64_GLOB_DAT +-ld.so: _dl_signal_exception + RELA R_X86_64_GLOB_DAT +-ld.so: _dl_catch_exception + RELA R_X86_64_GLOB_DAT diff --git a/SOURCES/glibc-RHEL-46979-3.patch b/SOURCES/glibc-RHEL-46979-3.patch new file mode 100644 index 0000000..de8b390 --- /dev/null +++ b/SOURCES/glibc-RHEL-46979-3.patch @@ -0,0 +1,82 @@ +Extra changes needed for backport: + +* rename field "rtld_catch" to "rtld_catch_f" to avoid conflict + between "struct rtld-catch" and rtld_catch macro + +* move rtld_catch into one of the unused padding fields to preserve + ABI + +* Validate that the padding fields used don't overlap other fields. + +diff -rup a/elf/dl-catch.c b/elf/dl-catch.c +--- a/elf/dl-catch.c 2024-09-04 16:30:02.086402568 -0400 ++++ b/elf/dl-catch.c 2024-09-04 16:55:01.933440181 -0400 +@@ -59,7 +59,7 @@ get_catch (void) + return rtld_catch_notls; + else + #endif +- return THREAD_GETMEM (THREAD_SELF, rtld_catch); ++ return THREAD_GETMEM (THREAD_SELF, rtld_catch_f); + } + + static void +@@ -70,7 +70,7 @@ set_catch (struct rtld_catch *catch) + rtld_catch_notls = catch; + else + #endif +- THREAD_SETMEM (THREAD_SELF, rtld_catch, catch); ++ THREAD_SETMEM (THREAD_SELF, rtld_catch_f, catch); + } + + /* Lossage while resolving the program's own symbols is always fatal. */ +diff -rup a/nptl/descr.h b/nptl/descr.h +--- a/nptl/descr.h 2024-08-29 11:29:16.801811033 -0400 ++++ b/nptl/descr.h 2024-08-29 11:48:56.547644398 -0400 +@@ -164,6 +164,12 @@ struct pthread + void *__padding[24]; + }; + ++#ifdef __x86_64__ ++#define rtld_catch_f header.__padding[7] ++#else ++#define rtld_catch_f __padding[23] ++#endif ++ + /* This descriptor's link on the GL (dl_stack_used) or + GL (dl_stack_user) list. */ + list_t list; +@@ -396,9 +402,6 @@ struct pthread + masked.) */ + sigset_t sigmask; + +- /* Used by the exception handling implementation in the dynamic loader. */ +- struct rtld_catch *rtld_catch; +- + /* Indicates whether is a C11 thread created by thrd_creat. */ + bool c11; + +@@ -432,6 +435,12 @@ struct pthread + + sizeof ((struct pthread) {}.rseq_area)) + } __attribute ((aligned (TCB_ALIGNMENT))); + ++#ifdef __x86_64__ ++_Static_assert (sizeof ((*(struct pthread *)0).header) > sizeof ((*(struct pthread *)0).__padding), "rtld_catch"); ++#else ++_Static_assert (sizeof ((*(struct pthread *)0).header) < sizeof ((*(struct pthread *)0).__padding), "rtld_catch"); ++#endif ++ + static inline bool + cancel_enabled_and_canceled (int value) + { +diff -rup a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h +--- a/sysdeps/mach/hurd/i386/tls.h 2024-08-29 11:29:16.810811382 -0400 ++++ b/sysdeps/mach/hurd/i386/tls.h 2024-08-29 11:35:45.262899113 -0400 +@@ -50,7 +50,7 @@ typedef struct + struct hurd_sigstate *_hurd_sigstate; + + /* Used by the exception handling implementation in the dynamic loader. */ +- struct rtld_catch *rtld_catch; ++ struct rtld_catch *rtld_catch_f; + } tcbhead_t; + #endif + diff --git a/SOURCES/glibc-RHEL-46979-4.patch b/SOURCES/glibc-RHEL-46979-4.patch new file mode 100644 index 0000000..d9d6985 --- /dev/null +++ b/SOURCES/glibc-RHEL-46979-4.patch @@ -0,0 +1,79 @@ +New test case to verify padding usage. + +diff --git a/nptl/Makefile b/nptl/Makefile +index ff4d590f11c38277..9a56d34313d06444 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -319,6 +319,8 @@ tests-internal := tst-robustpi8 tst-rwlock19 tst-rwlock20 \ + tst-barrier5 tst-signal7 tst-mutex8 tst-mutex8-static \ + tst-mutexpi8 tst-mutexpi8-static \ + tst-setgetname \ ++ tst-nptl-padding \ ++ # tests-internal + + xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ + tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 tst-setgroups \ +diff --git a/nptl/tst-nptl-padding.c b/nptl/tst-nptl-padding.c +new file mode 100644 +index 0000000000000000..5bb64f4a54335e36 +--- /dev/null ++++ b/nptl/tst-nptl-padding.c +@@ -0,0 +1,57 @@ ++/* Downstream-only test for verifying that fields that have been ++ relocated into struct pthread padding actually use the padding. ++ ++ At present, only rtld_catch (downstream: rtld_catch_f) has been ++ placed into padding. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct pthread descr; ++ ++ /* Mark the entire descriptor as used. */ ++ memset (&descr, 0xff, sizeof (descr)); ++ ++ /* Mark the padding as unused. */ ++#ifdef __x86_64__ ++ /* Special case: Usable padding is in the header. */ ++ memset (&descr.header.__padding, 0, sizeof (descr.header.__padding)); ++#else ++ /* The padding should be directly adjacent to the first real ++ struct field. */ ++ TEST_COMPARE (sizeof (descr.__padding), offsetof (struct pthread, list)); ++ ++ /* Clear the unused tail of the padding. */ ++ { ++ char *base = (char *) &descr; ++ char *end_of_header = base + sizeof (descr.header); ++ char *end_of_padding = base + sizeof (descr.__padding); ++ memset (end_of_header, 0, end_of_padding - end_of_header); ++ } ++#endif ++ ++ /* These fields are not in padding and should remain marked as used. */ ++ TEST_COMPARE (descr.header.gscope_flag, -1); ++ TEST_COMPARE ((intptr_t) descr.list.next, -1); ++ TEST_COMPARE ((intptr_t) descr.list.prev, -1); ++ ++ /* But this field remains in padding. */ ++ TEST_COMPARE ((intptr_t) descr.rtld_catch_f, 0); ++ ++ /* Write to all padding-relocated fields below to show that they ++ have independent locations. */ ++ struct rtld_catch *rtld_catch_dummy = (void *) "rtld_catch_dummy"; ++ descr.rtld_catch_f = rtld_catch_dummy; ++ ++ TEST_VERIFY (descr.rtld_catch_f == rtld_catch_dummy); ++ ++ return 0; ++} ++ ++#include + diff --git a/SOURCES/glibc-RHEL-47467.patch b/SOURCES/glibc-RHEL-47467.patch new file mode 100644 index 0000000..609ac9d --- /dev/null +++ b/SOURCES/glibc-RHEL-47467.patch @@ -0,0 +1,146 @@ +commit b7d4de086ce7fcc531cdd67a61dc27b5b3eff482 +Author: Florian Weimer +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 + +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}, diff --git a/SOURCES/glibc-RHEL-49489-1.patch b/SOURCES/glibc-RHEL-49489-1.patch new file mode 100644 index 0000000..3f2d6d8 --- /dev/null +++ b/SOURCES/glibc-RHEL-49489-1.patch @@ -0,0 +1,51 @@ +commit 9b7651410375ec8848a1944992d663d514db4ba7 +Author: Stefan Liebler +Date: Thu Jul 11 11:28:53 2024 +0200 + + s390x: Fix segfault in wcsncmp [BZ #31934] + + The z13/vector-optimized wcsncmp implementation segfaults if n=1 + and there is only one character (equal on both strings) before + the page end. Then it loads and compares one character and misses + to check n again. The following load fails. + + This patch removes the extra load and compare of the first character + and just start with the loop which uses vector-load-to-block-boundary. + This code-path also checks n. + + With this patch both tests are passing: + - the simplified one mentioned in the bugzilla 31934 + - the full one in Florian Weimer's patch: + "manual: Document a GNU extension for strncmp/wcsncmp" + (https://patchwork.sourceware.org/project/glibc/patch/874j9eml6y.fsf@oldenburg.str.redhat.com/): + On s390x-linux-gnu (z16), the new wcsncmp test fails due to bug 31934. + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/s390/wcsncmp-vx.S b/sysdeps/s390/wcsncmp-vx.S +index bf6dfa6bc2..8b081567a2 100644 +--- a/sysdeps/s390/wcsncmp-vx.S ++++ b/sysdeps/s390/wcsncmp-vx.S +@@ -59,14 +59,7 @@ ENTRY(WCSNCMP_Z13) + sllg %r4,%r4,2 /* Convert character-count to byte-count. */ + locgrne %r4,%r1 /* Use max byte-count, if bit 0/1 was one. */ + +- /* Check first character without vector load. */ +- lghi %r5,4 /* current_len = 4 bytes. */ +- /* Check s1/2[0]. */ +- lt %r0,0(%r2) +- l %r1,0(%r3) +- je .Lend_cmp_one_char +- crjne %r0,%r1,.Lend_cmp_one_char +- ++ lghi %r5,0 /* current_len = 0 bytes. */ + .Lloop: + vlbb %v17,0(%r5,%r3),6 /* Load s2 to block boundary. */ + vlbb %v16,0(%r5,%r2),6 /* Load s1 to block boundary. */ +@@ -167,7 +160,6 @@ ENTRY(WCSNCMP_Z13) + srl %r4,2 /* And convert it to character-index. */ + vlgvf %r0,%v16,0(%r4) /* Load character-values. */ + vlgvf %r1,%v17,0(%r4) +-.Lend_cmp_one_char: + cr %r0,%r1 + je .Lend_equal + lghi %r2,1 diff --git a/SOURCES/glibc-RHEL-49489-2.patch b/SOURCES/glibc-RHEL-49489-2.patch new file mode 100644 index 0000000..6802b1f --- /dev/null +++ b/SOURCES/glibc-RHEL-49489-2.patch @@ -0,0 +1,248 @@ +commit 54252394c25ddf0062e288d4a6ab7a885f8ae009 +Author: Florian Weimer +Date: Thu Jun 27 16:26:56 2024 +0200 + + Enhanced test coverage for strncmp, wcsncmp + + Add string/test-strncmp-nonarray and + wcsmbs/test-wcsncmp-nonarray. + + This is the test that uncovered bug 31934. Test run time + is more than one minute on a fairly current system, so turn + these into xtests that do not run automatically. + + Reviewed-by: Noah Goldstein + +diff -Nrup a/string/Makefile b/string/Makefile +--- a/string/Makefile 2024-09-03 11:42:30.396319962 -0400 ++++ b/string/Makefile 2024-09-03 11:52:17.707438963 -0400 +@@ -76,7 +76,10 @@ tests-unsupported += $(tests-translation + endif + + # This test allocates a lot of memory and can run for a long time. +-xtests = tst-strcoll-overflow ++xtests += tst-strcoll-overflow ++ ++# This test runs for a long time. ++xtests += test-strncmp-nonarray + + # This test needs libdl. + ifeq (yes,$(build-shared)) +diff -Nrup a/string/test-Xncmp-nonarray.c b/string/test-Xncmp-nonarray.c +--- a/string/test-Xncmp-nonarray.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/string/test-Xncmp-nonarray.c 2024-09-03 11:52:17.707438963 -0400 +@@ -0,0 +1,183 @@ ++/* Test non-array inputs to string comparison 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 ++ 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 ++ . */ ++ ++/* This skeleton file is included from string/test-strncmp-nonarray.c and ++ wcsmbs/test-wcsncmp-nonarray.c to test that reading of the arrays stops ++ at the first null character. ++ ++ TEST_IDENTIFIER must be the test function identifier. TEST_NAME is ++ the same as a string. ++ ++ CHAR must be defined as the character type. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Much shorter than test-Xnlen-nonarray.c because of deeply nested loops. */ ++enum { buffer_length = 80 }; ++ ++/* The test buffer layout follows what is described test-Xnlen-nonarray.c, ++ except that there two buffers, left and right. The variables ++ a_count, zero_count, start_offset are all duplicated. */ ++ ++/* Return the maximum string length for a string that starts at ++ start_offset. */ ++static int ++string_length (int a_count, int start_offset) ++{ ++ if (start_offset == buffer_length || start_offset >= a_count) ++ return 0; ++ else ++ return a_count - start_offset; ++} ++ ++/* This is the valid maximum length argument computation for ++ strnlen/wcsnlen. See text-Xnlen-nonarray.c. */ ++static int ++maximum_length (int start_offset, int zero_count) ++{ ++ if (start_offset == buffer_length) ++ return 0; ++ else if (zero_count > 0) ++ /* Effectively unbounded, but we need to stop fairly low, ++ otherwise testing takes too long. */ ++ return buffer_length + 32; ++ else ++ return buffer_length - start_offset; ++} ++ ++typedef __typeof (TEST_IDENTIFIER) *proto_t; ++ ++#define TEST_MAIN ++#include "test-string.h" ++ ++IMPL (TEST_IDENTIFIER, 1) ++ ++static int ++test_main (void) ++{ ++ TEST_VERIFY_EXIT (sysconf (_SC_PAGESIZE) >= buffer_length); ++ test_init (); ++ ++ struct support_next_to_fault left_ntf ++ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR)); ++ CHAR *left_buffer = (CHAR *) left_ntf.buffer; ++ struct support_next_to_fault right_ntf ++ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR)); ++ CHAR *right_buffer = (CHAR *) right_ntf.buffer; ++ ++ FOR_EACH_IMPL (impl, 0) ++ { ++ printf ("info: testing %s\n", impl->name); ++ for (size_t i = 0; i < buffer_length; ++i) ++ left_buffer[i] = 'A'; ++ ++ for (int left_zero_count = 0; left_zero_count <= buffer_length; ++ ++left_zero_count) ++ { ++ if (left_zero_count > 0) ++ left_buffer[buffer_length - left_zero_count] = 0; ++ int left_a_count = buffer_length - left_zero_count; ++ for (size_t i = 0; i < buffer_length; ++i) ++ right_buffer[i] = 'A'; ++ for (int right_zero_count = 0; right_zero_count <= buffer_length; ++ ++right_zero_count) ++ { ++ if (right_zero_count > 0) ++ right_buffer[buffer_length - right_zero_count] = 0; ++ int right_a_count = buffer_length - right_zero_count; ++ for (int left_start_offset = 0; ++ left_start_offset <= buffer_length; ++ ++left_start_offset) ++ { ++ CHAR *left_start_pointer = left_buffer + left_start_offset; ++ int left_maxlen ++ = maximum_length (left_start_offset, left_zero_count); ++ int left_length ++ = string_length (left_a_count, left_start_offset); ++ for (int right_start_offset = 0; ++ right_start_offset <= buffer_length; ++ ++right_start_offset) ++ { ++ CHAR *right_start_pointer ++ = right_buffer + right_start_offset; ++ int right_maxlen ++ = maximum_length (right_start_offset, right_zero_count); ++ int right_length ++ = string_length (right_a_count, right_start_offset); ++ ++ /* Maximum length is modelled after strnlen/wcsnlen, ++ and must be valid for both pointer arguments at ++ the same time. */ ++ int maxlen = MIN (left_maxlen, right_maxlen); ++ ++ for (int length_argument = 0; length_argument <= maxlen; ++ ++length_argument) ++ { ++ if (test_verbose) ++ { ++ printf ("left: zero_count=%d" ++ " a_count=%d start_offset=%d\n", ++ left_zero_count, left_a_count, ++ left_start_offset); ++ printf ("right: zero_count=%d" ++ " a_count=%d start_offset=%d\n", ++ right_zero_count, right_a_count, ++ right_start_offset); ++ printf ("length argument: %d\n", ++ length_argument); ++ } ++ ++ /* Effective lengths bounded by length argument. ++ The effective length determines the ++ outcome of the comparison. */ ++ int left_effective ++ = MIN (left_length, length_argument); ++ int right_effective ++ = MIN (right_length, length_argument); ++ if (left_effective == right_effective) ++ TEST_COMPARE (CALL (impl, ++ left_start_pointer, ++ right_start_pointer, ++ length_argument), 0); ++ else if (left_effective < right_effective) ++ TEST_COMPARE (CALL (impl, ++ left_start_pointer, ++ right_start_pointer, ++ length_argument) < 0, 1); ++ else ++ TEST_COMPARE (CALL (impl, ++ left_start_pointer, ++ right_start_pointer, ++ length_argument) > 0, 1); ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#include +diff -Nrup a/string/test-strncmp-nonarray.c b/string/test-strncmp-nonarray.c +--- a/string/test-strncmp-nonarray.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/string/test-strncmp-nonarray.c 2024-09-03 11:52:17.707438963 -0400 +@@ -0,0 +1,4 @@ ++#define TEST_IDENTIFIER strncmp ++#define TEST_NAME "strncmp" ++typedef char CHAR; ++#include "test-Xncmp-nonarray.c" +diff -Nrup a/wcsmbs/Makefile b/wcsmbs/Makefile +--- a/wcsmbs/Makefile 2024-09-03 11:42:30.398319976 -0400 ++++ b/wcsmbs/Makefile 2024-09-03 11:53:44.806049806 -0400 +@@ -56,6 +56,10 @@ tests := tst-wcstof wcsmbs-tst1 tst-wcsn + $(addprefix test-,$(strop-tests)) tst-mbstowcs \ + test-wcsdup + ++# This test runs for a long time. ++xtests += test-wcsncmp-nonarray ++ ++ + include ../Rules + + ifeq ($(run-built-tests),yes) +diff -Nrup a/wcsmbs/test-wcsncmp-nonarray.c b/wcsmbs/test-wcsncmp-nonarray.c +--- a/wcsmbs/test-wcsncmp-nonarray.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/wcsmbs/test-wcsncmp-nonarray.c 2024-09-03 11:52:17.708438970 -0400 +@@ -0,0 +1,5 @@ ++#include ++#define TEST_IDENTIFIER wcsncmp ++#define TEST_NAME "wcsncmp" ++typedef wchar_t CHAR; ++#include "../string/test-Xncmp-nonarray.c" diff --git a/SOURCES/glibc-RHEL-50545-1.patch b/SOURCES/glibc-RHEL-50545-1.patch new file mode 100644 index 0000000..a8a3fa1 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-1.patch @@ -0,0 +1,121 @@ +From 3bfdc4e2bceb601b90c81a9baa73c1904db58b2f Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +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 + . */ + +-#define _FILE_OFFSET_BITS 64 +- + #include + #include + #include +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 + . */ + +-#define _FILE_OFFSET_BITS 64 +- + #include + #include + #include +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-50545-10.patch b/SOURCES/glibc-RHEL-50545-10.patch new file mode 100644 index 0000000..714be39 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-10.patch @@ -0,0 +1,1337 @@ +From f169509ded534537eec9df00cfada6dbca908352 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 30 Aug 2024 21:52:53 +0200 +Subject: [PATCH] support: Add FUSE-based file system test framework to + support/ +Content-type: text/plain; charset=UTF-8 + +This allows to monitor the exact file system operations +performed by glibc and inject errors. + +Hurd does not have . To get the sources to compile +at least, the same approach as in support/test-container.c is used. + +Reviewed-by: DJ Delorie + +Conflicts + support/Makefile + context +--- + support/Makefile | 2 + + support/fuse.h | 215 +++++++++++ + support/support_fuse.c | 705 +++++++++++++++++++++++++++++++++++++ + support/tst-support_fuse.c | 348 ++++++++++++++++++ + 4 files changed, 1270 insertions(+) + create mode 100644 support/fuse.h + create mode 100644 support/support_fuse.c + create mode 100644 support/tst-support_fuse.c + +diff --git a/support/Makefile b/support/Makefile +index 8fb4d2c500..93d32ae75f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -62,6 +62,7 @@ libsupport-routines = \ + support_format_herrno \ + support_format_hostent \ + support_format_netent \ ++ support_fuse \ + support_isolate_in_subprocess \ + support_need_proc \ + support_path_support_time64 \ +@@ -300,6 +301,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support_fuse \ + tst-support-open-dev-null-range \ + tst-support-process_state \ + tst-support_quote_blob \ +diff --git a/support/fuse.h b/support/fuse.h +new file mode 100644 +index 0000000000..4c365fbc0c +--- /dev/null ++++ b/support/fuse.h +@@ -0,0 +1,215 @@ ++/* Facilities for FUSE-backed file system tests. ++ 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 ++ . */ ++ ++/* Before using this functionality, use support_enter_mount_namespace ++ to ensure that mounts do not impact the overall system. */ ++ ++#ifndef SUPPORT_FUSE_H ++#define SUPPORT_FUSE_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* This function must be called furst, before support_fuse_mount, to ++ prepare unprivileged mounting. */ ++void support_fuse_init (void); ++ ++/* This function can be called instead of support_fuse_init. It does ++ not use mount and user namespaces, so it requires root privileges, ++ and cleanup after testing may be incomplete. This is intended only ++ for test development. */ ++void support_fuse_init_no_namespace (void); ++ ++/* Opaque type for tracking FUSE mount state. */ ++struct support_fuse; ++ ++/* This function disables a mount point created using ++ support_fuse_mount. */ ++void support_fuse_unmount (struct support_fuse *) __nonnull ((1)); ++ ++/* This function is called on a separate thread after calling ++ support_fuse_mount. F is the mount state, and CLOSURE the argument ++ that was passed to support_fuse_mount. The callback function is ++ expected to call support_fuse_next to read packets from the kernel ++ and handle them according to the test's need. */ ++typedef void (*support_fuse_callback) (struct support_fuse *f, void *closure); ++ ++/* This function creates a new mount point, implemented by CALLBACK. ++ CLOSURE is passed to CALLBACK as the second argument. */ ++struct support_fuse *support_fuse_mount (support_fuse_callback callback, ++ void *closure) ++ __nonnull ((1)) __attr_dealloc (support_fuse_unmount, 1); ++ ++/* This function returns the path to the mount point for F. The ++ returned string is valid until support_fuse_unmount (F) is called. */ ++const char * support_fuse_mountpoint (struct support_fuse *f) __nonnull ((1)); ++ ++ ++/* Renders the OPCODE as a string (FUSE_* constant. The caller must ++ free the returned string. */ ++char * support_fuse_opcode (uint32_t opcode) __attr_dealloc_free; ++ ++/* Use to provide a checked cast facility. Use the ++ support_fuse_in_cast macro below. */ ++void *support_fuse_cast_internal (struct fuse_in_header *, uint32_t) ++ __nonnull ((1)); ++void *support_fuse_cast_name_internal (struct fuse_in_header *, uint32_t, ++ size_t skip, char **name) ++ __nonnull ((1)); ++ ++/* The macro expansion support_fuse_in_cast (P, TYPE) casts the ++ pointer INH to the appropriate type corresponding to the FUSE_TYPE ++ opcode. It fails (terminates the process) if INH->opcode does not ++ match FUSE_TYPE. The type of the returned pointer matches that of ++ the FUSE_* constant. ++ ++ Maintenance note: Adding support for additional struct fuse_*_in ++ types is generally easy, except when there is trailing data after ++ the struct (see below for support_fuse_cast_name, for example), and ++ the kernel has changed struct sizes over time. This has happened ++ recently with struct fuse_setxattr_in, and would require special ++ handling if implemented. */ ++#define support_fuse_payload_type_INIT struct fuse_init_in ++#define support_fuse_payload_type_LOOKUP char ++#define support_fuse_payload_type_OPEN struct fuse_open_in ++#define support_fuse_payload_type_READ struct fuse_read_in ++#define support_fuse_payload_type_SETATTR struct fuse_setattr_in ++#define support_fuse_payload_type_WRITE struct fuse_write_in ++#define support_fuse_cast(typ, inh) \ ++ ((support_fuse_payload_type_##typ *) \ ++ support_fuse_cast_internal ((inh), FUSE_##typ)) ++ ++/* Same as support_fuse_cast, but also writes the passed name to *NAMEP. */ ++#define support_fuse_payload_name_type_CREATE struct fuse_create_in ++#define support_fuse_payload_name_type_MKDIR struct fuse_mkdir_in ++#define support_fuse_cast_name(typ, inh, namep) \ ++ ((support_fuse_payload_name_type_##typ *) \ ++ support_fuse_cast_name_internal \ ++ ((inh), FUSE_##typ, sizeof (support_fuse_payload_name_type_##typ), \ ++ (namep))) ++ ++/* This function should be called from the callback function. It ++ returns NULL if the mount point has been unmounted. The result can ++ be cast using support_fuse_in_cast. The pointer is invalidated ++ with the next call to support_fuse_next. ++ ++ Typical use involves handling some basics using the ++ support_fuse_handle_* building blocks, following by a switch ++ statement on the result member of the returned struct, to implement ++ what a particular test needs. Casts to payload data should be made ++ using support_fuse_in_cast. ++ ++ By default, FUSE_FORGET responses are filtered. See ++ support_fuse_filter_forget for turning that off. */ ++struct fuse_in_header *support_fuse_next (struct support_fuse *f) ++ __nonnull ((1)); ++ ++/* This function can be called from a callback function to handle ++ basic aspects of directories (OPENDIR, GETATTR, RELEASEDIR). ++ inh->nodeid is used as the inode number for the directory. This ++ function must be called after support_fuse_next. */ ++bool support_fuse_handle_directory (struct support_fuse *f) __nonnull ((1)); ++ ++/* This function can be called from a callback function to handle ++ access to the mount point itself, after call support_fuse_next. */ ++bool support_fuse_handle_mountpoint (struct support_fuse *f) __nonnull ((1)); ++ ++/* If FILTER_ENABLED, future support_fuse_next calls will not return ++ FUSE_FORGET events (and simply discared them, as they require no ++ reply). If !FILTER_ENABLED, the callback needs to handle ++ FUSE_FORGET events and call support_fuse_no_reply. */ ++void support_fuse_filter_forget (struct support_fuse *f, bool filter_enabled) ++ __nonnull ((1)); ++ ++/* This function should be called from the callback function after ++ support_fuse_next returned a non-null pointer. It sends out a ++ response packet on the FUSE device with the supplied payload data. */ ++void support_fuse_reply (struct support_fuse *f, ++ const void *payload, size_t payload_size) ++ __nonnull ((1)) __attr_access ((__read_only__, 2, 3)); ++ ++/* This function should be called from the callback function. It ++ replies to a request with an error indicator. ERROR must be positive. */ ++void support_fuse_reply_error (struct support_fuse *f, uint32_t error) ++ __nonnull ((1)); ++ ++/* This function should be called from the callback function. It ++ sends out an empty (but success-indicating) reply packet. */ ++void support_fuse_reply_empty (struct support_fuse *f) __nonnull ((1)); ++ ++/* Do not send a reply. Only to be used after a support_fuse_next ++ call that returned a FUSE_FORGET event. */ ++void support_fuse_no_reply (struct support_fuse *f) __nonnull ((1)); ++ ++/* Specific reponse preparation functions. The returned object can be ++ updated as needed. If a NODEID argument is present, it will be ++ used to set the inode and FUSE nodeid fields. Without such an ++ argument, it is initialized from the current request (if the reply ++ requires this field). This function must be called after ++ support_fuse_next. The actual response must be sent using ++ support_fuse_reply_prepared (or a support_fuse_reply_error call can ++ be used to cancel the response). */ ++struct fuse_entry_out *support_fuse_prepare_entry (struct support_fuse *f, ++ uint64_t nodeid) ++ __nonnull ((1)); ++struct fuse_attr_out *support_fuse_prepare_attr (struct support_fuse *f) ++ __nonnull ((1)); ++ ++/* Similar to the other support_fuse_prepare_* functions, but it ++ prepares for two response packets. They can be updated through the ++ pointers written to *OUT_ENTRY and *OUT_OPEN prior to calling ++ support_fuse_reply_prepared. */ ++void support_fuse_prepare_create (struct support_fuse *f, ++ uint64_t nodeid, ++ struct fuse_entry_out **out_entry, ++ struct fuse_open_out **out_open) ++ __nonnull ((1, 3, 4)); ++ ++ ++/* Prepare sending a directory stream. Must be called after ++ support_fuse_next and before support_fuse_dirstream_add. */ ++struct support_fuse_dirstream; ++struct support_fuse_dirstream *support_fuse_prepare_readdir (struct ++ support_fuse *f); ++ ++/* Adds directory using D_INO, D_OFF, D_TYPE, D_NAME to the directory ++ stream D. Must be called after support_fuse_prepare_readdir. ++ ++ D_OFF is the offset of the next directory entry, not the current ++ one. The first entry has offset zero. The first requested offset ++ can be obtained from the READ payload (struct fuse_read_in) prior ++ to calling this function. ++ ++ Returns true if the entry could be added to the buffer, or false if ++ there was insufficient room. Sending the buffer is delayed until ++ support_fuse_reply_prepared is called. */ ++bool support_fuse_dirstream_add (struct support_fuse_dirstream *d, ++ uint64_t d_ino, uint64_t d_off, ++ uint32_t d_type, ++ const char *d_name); ++ ++/* Send a prepared response. Must be called after one of the ++ support_fuse_prepare_* functions and before the next ++ support_fuse_next call. */ ++void support_fuse_reply_prepared (struct support_fuse *f) __nonnull ((1)); ++ ++#endif /* SUPPORT_FUSE_H */ +diff --git a/support/support_fuse.c b/support/support_fuse.c +new file mode 100644 +index 0000000000..135dbf1198 +--- /dev/null ++++ b/support/support_fuse.c +@@ -0,0 +1,705 @@ ++/* Facilities for FUSE-backed file system tests. ++ 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++# include ++#else ++/* Fallback definitions that mark the test as unsupported. */ ++# define mount(...) ({ FAIL_UNSUPPORTED ("mount"); -1; }) ++# define umount(...) ({ FAIL_UNSUPPORTED ("mount"); -1; }) ++#endif ++ ++struct support_fuse ++{ ++ char *mountpoint; ++ void *buffer_start; /* Begin of allocation. */ ++ void *buffer_next; /* Next read position. */ ++ void *buffer_limit; /* End of buffered data. */ ++ void *buffer_end; /* End of allocation. */ ++ struct fuse_in_header *inh; /* Most recent request (support_fuse_next). */ ++ union /* Space for prepared responses. */ ++ { ++ struct fuse_attr_out attr; ++ struct fuse_entry_out entry; ++ struct ++ { ++ struct fuse_entry_out entry; ++ struct fuse_open_out open; ++ } create; ++ } prepared; ++ void *prepared_pointer; /* NULL if inactive. */ ++ size_t prepared_size; /* 0 if inactive. */ ++ ++ /* Used for preparing readdir responses. Already used-up area for ++ the current request is counted by prepared_size. */ ++ void *readdir_buffer; ++ size_t readdir_buffer_size; ++ ++ pthread_t handler; /* Thread handling requests. */ ++ uid_t uid; /* Cached value for the current process. */ ++ uid_t gid; /* Cached value for the current process. */ ++ int fd; /* FUSE file descriptor. */ ++ int connection; /* Entry under /sys/fs/fuse/connections. */ ++ bool filter_forget; /* Controls FUSE_FORGET event dropping. */ ++ _Atomic bool disconnected; ++}; ++ ++struct fuse_thread_wrapper_args ++{ ++ struct support_fuse *f; ++ support_fuse_callback callback; ++ void *closure; ++}; ++ ++/* Set by support_fuse_init to indicate that support_fuse_mount may be ++ called. */ ++static bool support_fuse_init_called; ++ ++/* Allocate the read buffer in F with SIZE bytes capacity. Does not ++ free the previously allocated buffer. */ ++static void support_fuse_allocate (struct support_fuse *f, size_t size) ++ __nonnull ((1)); ++ ++/* Internal mkdtemp replacement */ ++static char * support_fuse_mkdir (const char *prefix) __nonnull ((1)); ++ ++/* Low-level allocation function for support_fuse_mount. Does not ++ perform the mount. */ ++static struct support_fuse *support_fuse_open (void); ++ ++/* Thread wrapper function for use with pthread_create. Uses struct ++ fuse_thread_wrapper_args. */ ++static void *support_fuse_thread_wrapper (void *closure) __nonnull ((1)); ++ ++/* Initial step before preparing a reply. SIZE must be the size of ++ the F->prepared member that is going to be used. */ ++static void support_fuse_prepare_1 (struct support_fuse *f, size_t size); ++ ++/* Similar to support_fuse_reply_error, but not check that ERROR is ++ not zero. */ ++static void support_fuse_reply_error_1 (struct support_fuse *f, ++ uint32_t error) __nonnull ((1)); ++ ++/* Path to the directory containing mount points. Initialized by an ++ ELF constructor. All mountpoints are collected there so that the ++ test wrapper can clean them up without keeping track of them ++ individually. */ ++static char *support_fuse_mountpoints; ++ ++/* PID of the process that should clean up the mount points in the ELF ++ destructor. */ ++static pid_t support_fuse_cleanup_pid; ++ ++static void ++support_fuse_allocate (struct support_fuse *f, size_t size) ++{ ++ f->buffer_start = xmalloc (size); ++ f->buffer_end = f->buffer_start + size; ++ f->buffer_limit = f->buffer_start; ++ f->buffer_next = f->buffer_limit; ++} ++ ++void ++support_fuse_filter_forget (struct support_fuse *f, bool filter) ++{ ++ f->filter_forget = filter; ++} ++ ++void * ++support_fuse_cast_internal (struct fuse_in_header *p, uint32_t expected) ++{ ++ if (expected != p->opcode ++ && !(expected == FUSE_READ && p->opcode == FUSE_READDIR)) ++ { ++ char *expected1 = support_fuse_opcode (expected); ++ char *actual = support_fuse_opcode (p->opcode); ++ FAIL_EXIT1 ("attempt to cast %s to %s", actual, expected1); ++ } ++ return p + 1; ++} ++ ++void * ++support_fuse_cast_name_internal (struct fuse_in_header *p, uint32_t expected, ++ size_t skip, char **name) ++{ ++ char *result = support_fuse_cast_internal (p, expected); ++ *name = result + skip; ++ return result; ++} ++ ++bool ++support_fuse_dirstream_add (struct support_fuse_dirstream *d, ++ uint64_t d_ino, uint64_t d_off, ++ uint32_t d_type, const char *d_name) ++{ ++ struct support_fuse *f = (struct support_fuse *) d; ++ size_t structlen = offsetof (struct fuse_dirent, name); ++ size_t namelen = strlen (d_name); /* No null termination. */ ++ size_t required_size = FUSE_DIRENT_ALIGN (structlen + namelen); ++ if (f->readdir_buffer_size - f->prepared_size < required_size) ++ return false; ++ struct fuse_dirent entry = ++ { ++ .ino = d_ino, ++ .off = d_off, ++ .type = d_type, ++ .namelen = namelen, ++ }; ++ memcpy (f->readdir_buffer + f->prepared_size, &entry, structlen); ++ /* Use strncpy to write padding and avoid passing uninitialized ++ bytes to the read system call. */ ++ strncpy (f->readdir_buffer + f->prepared_size + structlen, d_name, ++ required_size - structlen); ++ f->prepared_size += required_size; ++ return true; ++} ++ ++bool ++support_fuse_handle_directory (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ switch (f->inh->opcode) ++ { ++ case FUSE_OPENDIR: ++ { ++ struct fuse_open_out out = ++ { ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ return true; ++ case FUSE_RELEASEDIR: ++ support_fuse_reply_empty (f); ++ return true; ++ case FUSE_GETATTR: ++ { ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFDIR | 0700; ++ support_fuse_reply_prepared (f); ++ } ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool ++support_fuse_handle_mountpoint (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ /* 1 is the root node. */ ++ if (f->inh->opcode == FUSE_GETATTR && f->inh->nodeid == 1) ++ return support_fuse_handle_directory (f); ++ return false; ++} ++ ++void ++support_fuse_init (void) ++{ ++ support_fuse_init_called = true; ++ ++ support_become_root (); ++ if (!support_enter_mount_namespace ()) ++ FAIL_UNSUPPORTED ("mount namespaces not supported"); ++} ++ ++void ++support_fuse_init_no_namespace (void) ++{ ++ support_fuse_init_called = true; ++} ++ ++static char * ++support_fuse_mkdir (const char *prefix) ++{ ++ /* Do not use mkdtemp to avoid interfering with its tests. */ ++ unsigned int counter = 1; ++ unsigned int pid = getpid (); ++ while (true) ++ { ++ char *path = xasprintf ("%s%u.%u/", prefix, pid, counter); ++ if (mkdir (path, 0700) == 0) ++ return path; ++ if (errno != EEXIST) ++ FAIL_EXIT1 ("mkdir (\"%s\"): %m", path); ++ free (path); ++ ++counter; ++ } ++} ++ ++struct support_fuse * ++support_fuse_mount (support_fuse_callback callback, void *closure) ++{ ++ TEST_VERIFY_EXIT (support_fuse_init_called); ++ ++ /* Request at least minor version 12 because it changed struct sizes. */ ++ enum { min_version = 12 }; ++ ++ struct support_fuse *f = support_fuse_open (); ++ char *mount_options ++ = xasprintf ("fd=%d,rootmode=040700,user_id=%u,group_id=%u", ++ f->fd, f->uid, f->gid); ++ if (mount ("fuse", f->mountpoint, "fuse.glibc", ++ MS_NOSUID|MS_NODEV, mount_options) ++ != 0) ++ FAIL_EXIT1 ("FUSE mount on %s: %m", f->mountpoint); ++ free (mount_options); ++ ++ /* Retry with an older FUSE version. */ ++ while (true) ++ { ++ struct fuse_in_header *inh = support_fuse_next (f); ++ struct fuse_init_in *init_in = support_fuse_cast (INIT, inh); ++ if (init_in->major < 7 ++ || (init_in->major == 7 && init_in->minor < min_version)) ++ FAIL_UNSUPPORTED ("kernel FUSE version is %u.%u, too old", ++ init_in->major, init_in->minor); ++ if (init_in->major > 7) ++ { ++ uint32_t major = 7; ++ support_fuse_reply (f, &major, sizeof (major)); ++ continue; ++ } ++ TEST_VERIFY (init_in->flags & FUSE_DONT_MASK); ++ struct fuse_init_out out = ++ { ++ .major = 7, ++ .minor = min_version, ++ /* Request that the kernel does not apply umask. */ ++ .flags = FUSE_DONT_MASK, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ ++ { ++ struct fuse_thread_wrapper_args args = ++ { ++ .f = f, ++ .callback = callback, ++ .closure = closure, ++ }; ++ f->handler = xpthread_create (NULL, ++ support_fuse_thread_wrapper, &args); ++ struct stat64 st; ++ xstat64 (f->mountpoint, &st); ++ f->connection = minor (st.st_dev); ++ /* Got a reply from the thread, safe to deallocate args. */ ++ } ++ ++ return f; ++ } ++} ++ ++const char * ++support_fuse_mountpoint (struct support_fuse *f) ++{ ++ return f->mountpoint; ++} ++ ++void ++support_fuse_no_reply (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ TEST_COMPARE (f->inh->opcode, FUSE_FORGET); ++ f->inh = NULL; ++} ++ ++char * ++support_fuse_opcode (uint32_t op) ++{ ++ const char *result; ++ switch (op) ++ { ++#define X(n) case n: result = #n; break ++ X(FUSE_LOOKUP); ++ X(FUSE_FORGET); ++ X(FUSE_GETATTR); ++ X(FUSE_SETATTR); ++ X(FUSE_READLINK); ++ X(FUSE_SYMLINK); ++ X(FUSE_MKNOD); ++ X(FUSE_MKDIR); ++ X(FUSE_UNLINK); ++ X(FUSE_RMDIR); ++ X(FUSE_RENAME); ++ X(FUSE_LINK); ++ X(FUSE_OPEN); ++ X(FUSE_READ); ++ X(FUSE_WRITE); ++ X(FUSE_STATFS); ++ X(FUSE_RELEASE); ++ X(FUSE_FSYNC); ++ X(FUSE_SETXATTR); ++ X(FUSE_GETXATTR); ++ X(FUSE_LISTXATTR); ++ X(FUSE_REMOVEXATTR); ++ X(FUSE_FLUSH); ++ X(FUSE_INIT); ++ X(FUSE_OPENDIR); ++ X(FUSE_READDIR); ++ X(FUSE_RELEASEDIR); ++ X(FUSE_FSYNCDIR); ++ X(FUSE_GETLK); ++ X(FUSE_SETLK); ++ X(FUSE_SETLKW); ++ X(FUSE_ACCESS); ++ X(FUSE_CREATE); ++ X(FUSE_INTERRUPT); ++ X(FUSE_BMAP); ++ X(FUSE_DESTROY); ++ X(FUSE_IOCTL); ++ X(FUSE_POLL); ++ X(FUSE_NOTIFY_REPLY); ++ X(FUSE_BATCH_FORGET); ++ X(FUSE_FALLOCATE); ++ X(FUSE_READDIRPLUS); ++ X(FUSE_RENAME2); ++ X(FUSE_LSEEK); ++ X(FUSE_COPY_FILE_RANGE); ++ X(FUSE_SETUPMAPPING); ++ X(FUSE_REMOVEMAPPING); ++ X(FUSE_SYNCFS); ++ X(FUSE_TMPFILE); ++ X(FUSE_STATX); ++#undef X ++ default: ++ return xasprintf ("FUSE_unknown_%u", op); ++ } ++ return xstrdup (result); ++} ++ ++static struct support_fuse * ++support_fuse_open (void) ++{ ++ struct support_fuse *result = xmalloc (sizeof (*result)); ++ result->mountpoint = support_fuse_mkdir (support_fuse_mountpoints); ++ result->inh = NULL; ++ result->prepared_pointer = NULL; ++ result->prepared_size = 0; ++ result->readdir_buffer = NULL; ++ result->readdir_buffer_size = 0; ++ result->uid = getuid (); ++ result->gid = getgid (); ++ result->fd = open ("/dev/fuse", O_RDWR, 0); ++ if (result->fd < 0) ++ { ++ if (errno == ENOENT || errno == ENODEV || errno == EPERM ++ || errno == EACCES) ++ FAIL_UNSUPPORTED ("cannot open /dev/fuse: %m"); ++ else ++ FAIL_EXIT1 ("cannot open /dev/fuse: %m"); ++ } ++ result->connection = -1; ++ result->filter_forget = true; ++ result->disconnected = false; ++ support_fuse_allocate (result, FUSE_MIN_READ_BUFFER); ++ return result; ++} ++ ++static void ++support_fuse_prepare_1 (struct support_fuse *f, size_t size) ++{ ++ TEST_VERIFY (f->prepared_pointer == NULL); ++ f->prepared_size = size; ++ memset (&f->prepared, 0, size); ++ f->prepared_pointer = &f->prepared; ++} ++ ++struct fuse_attr_out * ++support_fuse_prepare_attr (struct support_fuse *f) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.attr)); ++ f->prepared.attr.attr.uid = f->uid; ++ f->prepared.attr.attr.gid = f->gid; ++ f->prepared.attr.attr.ino = f->inh->nodeid; ++ return &f->prepared.attr; ++} ++ ++void ++support_fuse_prepare_create (struct support_fuse *f, ++ uint64_t nodeid, ++ struct fuse_entry_out **out_entry, ++ struct fuse_open_out **out_open) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.create)); ++ f->prepared.create.entry.nodeid = nodeid; ++ f->prepared.create.entry.attr.uid = f->uid; ++ f->prepared.create.entry.attr.gid = f->gid; ++ f->prepared.create.entry.attr.ino = nodeid; ++ *out_entry = &f->prepared.create.entry; ++ *out_open = &f->prepared.create.open; ++} ++ ++struct fuse_entry_out * ++support_fuse_prepare_entry (struct support_fuse *f, uint64_t nodeid) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.entry)); ++ f->prepared.entry.nodeid = nodeid; ++ f->prepared.entry.attr.uid = f->uid; ++ f->prepared.entry.attr.gid = f->gid; ++ f->prepared.entry.attr.ino = nodeid; ++ return &f->prepared.entry; ++} ++ ++struct support_fuse_dirstream * ++support_fuse_prepare_readdir (struct support_fuse *f) ++{ ++ support_fuse_prepare_1 (f, 0); ++ struct fuse_read_in *p = support_fuse_cast (READ, f->inh); ++ if (p->size > f->readdir_buffer_size) ++ { ++ free (f->readdir_buffer); ++ f->readdir_buffer = xmalloc (p->size); ++ f->readdir_buffer_size = p->size; ++ } ++ f->prepared_pointer = f->readdir_buffer; ++ return (struct support_fuse_dirstream *) f; ++} ++ ++struct fuse_in_header * ++support_fuse_next (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh == NULL); ++ while (true) ++ { ++ if (f->buffer_next < f->buffer_limit) ++ { ++ f->inh = f->buffer_next; ++ f->buffer_next = (void *) f->buffer_next + f->inh->len; ++ /* Suppress FUSE_FORGET responses if requested. */ ++ if (f->filter_forget && f->inh->opcode == FUSE_FORGET) ++ { ++ f->inh = NULL; ++ continue; ++ } ++ return f->inh; ++ } ++ ssize_t ret = read (f->fd, f->buffer_start, ++ f->buffer_end - f->buffer_start); ++ if (ret == 0) ++ FAIL_EXIT (1, "unexpected EOF on FUSE device"); ++ if (ret < 0 && errno == EINVAL) ++ { ++ /* Increase buffer size. */ ++ size_t new_size = 2 * (size_t) (f->buffer_end - f->buffer_start); ++ free (f->buffer_start); ++ support_fuse_allocate (f, new_size); ++ continue; ++ } ++ if (ret < 0) ++ { ++ if (f->disconnected) ++ /* Unmount detected. */ ++ return NULL; ++ FAIL_EXIT1 ("read error on FUSE device: %m"); ++ } ++ /* Read was successful, make [next, limit) the active buffer area. */ ++ f->buffer_next = f->buffer_start; ++ f->buffer_limit = (void *) f->buffer_start + ret; ++ } ++} ++ ++void ++support_fuse_reply (struct support_fuse *f, ++ const void *payload, size_t payload_size) ++{ ++ TEST_VERIFY_EXIT (f->inh != NULL); ++ TEST_VERIFY (f->prepared_pointer == NULL); ++ struct fuse_out_header outh = ++ { ++ .len = sizeof (outh) + payload_size, ++ .unique = f->inh->unique, ++ }; ++ struct iovec iov[] = ++ { ++ { &outh, sizeof (outh) }, ++ { (void *) payload, payload_size }, ++ }; ++ ssize_t ret = writev (f->fd, iov, array_length (iov)); ++ if (ret < 0) ++ { ++ if (!f->disconnected) ++ /* Some kernels produce write errors upon disconnect. */ ++ FAIL_EXIT1 ("FUSE write failed for %s response" ++ " (%zu bytes payload): %m", ++ support_fuse_opcode (f->inh->opcode), payload_size); ++ } ++ else if (ret != sizeof (outh) + payload_size) ++ FAIL_EXIT1 ("FUSE write short for %s response (%zu bytes payload):" ++ " %zd bytes", ++ support_fuse_opcode (f->inh->opcode), payload_size, ret); ++ f->inh = NULL; ++} ++ ++void ++support_fuse_reply_empty (struct support_fuse *f) ++{ ++ support_fuse_reply_error_1 (f, 0); ++} ++ ++static void ++support_fuse_reply_error_1 (struct support_fuse *f, uint32_t error) ++{ ++ TEST_VERIFY_EXIT (f->inh != NULL); ++ struct fuse_out_header outh = ++ { ++ .len = sizeof (outh), ++ .error = -error, ++ .unique = f->inh->unique, ++ }; ++ ssize_t ret = write (f->fd, &outh, sizeof (outh)); ++ if (ret < 0) ++ { ++ /* Some kernels produce write errors upon disconnect. */ ++ if (!f->disconnected) ++ FAIL_EXIT1 ("FUSE write failed for %s error response: %m", ++ support_fuse_opcode (f->inh->opcode)); ++ } ++ else if (ret != sizeof (outh)) ++ FAIL_EXIT1 ("FUSE write short for %s error response: %zd bytes", ++ support_fuse_opcode (f->inh->opcode), ret); ++ f->inh = NULL; ++ f->prepared_pointer = NULL; ++ f->prepared_size = 0; ++} ++ ++void ++support_fuse_reply_error (struct support_fuse *f, uint32_t error) ++{ ++ TEST_VERIFY (error > 0); ++ support_fuse_reply_error_1 (f, error); ++} ++ ++void ++support_fuse_reply_prepared (struct support_fuse *f) ++{ ++ TEST_VERIFY_EXIT (f->prepared_pointer != NULL); ++ /* Re-use the non-prepared reply function. It requires ++ f->prepared_* to be non-null, so reset the fields before the call. */ ++ void *prepared_pointer = f->prepared_pointer; ++ size_t prepared_size = f->prepared_size; ++ f->prepared_pointer = NULL; ++ f->prepared_size = 0; ++ support_fuse_reply (f, prepared_pointer, prepared_size); ++} ++ ++static void * ++support_fuse_thread_wrapper (void *closure) ++{ ++ struct fuse_thread_wrapper_args args ++ = *(struct fuse_thread_wrapper_args *) closure; ++ ++ /* Handle the initial stat call. */ ++ struct fuse_in_header *inh = support_fuse_next (args.f); ++ if (inh == NULL || !support_fuse_handle_mountpoint (args.f)) ++ { ++ support_fuse_reply_error (args.f, EIO); ++ return NULL; ++ } ++ ++ args.callback (args.f, args.closure); ++ return NULL; ++} ++ ++void ++support_fuse_unmount (struct support_fuse *f) ++{ ++ /* Signal the unmount to the handler thread. Some kernels report ++ not just ENODEV errors on read. */ ++ f->disconnected = true; ++ ++ { ++ char *path = xasprintf ("/sys/fs/fuse/connections/%d/abort", ++ f->connection); ++ /* Some kernels do not support these files under /sys. */ ++ int fd = open (path, O_RDWR | O_TRUNC); ++ if (fd >= 0) ++ { ++ TEST_COMPARE (write (fd, "1", 1), 1); ++ xclose (fd); ++ } ++ free (path); ++ } ++ if (umount (f->mountpoint) != 0) ++ FAIL ("FUSE: umount (\"%s\"): %m", f->mountpoint); ++ xpthread_join (f->handler); ++ if (rmdir (f->mountpoint) != 0) ++ FAIL ("FUSE: rmdir (\"%s\"): %m", f->mountpoint); ++ xclose (f->fd); ++ free (f->mountpoint); ++ free (f->readdir_buffer); ++ free (f); ++} ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ /* The test_dir test driver variable is not yet set at this point. */ ++ const char *tmpdir = getenv ("TMPDIR"); ++ if (tmpdir == NULL || tmpdir[0] == '\0') ++ tmpdir = "/tmp"; ++ ++ char *prefix = xasprintf ("%s/glibc-tst-fuse.", tmpdir); ++ support_fuse_mountpoints = support_fuse_mkdir (prefix); ++ free (prefix); ++ support_fuse_cleanup_pid = getpid (); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (support_fuse_cleanup_pid != getpid () ++ || support_fuse_mountpoints == NULL) ++ return; ++ DIR *dir = xopendir (support_fuse_mountpoints); ++ while (true) ++ { ++ struct dirent64 *e = readdir64 (dir); ++ if (e == NULL) ++ /* Ignore errors. */ ++ break; ++ if (*e->d_name == '.') ++ /* Skip "." and "..". No hidden files expected. */ ++ continue; ++ if (unlinkat (dirfd (dir), e->d_name, AT_REMOVEDIR) != 0) ++ break; ++ rewinddir (dir); ++ } ++ xclosedir (dir); ++ rmdir (support_fuse_mountpoints); ++ free (support_fuse_mountpoints); ++ support_fuse_mountpoints = NULL; ++} +diff --git a/support/tst-support_fuse.c b/support/tst-support_fuse.c +new file mode 100644 +index 0000000000..c4075a6608 +--- /dev/null ++++ b/support/tst-support_fuse.c +@@ -0,0 +1,348 @@ ++/* Facilities for FUSE-backed file system tests. ++ 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ /* Turn on returning FUSE_FORGET responses. */ ++ support_fuse_filter_forget (f, false); ++ ++ /* Inode and nodeid for "file" and "new". */ ++ enum { NODE_FILE = 2, NODE_NEW, NODE_SUBDIR, NODE_SYMLINK }; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ { ++ char *opcode = support_fuse_opcode (inh->opcode); ++ printf ("info: (T) event %s(%llu) len=%u nodeid=%llu\n", ++ opcode, (unsigned long long int) inh->unique, inh->len, ++ (unsigned long long int) inh->nodeid); ++ free (opcode); ++ } ++ ++ /* Handle mountpoint and basic directory operation for the root (1). */ ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_READDIR: ++ /* Implementation of getdents64. */ ++ if (inh->nodeid == 1) ++ { ++ struct support_fuse_dirstream *d ++ = support_fuse_prepare_readdir (f); ++ TEST_COMPARE (support_fuse_cast (READ, inh)->offset, 0); ++ TEST_VERIFY (support_fuse_dirstream_add (d, 1, 1, DT_DIR, ".")); ++ TEST_VERIFY (support_fuse_dirstream_add (d, 1, 2, DT_DIR, "..")); ++ TEST_VERIFY (support_fuse_dirstream_add (d, NODE_FILE, 3, DT_REG, ++ "file")); ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_LOOKUP: ++ /* Part of the implementation of open. */ ++ { ++ char *name = support_fuse_cast (LOOKUP, inh); ++ printf (" name: %s\n", name); ++ if (inh->nodeid == 1 && strcmp (name, "file") == 0) ++ { ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_FILE); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else if (inh->nodeid == 1 && strcmp (name, "symlink") == 0) ++ { ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_SYMLINK); ++ out->attr.mode = S_IFLNK | 0777; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ } ++ break; ++ case FUSE_OPEN: ++ /* Implementation of open. */ ++ { ++ struct fuse_open_in *p = support_fuse_cast (OPEN, inh); ++ if (inh->nodeid == NODE_FILE) ++ { ++ TEST_VERIFY (!(p->flags & O_EXCL)); ++ struct fuse_open_out out = { 0, }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ } ++ break; ++ case FUSE_GETATTR: ++ /* Happens after open. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | 0600; ++ out->attr.size = strlen ("Hello, world!"); ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ break; ++ case FUSE_READ: ++ /* Implementation of read. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_read_in *p = support_fuse_cast (READ, inh); ++ TEST_COMPARE (p->offset, 0); ++ TEST_VERIFY (p->size >= strlen ("Hello, world!")); ++ support_fuse_reply (f, ++ "Hello, world!", strlen ("Hello, world!")); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_FLUSH: ++ /* Sent in response to close. */ ++ support_fuse_reply_empty (f); ++ break; ++ case FUSE_GETXATTR: ++ /* This happens as part of a open-for-write operation. ++ Signal no support for extended attributes. */ ++ support_fuse_reply_error (f, ENOSYS); ++ break; ++ case FUSE_SETATTR: ++ /* This happens as part of a open-for-write operation to ++ implement O_TRUNC. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_setattr_in *p = support_fuse_cast (SETATTR, inh); ++ /* FATTR_LOCKOWNER may also be set. */ ++ TEST_COMPARE ((p->valid) & ~ FATTR_LOCKOWNER, FATTR_SIZE); ++ TEST_COMPARE (p->size, 0); ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_WRITE: ++ /* Implementation of write. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_write_in *p = support_fuse_cast (WRITE, inh); ++ TEST_COMPARE (p->offset, 0); ++ /* Write payload follows after struct fuse_write_in. */ ++ TEST_COMPARE_BLOB (p + 1, p->size, ++ "Good day to you too.", ++ strlen ("Good day to you too.")); ++ struct fuse_write_out out = ++ { ++ .size = p->size, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_CREATE: ++ /* Implementation of O_CREAT. */ ++ if (inh->nodeid == 1) ++ { ++ char *name; ++ struct fuse_create_in *p ++ = support_fuse_cast_name (CREATE, inh, &name); ++ TEST_VERIFY (S_ISREG (p->mode)); ++ TEST_COMPARE (p->mode & 07777, 0600); ++ TEST_COMPARE_STRING (name, "new"); ++ struct fuse_entry_out *out_entry; ++ struct fuse_open_out *out_open; ++ support_fuse_prepare_create (f, NODE_NEW, &out_entry, &out_open); ++ out_entry->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_MKDIR: ++ /* Implementation of mkdir. */ ++ { ++ if (inh->nodeid == 1) ++ { ++ char *name; ++ struct fuse_mkdir_in *p ++ = support_fuse_cast_name (MKDIR, inh, &name); ++ TEST_COMPARE (p->mode, 01234); ++ TEST_COMPARE_STRING (name, "subdir"); ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_SUBDIR); ++ out->attr.mode = S_IFDIR | p->mode; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ } ++ break; ++ case FUSE_READLINK: ++ /* Implementation of readlink. */ ++ TEST_COMPARE (inh->nodeid, NODE_SYMLINK); ++ if (inh->nodeid == NODE_SYMLINK) ++ support_fuse_reply (f, "target-of-symbolic-link", ++ strlen ("target-of-symbolic-link")); ++ else ++ support_fuse_reply_error (f, EINVAL); ++ break; ++ case FUSE_FORGET: ++ support_fuse_no_reply (f); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ ++ printf ("info: Attributes of mountpoint/root directory %s\n", ++ support_fuse_mountpoint (f)); ++ { ++ struct statx st; ++ xstatx (AT_FDCWD, support_fuse_mountpoint (f), 0, STATX_BASIC_STATS, &st); ++ TEST_COMPARE (st.stx_uid, getuid ()); ++ TEST_COMPARE (st.stx_gid, getgid ()); ++ TEST_VERIFY (S_ISDIR (st.stx_mode)); ++ TEST_COMPARE (st.stx_mode & 07777, 0700); ++ } ++ ++ printf ("info: List directory %s\n", support_fuse_mountpoint (f)); ++ { ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ ++ struct dirent *e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 1); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 1); ++#endif ++ TEST_COMPARE (e->d_type, DT_DIR); ++ TEST_COMPARE_STRING (e->d_name, "."); ++ ++ e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 1); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 2); ++#endif ++ TEST_COMPARE (e->d_type, DT_DIR); ++ TEST_COMPARE_STRING (e->d_name, ".."); ++ ++ e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 2); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 3); ++#endif ++ TEST_COMPARE (e->d_type, DT_REG); ++ TEST_COMPARE_STRING (e->d_name, "file"); ++ ++ TEST_COMPARE (closedir (dir), 0); ++ } ++ ++ char *file_path = xasprintf ("%s/file", support_fuse_mountpoint (f)); ++ ++ printf ("info: Attributes of file %s\n", file_path); ++ { ++ struct statx st; ++ xstatx (AT_FDCWD, file_path, 0, STATX_BASIC_STATS, &st); ++ TEST_COMPARE (st.stx_uid, getuid ()); ++ TEST_COMPARE (st.stx_gid, getgid ()); ++ TEST_VERIFY (S_ISREG (st.stx_mode)); ++ TEST_COMPARE (st.stx_mode & 07777, 0600); ++ TEST_COMPARE (st.stx_size, strlen ("Hello, world!")); ++ } ++ ++ printf ("info: Read from %s\n", file_path); ++ { ++ int fd = xopen (file_path, O_RDONLY, 0); ++ char buf[64]; ++ ssize_t len = read (fd, buf, sizeof (buf)); ++ if (len < 0) ++ FAIL_EXIT1 ("read: %m"); ++ TEST_COMPARE_BLOB (buf, len, "Hello, world!", strlen ("Hello, world!")); ++ xclose (fd); ++ } ++ ++ printf ("info: Write to %s\n", file_path); ++ { ++ int fd = xopen (file_path, O_WRONLY | O_TRUNC, 0); ++ xwrite (fd, "Good day to you too.", strlen ("Good day to you too.")); ++ xclose (fd); ++ } ++ ++ printf ("info: Attempt O_EXCL creation of existing %s\n", file_path); ++ /* O_EXCL creation shall fail. */ ++ errno = 0; ++ TEST_COMPARE (open64 (file_path, O_RDWR | O_EXCL | O_CREAT, 0600), -1); ++ TEST_COMPARE (errno, EEXIST); ++ ++ free (file_path); ++ ++ { ++ char *new_path = xasprintf ("%s/new", support_fuse_mountpoint (f)); ++ printf ("info: Test successful O_EXCL creation at %s\n", new_path); ++ int fd = xopen (new_path, O_RDWR | O_EXCL | O_CREAT, 0600); ++ xclose (fd); ++ free (new_path); ++ } ++ ++ { ++ char *subdir_path = xasprintf ("%s/subdir", support_fuse_mountpoint (f)); ++ xmkdir (subdir_path, 01234); ++ } ++ ++ { ++ char *symlink_path = xasprintf ("%s/symlink", support_fuse_mountpoint (f)); ++ char *target = xreadlink (symlink_path); ++ TEST_COMPARE_STRING (target, "target-of-symbolic-link"); ++ free (target); ++ free (symlink_path); ++ } ++ ++ support_fuse_unmount (f); ++ return 0; ++} ++ ++#include +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-50545-11.patch b/SOURCES/glibc-RHEL-50545-11.patch new file mode 100644 index 0000000..4681971 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-11.patch @@ -0,0 +1,501 @@ +From e3db0a699c639e97deddcb15939fd9c162801c77 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + +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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 *) ¤t, 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 +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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-50545-12.patch b/SOURCES/glibc-RHEL-50545-12.patch new file mode 100644 index 0000000..a54cff9 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-12.patch @@ -0,0 +1,40 @@ +From 455c7622835d16c79e49fe75b8d3a1ae59a3d0ee Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + diff --git a/SOURCES/glibc-RHEL-50545-13.patch b/SOURCES/glibc-RHEL-50545-13.patch new file mode 100644 index 0000000..59b5f29 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-13.patch @@ -0,0 +1,32 @@ +From 366cce74d2aa2e5753d8787d415b745fd57fda04 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Sat, 21 Sep 2024 19:29:13 +0200 +Subject: [PATCH] support: Add valgrind instructions to +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 + . */ + +-/* 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 + diff --git a/SOURCES/glibc-RHEL-50545-14.patch b/SOURCES/glibc-RHEL-50545-14.patch new file mode 100644 index 0000000..c2674d1 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-14.patch @@ -0,0 +1,24 @@ +From 3ef26b708725b528a1c69ab3eb523036c50b89d6 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + diff --git a/SOURCES/glibc-RHEL-50545-2.patch b/SOURCES/glibc-RHEL-50545-2.patch new file mode 100644 index 0000000..b392625 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-2.patch @@ -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?= +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 +--- + 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 + #include + ++#include ++ + #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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include ++#include + + #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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + ++#include ++ + 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 + ++#include ++ + 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 + ++#include ++ + 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 + #include + ++#include ++ + 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 + #include + ++#include ++ + 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 + #include + ++#include ++ + 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 + #include + ++#include ++ + #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 + #include + ++#include + + 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 + #include + ++#include ++ + 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 + #include + ++#include ++ + #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 + #include + ++#include ++ + 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 + #include + ++#include ++ + 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 + #include + ++#include ++ + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include + + 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 + #include + ++#include ++ + /* 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 + diff --git a/SOURCES/glibc-RHEL-50545-3.patch b/SOURCES/glibc-RHEL-50545-3.patch new file mode 100644 index 0000000..076b7f7 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-3.patch @@ -0,0 +1,30 @@ +From 34bb581e7713589d38c797c214f4c6bf2b14b702 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 16 Aug 2024 16:05:19 +0200 +Subject: [PATCH] support: Include 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 +--- + 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 + #include + #include ++#include + #include + #include + +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-50545-4.patch b/SOURCES/glibc-RHEL-50545-4.patch new file mode 100644 index 0000000..612e0ec --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-4.patch @@ -0,0 +1,91 @@ +From 921690512946d73bf66a8c495baff31316e4489f Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + +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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++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 + diff --git a/SOURCES/glibc-RHEL-50545-5.patch b/SOURCES/glibc-RHEL-50545-5.patch new file mode 100644 index 0000000..b1b9e6a --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-5.patch @@ -0,0 +1,410 @@ +From bf2927484152e12996af60ea439cf94b66fcd81d Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 +--- + 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 + #include ++#include + #include + +-#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 + #include ++#include + #include + #include + +-#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 + #include + +-#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 + #include ++#include + #include + #include + +-#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 + #include + #include ++#include + #include + +-#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 + #include + +-#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 + #include ++#include + #include + #include + #include + +-#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 + diff --git a/SOURCES/glibc-RHEL-50545-6.patch b/SOURCES/glibc-RHEL-50545-6.patch new file mode 100644 index 0000000..ea404be --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-6.patch @@ -0,0 +1,452 @@ +From e7c14e542d8d858b824b5df4f4e3dc93695e6171 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + +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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-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 + #include +-#include + + 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 + #include +-#include + + 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#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 + diff --git a/SOURCES/glibc-RHEL-50545-7.patch b/SOURCES/glibc-RHEL-50545-7.patch new file mode 100644 index 0000000..b07088e --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-7.patch @@ -0,0 +1,47 @@ +From 34e52acd55d69964d14fb3188c5538442b8b32be Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 +--- + 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 @@ + . */ + + #include ++#include + #include ++#include + #include + + 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 + diff --git a/SOURCES/glibc-RHEL-50545-8.patch b/SOURCES/glibc-RHEL-50545-8.patch new file mode 100644 index 0000000..e6d036a --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-8.patch @@ -0,0 +1,1661 @@ +From b09a520bb6d98d465818aadfd0641751ce824053 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 30 Aug 2024 21:51:46 +0200 +Subject: [PATCH] Bundle userspace header from Linux 6.10 +Content-type: text/plain; charset=UTF-8 + +And include the required licensing information. The only +change is a removed trailing empty line in +LICENSES/exceptions/Linux-syscall-note. + +Bundling is the recommended way to deal with +the evolution of the FUSE userspace interface because +structs change sizes over time. The kernel maintains +compatibility, but source-level compatibility on recompilation +may require additional code that is aware of older struct sizes. + +Signed-off-by: Florian Weimer +Reviewed-by: DJ Delorie +--- + support/bundled/README | 5 + + support/bundled/linux/COPYING | 20 + + .../LICENSES/exceptions/Linux-syscall-note | 24 + + .../bundled/linux/LICENSES/preferred/GPL-2.0 | 359 +++++ + .../bundled/linux/include/uapi/linux/fuse.h | 1189 +++++++++++++++++ + 5 files changed, 1597 insertions(+) + create mode 100644 support/bundled/README + create mode 100644 support/bundled/linux/COPYING + create mode 100644 support/bundled/linux/LICENSES/exceptions/Linux-syscall-note + create mode 100644 support/bundled/linux/LICENSES/preferred/GPL-2.0 + create mode 100644 support/bundled/linux/include/uapi/linux/fuse.h + +diff --git a/support/bundled/README b/support/bundled/README +new file mode 100644 +index 0000000000..e861b3d40a +--- /dev/null ++++ b/support/bundled/README +@@ -0,0 +1,5 @@ ++This subtree contains bundled files included verbatim from other ++sources. They are used for building the support/ infrastructure. ++ ++linux/ ++ Select files from the Linux 6.10 source tree. +diff --git a/support/bundled/linux/COPYING b/support/bundled/linux/COPYING +new file mode 100644 +index 0000000000..a635a38ef9 +--- /dev/null ++++ b/support/bundled/linux/COPYING +@@ -0,0 +1,20 @@ ++The Linux Kernel is provided under: ++ ++ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++ ++Being under the terms of the GNU General Public License version 2 only, ++according with: ++ ++ LICENSES/preferred/GPL-2.0 ++ ++With an explicit syscall exception, as stated at: ++ ++ LICENSES/exceptions/Linux-syscall-note ++ ++In addition, other licenses may also apply. Please see: ++ ++ Documentation/process/license-rules.rst ++ ++for more details. ++ ++All contributions to the Linux Kernel are subject to this COPYING file. +diff --git a/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note b/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note +new file mode 100644 +index 0000000000..adbe756a05 +--- /dev/null ++++ b/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note +@@ -0,0 +1,24 @@ ++SPDX-Exception-Identifier: Linux-syscall-note ++SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html ++SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+, GPL-2.0-only, GPL-2.0-or-later ++Usage-Guide: ++ This exception is used together with one of the above SPDX-Licenses ++ to mark user space API (uapi) header files so they can be included ++ into non GPL compliant user space application code. ++ To use this exception add it with the keyword WITH to one of the ++ identifiers in the SPDX-Licenses tag: ++ SPDX-License-Identifier: WITH Linux-syscall-note ++License-Text: ++ ++ NOTE! This copyright does *not* cover user programs that use kernel ++ services by normal system calls - this is merely considered normal use ++ of the kernel, and does *not* fall under the heading of "derived work". ++ Also note that the GPL below is copyrighted by the Free Software ++ Foundation, but the instance of code that it refers to (the Linux ++ kernel) is copyrighted by me and others who actually wrote it. ++ ++ Also note that the only valid version of the GPL as far as the kernel ++ is concerned is _this_ particular version of the license (ie v2, not ++ v2.2 or v3.x or whatever), unless explicitly otherwise stated. ++ ++ Linus Torvalds +diff --git a/support/bundled/linux/LICENSES/preferred/GPL-2.0 b/support/bundled/linux/LICENSES/preferred/GPL-2.0 +new file mode 100644 +index 0000000000..ff0812fd89 +--- /dev/null ++++ b/support/bundled/linux/LICENSES/preferred/GPL-2.0 +@@ -0,0 +1,359 @@ ++Valid-License-Identifier: GPL-2.0 ++Valid-License-Identifier: GPL-2.0-only ++Valid-License-Identifier: GPL-2.0+ ++Valid-License-Identifier: GPL-2.0-or-later ++SPDX-URL: https://spdx.org/licenses/GPL-2.0.html ++Usage-Guide: ++ To use this license in source code, put one of the following SPDX ++ tag/value pairs into a comment according to the placement ++ guidelines in the licensing rules documentation. ++ For 'GNU General Public License (GPL) version 2 only' use: ++ SPDX-License-Identifier: GPL-2.0 ++ or ++ SPDX-License-Identifier: GPL-2.0-only ++ For 'GNU General Public License (GPL) version 2 or any later version' use: ++ SPDX-License-Identifier: GPL-2.0+ ++ or ++ SPDX-License-Identifier: GPL-2.0-or-later ++License-Text: ++ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) year name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff --git a/support/bundled/linux/include/uapi/linux/fuse.h b/support/bundled/linux/include/uapi/linux/fuse.h +new file mode 100644 +index 0000000000..d08b99d60f +--- /dev/null ++++ b/support/bundled/linux/include/uapi/linux/fuse.h +@@ -0,0 +1,1189 @@ ++/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */ ++/* ++ This file defines the kernel interface of FUSE ++ Copyright (C) 2001-2008 Miklos Szeredi ++ ++ This program can be distributed under the terms of the GNU GPL. ++ See the file COPYING. ++ ++ This -- and only this -- header file may also be distributed under ++ the terms of the BSD Licence as follows: ++ ++ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ 1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ ++ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE ++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ SUCH DAMAGE. ++*/ ++ ++/* ++ * This file defines the kernel interface of FUSE ++ * ++ * Protocol changelog: ++ * ++ * 7.1: ++ * - add the following messages: ++ * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK, ++ * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE, ++ * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR, ++ * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR, ++ * FUSE_RELEASEDIR ++ * - add padding to messages to accommodate 32-bit servers on 64-bit kernels ++ * ++ * 7.2: ++ * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags ++ * - add FUSE_FSYNCDIR message ++ * ++ * 7.3: ++ * - add FUSE_ACCESS message ++ * - add FUSE_CREATE message ++ * - add filehandle to fuse_setattr_in ++ * ++ * 7.4: ++ * - add frsize to fuse_kstatfs ++ * - clean up request size limit checking ++ * ++ * 7.5: ++ * - add flags and max_write to fuse_init_out ++ * ++ * 7.6: ++ * - add max_readahead to fuse_init_in and fuse_init_out ++ * ++ * 7.7: ++ * - add FUSE_INTERRUPT message ++ * - add POSIX file lock support ++ * ++ * 7.8: ++ * - add lock_owner and flags fields to fuse_release_in ++ * - add FUSE_BMAP message ++ * - add FUSE_DESTROY message ++ * ++ * 7.9: ++ * - new fuse_getattr_in input argument of GETATTR ++ * - add lk_flags in fuse_lk_in ++ * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in ++ * - add blksize field to fuse_attr ++ * - add file flags field to fuse_read_in and fuse_write_in ++ * - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in ++ * ++ * 7.10 ++ * - add nonseekable open flag ++ * ++ * 7.11 ++ * - add IOCTL message ++ * - add unsolicited notification support ++ * - add POLL message and NOTIFY_POLL notification ++ * ++ * 7.12 ++ * - add umask flag to input argument of create, mknod and mkdir ++ * - add notification messages for invalidation of inodes and ++ * directory entries ++ * ++ * 7.13 ++ * - make max number of background requests and congestion threshold ++ * tunables ++ * ++ * 7.14 ++ * - add splice support to fuse device ++ * ++ * 7.15 ++ * - add store notify ++ * - add retrieve notify ++ * ++ * 7.16 ++ * - add BATCH_FORGET request ++ * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct ++ * fuse_ioctl_iovec' instead of ambiguous 'struct iovec' ++ * - add FUSE_IOCTL_32BIT flag ++ * ++ * 7.17 ++ * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK ++ * ++ * 7.18 ++ * - add FUSE_IOCTL_DIR flag ++ * - add FUSE_NOTIFY_DELETE ++ * ++ * 7.19 ++ * - add FUSE_FALLOCATE ++ * ++ * 7.20 ++ * - add FUSE_AUTO_INVAL_DATA ++ * ++ * 7.21 ++ * - add FUSE_READDIRPLUS ++ * - send the requested events in POLL request ++ * ++ * 7.22 ++ * - add FUSE_ASYNC_DIO ++ * ++ * 7.23 ++ * - add FUSE_WRITEBACK_CACHE ++ * - add time_gran to fuse_init_out ++ * - add reserved space to fuse_init_out ++ * - add FATTR_CTIME ++ * - add ctime and ctimensec to fuse_setattr_in ++ * - add FUSE_RENAME2 request ++ * - add FUSE_NO_OPEN_SUPPORT flag ++ * ++ * 7.24 ++ * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support ++ * ++ * 7.25 ++ * - add FUSE_PARALLEL_DIROPS ++ * ++ * 7.26 ++ * - add FUSE_HANDLE_KILLPRIV ++ * - add FUSE_POSIX_ACL ++ * ++ * 7.27 ++ * - add FUSE_ABORT_ERROR ++ * ++ * 7.28 ++ * - add FUSE_COPY_FILE_RANGE ++ * - add FOPEN_CACHE_DIR ++ * - add FUSE_MAX_PAGES, add max_pages to init_out ++ * - add FUSE_CACHE_SYMLINKS ++ * ++ * 7.29 ++ * - add FUSE_NO_OPENDIR_SUPPORT flag ++ * ++ * 7.30 ++ * - add FUSE_EXPLICIT_INVAL_DATA ++ * - add FUSE_IOCTL_COMPAT_X32 ++ * ++ * 7.31 ++ * - add FUSE_WRITE_KILL_PRIV flag ++ * - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING ++ * - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag ++ * ++ * 7.32 ++ * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS ++ * ++ * 7.33 ++ * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID ++ * - add FUSE_OPEN_KILL_SUIDGID ++ * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT ++ * - add FUSE_SETXATTR_ACL_KILL_SGID ++ * ++ * 7.34 ++ * - add FUSE_SYNCFS ++ * ++ * 7.35 ++ * - add FOPEN_NOFLUSH ++ * ++ * 7.36 ++ * - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag ++ * - add flags2 to fuse_init_in and fuse_init_out ++ * - add FUSE_SECURITY_CTX init flag ++ * - add security context to create, mkdir, symlink, and mknod requests ++ * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX ++ * ++ * 7.37 ++ * - add FUSE_TMPFILE ++ * ++ * 7.38 ++ * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry ++ * - add FOPEN_PARALLEL_DIRECT_WRITES ++ * - add total_extlen to fuse_in_header ++ * - add FUSE_MAX_NR_SECCTX ++ * - add extension header ++ * - add FUSE_EXT_GROUPS ++ * - add FUSE_CREATE_SUPP_GROUP ++ * - add FUSE_HAS_EXPIRE_ONLY ++ * ++ * 7.39 ++ * - add FUSE_DIRECT_IO_ALLOW_MMAP ++ * - add FUSE_STATX and related structures ++ * ++ * 7.40 ++ * - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag ++ * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag ++ * - add FUSE_NO_EXPORT_SUPPORT init flag ++ * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag ++ */ ++ ++#ifndef _LINUX_FUSE_H ++#define _LINUX_FUSE_H ++ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#endif ++ ++/* ++ * Version negotiation: ++ * ++ * Both the kernel and userspace send the version they support in the ++ * INIT request and reply respectively. ++ * ++ * If the major versions match then both shall use the smallest ++ * of the two minor versions for communication. ++ * ++ * If the kernel supports a larger major version, then userspace shall ++ * reply with the major version it supports, ignore the rest of the ++ * INIT message and expect a new INIT message from the kernel with a ++ * matching major version. ++ * ++ * If the library supports a larger major version, then it shall fall ++ * back to the major protocol version sent by the kernel for ++ * communication and reply with that major version (and an arbitrary ++ * supported minor version). ++ */ ++ ++/** Version number of this interface */ ++#define FUSE_KERNEL_VERSION 7 ++ ++/** Minor version number of this interface */ ++#define FUSE_KERNEL_MINOR_VERSION 40 ++ ++/** The node ID of the root inode */ ++#define FUSE_ROOT_ID 1 ++ ++/* Make sure all structures are padded to 64bit boundary, so 32bit ++ userspace works under 64bit kernels */ ++ ++struct fuse_attr { ++ uint64_t ino; ++ uint64_t size; ++ uint64_t blocks; ++ uint64_t atime; ++ uint64_t mtime; ++ uint64_t ctime; ++ uint32_t atimensec; ++ uint32_t mtimensec; ++ uint32_t ctimensec; ++ uint32_t mode; ++ uint32_t nlink; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t rdev; ++ uint32_t blksize; ++ uint32_t flags; ++}; ++ ++/* ++ * The following structures are bit-for-bit compatible with the statx(2) ABI in ++ * Linux. ++ */ ++struct fuse_sx_time { ++ int64_t tv_sec; ++ uint32_t tv_nsec; ++ int32_t __reserved; ++}; ++ ++struct fuse_statx { ++ uint32_t mask; ++ uint32_t blksize; ++ uint64_t attributes; ++ uint32_t nlink; ++ uint32_t uid; ++ uint32_t gid; ++ uint16_t mode; ++ uint16_t __spare0[1]; ++ uint64_t ino; ++ uint64_t size; ++ uint64_t blocks; ++ uint64_t attributes_mask; ++ struct fuse_sx_time atime; ++ struct fuse_sx_time btime; ++ struct fuse_sx_time ctime; ++ struct fuse_sx_time mtime; ++ uint32_t rdev_major; ++ uint32_t rdev_minor; ++ uint32_t dev_major; ++ uint32_t dev_minor; ++ uint64_t __spare2[14]; ++}; ++ ++struct fuse_kstatfs { ++ uint64_t blocks; ++ uint64_t bfree; ++ uint64_t bavail; ++ uint64_t files; ++ uint64_t ffree; ++ uint32_t bsize; ++ uint32_t namelen; ++ uint32_t frsize; ++ uint32_t padding; ++ uint32_t spare[6]; ++}; ++ ++struct fuse_file_lock { ++ uint64_t start; ++ uint64_t end; ++ uint32_t type; ++ uint32_t pid; /* tgid */ ++}; ++ ++/** ++ * Bitmasks for fuse_setattr_in.valid ++ */ ++#define FATTR_MODE (1 << 0) ++#define FATTR_UID (1 << 1) ++#define FATTR_GID (1 << 2) ++#define FATTR_SIZE (1 << 3) ++#define FATTR_ATIME (1 << 4) ++#define FATTR_MTIME (1 << 5) ++#define FATTR_FH (1 << 6) ++#define FATTR_ATIME_NOW (1 << 7) ++#define FATTR_MTIME_NOW (1 << 8) ++#define FATTR_LOCKOWNER (1 << 9) ++#define FATTR_CTIME (1 << 10) ++#define FATTR_KILL_SUIDGID (1 << 11) ++ ++/** ++ * Flags returned by the OPEN request ++ * ++ * FOPEN_DIRECT_IO: bypass page cache for this open file ++ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open ++ * FOPEN_NONSEEKABLE: the file is not seekable ++ * FOPEN_CACHE_DIR: allow caching this directory ++ * FOPEN_STREAM: the file is stream-like (no file position at all) ++ * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE) ++ * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode ++ * FOPEN_PASSTHROUGH: passthrough read/write io for this open file ++ */ ++#define FOPEN_DIRECT_IO (1 << 0) ++#define FOPEN_KEEP_CACHE (1 << 1) ++#define FOPEN_NONSEEKABLE (1 << 2) ++#define FOPEN_CACHE_DIR (1 << 3) ++#define FOPEN_STREAM (1 << 4) ++#define FOPEN_NOFLUSH (1 << 5) ++#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6) ++#define FOPEN_PASSTHROUGH (1 << 7) ++ ++/** ++ * INIT request/reply flags ++ * ++ * FUSE_ASYNC_READ: asynchronous read requests ++ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks ++ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported) ++ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem ++ * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." ++ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB ++ * FUSE_DONT_MASK: don't apply umask to file mode on create operations ++ * FUSE_SPLICE_WRITE: kernel supports splice write on the device ++ * FUSE_SPLICE_MOVE: kernel supports splice move on the device ++ * FUSE_SPLICE_READ: kernel supports splice read on the device ++ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks ++ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories ++ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages ++ * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) ++ * FUSE_READDIRPLUS_AUTO: adaptive readdirplus ++ * FUSE_ASYNC_DIO: asynchronous direct I/O submission ++ * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes ++ * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens ++ * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir ++ * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc ++ * FUSE_POSIX_ACL: filesystem supports posix acls ++ * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED ++ * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages ++ * FUSE_CACHE_SYMLINKS: cache READLINK responses ++ * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir ++ * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request ++ * FUSE_MAP_ALIGNMENT: init_out.map_alignment contains log2(byte alignment) for ++ * foffset and moffset fields in struct ++ * fuse_setupmapping_out and fuse_removemapping_one. ++ * FUSE_SUBMOUNTS: kernel supports auto-mounting directory submounts ++ * FUSE_HANDLE_KILLPRIV_V2: fs kills suid/sgid/cap on write/chown/trunc. ++ * Upon write/truncate suid/sgid is only killed if caller ++ * does not have CAP_FSETID. Additionally upon ++ * write/truncate sgid is killed only if file has group ++ * execute permission. (Same as Linux VFS behavior). ++ * FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in ++ * FUSE_INIT_EXT: extended fuse_init_in request ++ * FUSE_INIT_RESERVED: reserved, do not use ++ * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and ++ * mknod ++ * FUSE_HAS_INODE_DAX: use per inode DAX ++ * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, ++ * symlink and mknod (single group that matches parent) ++ * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation ++ * FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode. ++ * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support ++ * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit ++ * of the request ID indicates resend requests ++ */ ++#define FUSE_ASYNC_READ (1 << 0) ++#define FUSE_POSIX_LOCKS (1 << 1) ++#define FUSE_FILE_OPS (1 << 2) ++#define FUSE_ATOMIC_O_TRUNC (1 << 3) ++#define FUSE_EXPORT_SUPPORT (1 << 4) ++#define FUSE_BIG_WRITES (1 << 5) ++#define FUSE_DONT_MASK (1 << 6) ++#define FUSE_SPLICE_WRITE (1 << 7) ++#define FUSE_SPLICE_MOVE (1 << 8) ++#define FUSE_SPLICE_READ (1 << 9) ++#define FUSE_FLOCK_LOCKS (1 << 10) ++#define FUSE_HAS_IOCTL_DIR (1 << 11) ++#define FUSE_AUTO_INVAL_DATA (1 << 12) ++#define FUSE_DO_READDIRPLUS (1 << 13) ++#define FUSE_READDIRPLUS_AUTO (1 << 14) ++#define FUSE_ASYNC_DIO (1 << 15) ++#define FUSE_WRITEBACK_CACHE (1 << 16) ++#define FUSE_NO_OPEN_SUPPORT (1 << 17) ++#define FUSE_PARALLEL_DIROPS (1 << 18) ++#define FUSE_HANDLE_KILLPRIV (1 << 19) ++#define FUSE_POSIX_ACL (1 << 20) ++#define FUSE_ABORT_ERROR (1 << 21) ++#define FUSE_MAX_PAGES (1 << 22) ++#define FUSE_CACHE_SYMLINKS (1 << 23) ++#define FUSE_NO_OPENDIR_SUPPORT (1 << 24) ++#define FUSE_EXPLICIT_INVAL_DATA (1 << 25) ++#define FUSE_MAP_ALIGNMENT (1 << 26) ++#define FUSE_SUBMOUNTS (1 << 27) ++#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28) ++#define FUSE_SETXATTR_EXT (1 << 29) ++#define FUSE_INIT_EXT (1 << 30) ++#define FUSE_INIT_RESERVED (1 << 31) ++/* bits 32..63 get shifted down 32 bits into the flags2 field */ ++#define FUSE_SECURITY_CTX (1ULL << 32) ++#define FUSE_HAS_INODE_DAX (1ULL << 33) ++#define FUSE_CREATE_SUPP_GROUP (1ULL << 34) ++#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) ++#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36) ++#define FUSE_PASSTHROUGH (1ULL << 37) ++#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38) ++#define FUSE_HAS_RESEND (1ULL << 39) ++ ++/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */ ++#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP ++ ++/** ++ * CUSE INIT request/reply flags ++ * ++ * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl ++ */ ++#define CUSE_UNRESTRICTED_IOCTL (1 << 0) ++ ++/** ++ * Release flags ++ */ ++#define FUSE_RELEASE_FLUSH (1 << 0) ++#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1) ++ ++/** ++ * Getattr flags ++ */ ++#define FUSE_GETATTR_FH (1 << 0) ++ ++/** ++ * Lock flags ++ */ ++#define FUSE_LK_FLOCK (1 << 0) ++ ++/** ++ * WRITE flags ++ * ++ * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed ++ * FUSE_WRITE_LOCKOWNER: lock_owner field is valid ++ * FUSE_WRITE_KILL_SUIDGID: kill suid and sgid bits ++ */ ++#define FUSE_WRITE_CACHE (1 << 0) ++#define FUSE_WRITE_LOCKOWNER (1 << 1) ++#define FUSE_WRITE_KILL_SUIDGID (1 << 2) ++ ++/* Obsolete alias; this flag implies killing suid/sgid only. */ ++#define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID ++ ++/** ++ * Read flags ++ */ ++#define FUSE_READ_LOCKOWNER (1 << 1) ++ ++/** ++ * Ioctl flags ++ * ++ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine ++ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed ++ * FUSE_IOCTL_RETRY: retry with new iovecs ++ * FUSE_IOCTL_32BIT: 32bit ioctl ++ * FUSE_IOCTL_DIR: is a directory ++ * FUSE_IOCTL_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t) ++ * ++ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs ++ */ ++#define FUSE_IOCTL_COMPAT (1 << 0) ++#define FUSE_IOCTL_UNRESTRICTED (1 << 1) ++#define FUSE_IOCTL_RETRY (1 << 2) ++#define FUSE_IOCTL_32BIT (1 << 3) ++#define FUSE_IOCTL_DIR (1 << 4) ++#define FUSE_IOCTL_COMPAT_X32 (1 << 5) ++ ++#define FUSE_IOCTL_MAX_IOV 256 ++ ++/** ++ * Poll flags ++ * ++ * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify ++ */ ++#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) ++ ++/** ++ * Fsync flags ++ * ++ * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata ++ */ ++#define FUSE_FSYNC_FDATASYNC (1 << 0) ++ ++/** ++ * fuse_attr flags ++ * ++ * FUSE_ATTR_SUBMOUNT: Object is a submount root ++ * FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode ++ */ ++#define FUSE_ATTR_SUBMOUNT (1 << 0) ++#define FUSE_ATTR_DAX (1 << 1) ++ ++/** ++ * Open flags ++ * FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable ++ */ ++#define FUSE_OPEN_KILL_SUIDGID (1 << 0) ++ ++/** ++ * setxattr flags ++ * FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set ++ */ ++#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0) ++ ++/** ++ * notify_inval_entry flags ++ * FUSE_EXPIRE_ONLY ++ */ ++#define FUSE_EXPIRE_ONLY (1 << 0) ++ ++/** ++ * extension type ++ * FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx ++ * FUSE_EXT_GROUPS: &fuse_supp_groups extension ++ */ ++enum fuse_ext_type { ++ /* Types 0..31 are reserved for fuse_secctx_header */ ++ FUSE_MAX_NR_SECCTX = 31, ++ FUSE_EXT_GROUPS = 32, ++}; ++ ++enum fuse_opcode { ++ FUSE_LOOKUP = 1, ++ FUSE_FORGET = 2, /* no reply */ ++ FUSE_GETATTR = 3, ++ FUSE_SETATTR = 4, ++ FUSE_READLINK = 5, ++ FUSE_SYMLINK = 6, ++ FUSE_MKNOD = 8, ++ FUSE_MKDIR = 9, ++ FUSE_UNLINK = 10, ++ FUSE_RMDIR = 11, ++ FUSE_RENAME = 12, ++ FUSE_LINK = 13, ++ FUSE_OPEN = 14, ++ FUSE_READ = 15, ++ FUSE_WRITE = 16, ++ FUSE_STATFS = 17, ++ FUSE_RELEASE = 18, ++ FUSE_FSYNC = 20, ++ FUSE_SETXATTR = 21, ++ FUSE_GETXATTR = 22, ++ FUSE_LISTXATTR = 23, ++ FUSE_REMOVEXATTR = 24, ++ FUSE_FLUSH = 25, ++ FUSE_INIT = 26, ++ FUSE_OPENDIR = 27, ++ FUSE_READDIR = 28, ++ FUSE_RELEASEDIR = 29, ++ FUSE_FSYNCDIR = 30, ++ FUSE_GETLK = 31, ++ FUSE_SETLK = 32, ++ FUSE_SETLKW = 33, ++ FUSE_ACCESS = 34, ++ FUSE_CREATE = 35, ++ FUSE_INTERRUPT = 36, ++ FUSE_BMAP = 37, ++ FUSE_DESTROY = 38, ++ FUSE_IOCTL = 39, ++ FUSE_POLL = 40, ++ FUSE_NOTIFY_REPLY = 41, ++ FUSE_BATCH_FORGET = 42, ++ FUSE_FALLOCATE = 43, ++ FUSE_READDIRPLUS = 44, ++ FUSE_RENAME2 = 45, ++ FUSE_LSEEK = 46, ++ FUSE_COPY_FILE_RANGE = 47, ++ FUSE_SETUPMAPPING = 48, ++ FUSE_REMOVEMAPPING = 49, ++ FUSE_SYNCFS = 50, ++ FUSE_TMPFILE = 51, ++ FUSE_STATX = 52, ++ ++ /* CUSE specific operations */ ++ CUSE_INIT = 4096, ++ ++ /* Reserved opcodes: helpful to detect structure endian-ness */ ++ CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */ ++ FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */ ++}; ++ ++enum fuse_notify_code { ++ FUSE_NOTIFY_POLL = 1, ++ FUSE_NOTIFY_INVAL_INODE = 2, ++ FUSE_NOTIFY_INVAL_ENTRY = 3, ++ FUSE_NOTIFY_STORE = 4, ++ FUSE_NOTIFY_RETRIEVE = 5, ++ FUSE_NOTIFY_DELETE = 6, ++ FUSE_NOTIFY_RESEND = 7, ++ FUSE_NOTIFY_CODE_MAX, ++}; ++ ++/* The read buffer is required to be at least 8k, but may be much larger */ ++#define FUSE_MIN_READ_BUFFER 8192 ++ ++#define FUSE_COMPAT_ENTRY_OUT_SIZE 120 ++ ++struct fuse_entry_out { ++ uint64_t nodeid; /* Inode ID */ ++ uint64_t generation; /* Inode generation: nodeid:gen must ++ be unique for the fs's lifetime */ ++ uint64_t entry_valid; /* Cache timeout for the name */ ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t entry_valid_nsec; ++ uint32_t attr_valid_nsec; ++ struct fuse_attr attr; ++}; ++ ++struct fuse_forget_in { ++ uint64_t nlookup; ++}; ++ ++struct fuse_forget_one { ++ uint64_t nodeid; ++ uint64_t nlookup; ++}; ++ ++struct fuse_batch_forget_in { ++ uint32_t count; ++ uint32_t dummy; ++}; ++ ++struct fuse_getattr_in { ++ uint32_t getattr_flags; ++ uint32_t dummy; ++ uint64_t fh; ++}; ++ ++#define FUSE_COMPAT_ATTR_OUT_SIZE 96 ++ ++struct fuse_attr_out { ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t attr_valid_nsec; ++ uint32_t dummy; ++ struct fuse_attr attr; ++}; ++ ++struct fuse_statx_in { ++ uint32_t getattr_flags; ++ uint32_t reserved; ++ uint64_t fh; ++ uint32_t sx_flags; ++ uint32_t sx_mask; ++}; ++ ++struct fuse_statx_out { ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t attr_valid_nsec; ++ uint32_t flags; ++ uint64_t spare[2]; ++ struct fuse_statx stat; ++}; ++ ++#define FUSE_COMPAT_MKNOD_IN_SIZE 8 ++ ++struct fuse_mknod_in { ++ uint32_t mode; ++ uint32_t rdev; ++ uint32_t umask; ++ uint32_t padding; ++}; ++ ++struct fuse_mkdir_in { ++ uint32_t mode; ++ uint32_t umask; ++}; ++ ++struct fuse_rename_in { ++ uint64_t newdir; ++}; ++ ++struct fuse_rename2_in { ++ uint64_t newdir; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++struct fuse_link_in { ++ uint64_t oldnodeid; ++}; ++ ++struct fuse_setattr_in { ++ uint32_t valid; ++ uint32_t padding; ++ uint64_t fh; ++ uint64_t size; ++ uint64_t lock_owner; ++ uint64_t atime; ++ uint64_t mtime; ++ uint64_t ctime; ++ uint32_t atimensec; ++ uint32_t mtimensec; ++ uint32_t ctimensec; ++ uint32_t mode; ++ uint32_t unused4; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t unused5; ++}; ++ ++struct fuse_open_in { ++ uint32_t flags; ++ uint32_t open_flags; /* FUSE_OPEN_... */ ++}; ++ ++struct fuse_create_in { ++ uint32_t flags; ++ uint32_t mode; ++ uint32_t umask; ++ uint32_t open_flags; /* FUSE_OPEN_... */ ++}; ++ ++struct fuse_open_out { ++ uint64_t fh; ++ uint32_t open_flags; ++ int32_t backing_id; ++}; ++ ++struct fuse_release_in { ++ uint64_t fh; ++ uint32_t flags; ++ uint32_t release_flags; ++ uint64_t lock_owner; ++}; ++ ++struct fuse_flush_in { ++ uint64_t fh; ++ uint32_t unused; ++ uint32_t padding; ++ uint64_t lock_owner; ++}; ++ ++struct fuse_read_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t read_flags; ++ uint64_t lock_owner; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_WRITE_IN_SIZE 24 ++ ++struct fuse_write_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t write_flags; ++ uint64_t lock_owner; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++struct fuse_write_out { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_STATFS_SIZE 48 ++ ++struct fuse_statfs_out { ++ struct fuse_kstatfs st; ++}; ++ ++struct fuse_fsync_in { ++ uint64_t fh; ++ uint32_t fsync_flags; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_SETXATTR_IN_SIZE 8 ++ ++struct fuse_setxattr_in { ++ uint32_t size; ++ uint32_t flags; ++ uint32_t setxattr_flags; ++ uint32_t padding; ++}; ++ ++struct fuse_getxattr_in { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_getxattr_out { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_lk_in { ++ uint64_t fh; ++ uint64_t owner; ++ struct fuse_file_lock lk; ++ uint32_t lk_flags; ++ uint32_t padding; ++}; ++ ++struct fuse_lk_out { ++ struct fuse_file_lock lk; ++}; ++ ++struct fuse_access_in { ++ uint32_t mask; ++ uint32_t padding; ++}; ++ ++struct fuse_init_in { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t max_readahead; ++ uint32_t flags; ++ uint32_t flags2; ++ uint32_t unused[11]; ++}; ++ ++#define FUSE_COMPAT_INIT_OUT_SIZE 8 ++#define FUSE_COMPAT_22_INIT_OUT_SIZE 24 ++ ++struct fuse_init_out { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t max_readahead; ++ uint32_t flags; ++ uint16_t max_background; ++ uint16_t congestion_threshold; ++ uint32_t max_write; ++ uint32_t time_gran; ++ uint16_t max_pages; ++ uint16_t map_alignment; ++ uint32_t flags2; ++ uint32_t max_stack_depth; ++ uint32_t unused[6]; ++}; ++ ++#define CUSE_INIT_INFO_MAX 4096 ++ ++struct cuse_init_in { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t unused; ++ uint32_t flags; ++}; ++ ++struct cuse_init_out { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t unused; ++ uint32_t flags; ++ uint32_t max_read; ++ uint32_t max_write; ++ uint32_t dev_major; /* chardev major */ ++ uint32_t dev_minor; /* chardev minor */ ++ uint32_t spare[10]; ++}; ++ ++struct fuse_interrupt_in { ++ uint64_t unique; ++}; ++ ++struct fuse_bmap_in { ++ uint64_t block; ++ uint32_t blocksize; ++ uint32_t padding; ++}; ++ ++struct fuse_bmap_out { ++ uint64_t block; ++}; ++ ++struct fuse_ioctl_in { ++ uint64_t fh; ++ uint32_t flags; ++ uint32_t cmd; ++ uint64_t arg; ++ uint32_t in_size; ++ uint32_t out_size; ++}; ++ ++struct fuse_ioctl_iovec { ++ uint64_t base; ++ uint64_t len; ++}; ++ ++struct fuse_ioctl_out { ++ int32_t result; ++ uint32_t flags; ++ uint32_t in_iovs; ++ uint32_t out_iovs; ++}; ++ ++struct fuse_poll_in { ++ uint64_t fh; ++ uint64_t kh; ++ uint32_t flags; ++ uint32_t events; ++}; ++ ++struct fuse_poll_out { ++ uint32_t revents; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_poll_wakeup_out { ++ uint64_t kh; ++}; ++ ++struct fuse_fallocate_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint64_t length; ++ uint32_t mode; ++ uint32_t padding; ++}; ++ ++/** ++ * FUSE request unique ID flag ++ * ++ * Indicates whether this is a resend request. The receiver should handle this ++ * request accordingly. ++ */ ++#define FUSE_UNIQUE_RESEND (1ULL << 63) ++ ++struct fuse_in_header { ++ uint32_t len; ++ uint32_t opcode; ++ uint64_t unique; ++ uint64_t nodeid; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t pid; ++ uint16_t total_extlen; /* length of extensions in 8byte units */ ++ uint16_t padding; ++}; ++ ++struct fuse_out_header { ++ uint32_t len; ++ int32_t error; ++ uint64_t unique; ++}; ++ ++struct fuse_dirent { ++ uint64_t ino; ++ uint64_t off; ++ uint32_t namelen; ++ uint32_t type; ++ char name[]; ++}; ++ ++/* Align variable length records to 64bit boundary */ ++#define FUSE_REC_ALIGN(x) \ ++ (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) ++ ++#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) ++#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x) ++#define FUSE_DIRENT_SIZE(d) \ ++ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) ++ ++struct fuse_direntplus { ++ struct fuse_entry_out entry_out; ++ struct fuse_dirent dirent; ++}; ++ ++#define FUSE_NAME_OFFSET_DIRENTPLUS \ ++ offsetof(struct fuse_direntplus, dirent.name) ++#define FUSE_DIRENTPLUS_SIZE(d) \ ++ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen) ++ ++struct fuse_notify_inval_inode_out { ++ uint64_t ino; ++ int64_t off; ++ int64_t len; ++}; ++ ++struct fuse_notify_inval_entry_out { ++ uint64_t parent; ++ uint32_t namelen; ++ uint32_t flags; ++}; ++ ++struct fuse_notify_delete_out { ++ uint64_t parent; ++ uint64_t child; ++ uint32_t namelen; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_store_out { ++ uint64_t nodeid; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_retrieve_out { ++ uint64_t notify_unique; ++ uint64_t nodeid; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++/* Matches the size of fuse_write_in */ ++struct fuse_notify_retrieve_in { ++ uint64_t dummy1; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t dummy2; ++ uint64_t dummy3; ++ uint64_t dummy4; ++}; ++ ++struct fuse_backing_map { ++ int32_t fd; ++ uint32_t flags; ++ uint64_t padding; ++}; ++ ++/* Device ioctls: */ ++#define FUSE_DEV_IOC_MAGIC 229 ++#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) ++#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \ ++ struct fuse_backing_map) ++#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t) ++ ++struct fuse_lseek_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t whence; ++ uint32_t padding; ++}; ++ ++struct fuse_lseek_out { ++ uint64_t offset; ++}; ++ ++struct fuse_copy_file_range_in { ++ uint64_t fh_in; ++ uint64_t off_in; ++ uint64_t nodeid_out; ++ uint64_t fh_out; ++ uint64_t off_out; ++ uint64_t len; ++ uint64_t flags; ++}; ++ ++#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0) ++#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1) ++struct fuse_setupmapping_in { ++ /* An already open handle */ ++ uint64_t fh; ++ /* Offset into the file to start the mapping */ ++ uint64_t foffset; ++ /* Length of mapping required */ ++ uint64_t len; ++ /* Flags, FUSE_SETUPMAPPING_FLAG_* */ ++ uint64_t flags; ++ /* Offset in Memory Window */ ++ uint64_t moffset; ++}; ++ ++struct fuse_removemapping_in { ++ /* number of fuse_removemapping_one follows */ ++ uint32_t count; ++}; ++ ++struct fuse_removemapping_one { ++ /* Offset into the dax window start the unmapping */ ++ uint64_t moffset; ++ /* Length of mapping required */ ++ uint64_t len; ++}; ++ ++#define FUSE_REMOVEMAPPING_MAX_ENTRY \ ++ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) ++ ++struct fuse_syncfs_in { ++ uint64_t padding; ++}; ++ ++/* ++ * For each security context, send fuse_secctx with size of security context ++ * fuse_secctx will be followed by security context name and this in turn ++ * will be followed by actual context label. ++ * fuse_secctx, name, context ++ */ ++struct fuse_secctx { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++/* ++ * Contains the information about how many fuse_secctx structures are being ++ * sent and what's the total size of all security contexts (including ++ * size of fuse_secctx_header). ++ * ++ */ ++struct fuse_secctx_header { ++ uint32_t size; ++ uint32_t nr_secctx; ++}; ++ ++/** ++ * struct fuse_ext_header - extension header ++ * @size: total size of this extension including this header ++ * @type: type of extension ++ * ++ * This is made compatible with fuse_secctx_header by using type values > ++ * FUSE_MAX_NR_SECCTX ++ */ ++struct fuse_ext_header { ++ uint32_t size; ++ uint32_t type; ++}; ++ ++/** ++ * struct fuse_supp_groups - Supplementary group extension ++ * @nr_groups: number of supplementary groups ++ * @groups: flexible array of group IDs ++ */ ++struct fuse_supp_groups { ++ uint32_t nr_groups; ++ uint32_t groups[]; ++}; ++ ++#endif /* _LINUX_FUSE_H */ +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-50545-9.patch b/SOURCES/glibc-RHEL-50545-9.patch new file mode 100644 index 0000000..4127da1 --- /dev/null +++ b/SOURCES/glibc-RHEL-50545-9.patch @@ -0,0 +1,438 @@ +From 3b1d32177635023e37bec7fbfd77c3cfb2659eb1 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 30 Aug 2024 21:52:10 +0200 +Subject: [PATCH] support: Add +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 + +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 ++ . */ ++ ++#include ++ ++#include ++ ++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 ++ . */ ++ ++#include ++ ++#include ++ ++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 ++ 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++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 +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 ++ . */ ++ ++#include ++ ++#include ++ ++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 ++ 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 ++ . */ ++ ++#ifndef SUPPORT_XDIRENT_H ++#define SUPPORT_XDIRENT_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++__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 ++ . */ ++ ++#include ++ ++#include ++ ++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 ++ . */ ++ ++#include ++ ++#include ++ ++DIR * ++xopendir (const char *path) ++{ ++ DIR *result = opendir (path); ++ if (result == NULL) ++ FAIL_EXIT1 ("opendir (\"%s\"): %m", path); ++ return result; ++} +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-50548-1.patch b/SOURCES/glibc-RHEL-50548-1.patch new file mode 100644 index 0000000..15099a5 --- /dev/null +++ b/SOURCES/glibc-RHEL-50548-1.patch @@ -0,0 +1,94 @@ +commit 424d97be50488beb6196c0ff0bc3dfeb87b4281c +Author: Florian Weimer +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 + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++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 diff --git a/SOURCES/glibc-RHEL-50548-2.patch b/SOURCES/glibc-RHEL-50548-2.patch new file mode 100644 index 0000000..3236001 --- /dev/null +++ b/SOURCES/glibc-RHEL-50548-2.patch @@ -0,0 +1,44 @@ +commit 3844cdc33093dbe1e33ddb831eada9bdb4a482b9 +Author: Florian Weimer +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 + +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 + #include ++#include + #include + #include ++#include + + 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. */ diff --git a/SOURCES/glibc-RHEL-50548-3.patch b/SOURCES/glibc-RHEL-50548-3.patch new file mode 100644 index 0000000..e7d53f5 --- /dev/null +++ b/SOURCES/glibc-RHEL-50548-3.patch @@ -0,0 +1,149 @@ +commit 43669fcf7315f494bbbc2c040cedeb0fa8416a5f +Author: Florian Weimer +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 + +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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 diff --git a/SOURCES/glibc-RHEL-50550.patch b/SOURCES/glibc-RHEL-50550.patch new file mode 100644 index 0000000..b448e5a --- /dev/null +++ b/SOURCES/glibc-RHEL-50550.patch @@ -0,0 +1,89 @@ +commit 70d083630563831e7069ad412cd3ab0b33638e92 +Author: Florian Weimer +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 + +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); + } + diff --git a/SOURCES/glibc-RHEL-50662-1.patch b/SOURCES/glibc-RHEL-50662-1.patch new file mode 100644 index 0000000..3e429ae --- /dev/null +++ b/SOURCES/glibc-RHEL-50662-1.patch @@ -0,0 +1,58 @@ +commit 868ab8923a2ec977faafec97ecafac0c3159c1b2 +Author: Florian Weimer +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 + +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. */ diff --git a/SOURCES/glibc-RHEL-50662-2.patch b/SOURCES/glibc-RHEL-50662-2.patch new file mode 100644 index 0000000..2f35180 --- /dev/null +++ b/SOURCES/glibc-RHEL-50662-2.patch @@ -0,0 +1,200 @@ +commit 691a3b2e9bfaba842e46a5ccb7f5e6ea144c3ade +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Allow short error responses to match any query (bug 31890) + + Reviewed-by: DJ Delorie + +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* 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 diff --git a/SOURCES/glibc-RHEL-50662-3.patch b/SOURCES/glibc-RHEL-50662-3.patch new file mode 100644 index 0000000..6524bce --- /dev/null +++ b/SOURCES/glibc-RHEL-50662-3.patch @@ -0,0 +1,208 @@ +commit af625987d619388a100b153520d3ee308bda9889 +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Do not wait for non-existing second DNS response after error (bug 30081) + + In single-request mode, there is no second response after an error + because the second query has not been sent yet. Waiting for it + introduces an unnecessary timeout. + + Reviewed-by: DJ Delorie + +diff --git a/resolv/Makefile b/resolv/Makefile +index d927e337d9..abff7fc007 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-semi-failure \ + tst-resolv-short-response \ + tst-resolv-trailing \ + +@@ -300,6 +301,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-semi-failure: $(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) +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 572e72c32f..9c77613f37 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1238,7 +1238,7 @@ send_dg(res_state statp, + *resplen2 = 0; + return resplen; + } +- if (buf2 != NULL) ++ if (buf2 != NULL && !single_request) + { + /* No data from the first reply. */ + resplen = 0; +diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c +new file mode 100644 +index 0000000000..aa9798b5a7 +--- /dev/null ++++ b/resolv/tst-resolv-semi-failure.c +@@ -0,0 +1,133 @@ ++/* Test parallel failure/success responses (bug 30081). ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* The rcode in the initial response. */ ++static volatile int rcode; ++ ++/* Whether to fail the initial A query (!fail_aaaa) or the initial ++ AAAA query (fail_aaaa). */ ++static volatile bool fail_aaaa; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* Handle the failing query. */ ++ if ((fail_aaaa && qtype == T_AAAA) && ctx->server_index == 0) ++ { ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ return; ++ } ++ ++ /* Otherwise produce a response. */ ++ 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); ++} ++ ++static void ++check_one (void) ++{ ++ ++ /* The buggy 1-second query timeout results in 30 seconds of delay, ++ which triggers are test timeout failure. */ ++ for (int i = 0; i < 30; ++i) ++ { ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("www.example", "80", &hints, &ai); ++ const char *expected; ++ if (ret == 0 && ai->ai_next != NULL) ++ expected = ("address: STREAM/TCP 192.0.2.17 80\n" ++ "address: STREAM/TCP 2001:db8::1 80\n"); ++ else ++ /* Only one response because the AAAA lookup failure is ++ treated as an ignoreable error. */ ++ expected = "address: STREAM/TCP 192.0.2.17 80\n"; ++ check_addrinfo ("www.example", ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ if (do_single_lookup) ++ _res.options |= RES_SNGLKUP; ++ ++ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) ++ { ++ fail_aaaa = do_fail_aaaa; ++ ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); ++ ++ rcode = 4; /* NOTIMP. */ ++ check_one (); ++ ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ } ++ ++ resolv_test_end (aux); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +index cf1e39876f..be354ae1c7 100644 +--- a/resolv/tst-resolv-short-response.c ++++ b/resolv/tst-resolv-short-response.c +@@ -81,6 +81,18 @@ check_one (void) + check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6), + "name: www.example\n" + "address: 2001:db8::1\n"); ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("www.example", "80", &hints, &ai); ++ check_addrinfo ("www.example", ai, ret, ++ "address: STREAM/TCP 192.0.2.17 80\n" ++ "address: STREAM/TCP 2001:db8::1 80\n"); ++ if (ret == 0) ++ freeaddrinfo (ai); + } + } + diff --git a/SOURCES/glibc-RHEL-50662-4.patch b/SOURCES/glibc-RHEL-50662-4.patch new file mode 100644 index 0000000..db465d8 --- /dev/null +++ b/SOURCES/glibc-RHEL-50662-4.patch @@ -0,0 +1,83 @@ +commit 95f61610f3e481d191b6184432342236fd59186d +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Support clearing option flags with a “-” prefix (bug 14799) + + I think using a “-” prefix is less confusing than introducing + double-negation construct (“no-no-tld-query”). + + Reviewed-by: DJ Delorie + +Conflicts: + NEWS + (Dropped) + +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 263263d474..243532b3ad 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -682,27 +682,29 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + { + char str[22]; + uint8_t len; +- uint8_t clear; + unsigned long int flag; + } options[] = { + #define STRnLEN(str) str, sizeof (str) - 1 +- { STRnLEN ("rotate"), 0, RES_ROTATE }, +- { STRnLEN ("edns0"), 0, RES_USE_EDNS0 }, +- { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP }, +- { STRnLEN ("single-request"), 0, RES_SNGLKUP }, +- { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY }, +- { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY }, +- { STRnLEN ("no-reload"), 0, RES_NORELOAD }, +- { STRnLEN ("use-vc"), 0, RES_USEVC }, +- { STRnLEN ("trust-ad"), 0, RES_TRUSTAD }, +- { STRnLEN ("no-aaaa"), 0, RES_NOAAAA }, ++ { STRnLEN ("rotate"), RES_ROTATE }, ++ { STRnLEN ("edns0"), RES_USE_EDNS0 }, ++ { STRnLEN ("single-request-reopen"), RES_SNGLKUPREOP }, ++ { STRnLEN ("single-request"), RES_SNGLKUP }, ++ { STRnLEN ("no_tld_query"), RES_NOTLDQUERY }, ++ { STRnLEN ("no-tld-query"), RES_NOTLDQUERY }, ++ { STRnLEN ("no-reload"), RES_NORELOAD }, ++ { STRnLEN ("use-vc"), RES_USEVC }, ++ { STRnLEN ("trust-ad"), RES_TRUSTAD }, ++ { STRnLEN ("no-aaaa"), RES_NOAAAA }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) ++ bool negate_option = *cp == '-'; ++ if (negate_option) ++ ++cp; + for (int i = 0; i < noptions; ++i) + if (strncmp (cp, options[i].str, options[i].len) == 0) + { +- if (options[i].clear) +- parser->template.options &= options[i].flag; ++ if (negate_option) ++ parser->template.options &= ~options[i].flag; + else + parser->template.options |= options[i].flag; + break; +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index 6bef62cde2..d3a19eb305 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -679,6 +679,16 @@ struct test_case test_cases[] = + "; nameserver[0]: [192.0.2.1]:53\n", + .res_options = "attempts:5 ndots:3 edns0 ", + }, ++ {.name = "RES_OPTIONS can clear flags", ++ .conf = "options ndots:2 use-vc no-aaaa edns0\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options ndots:3 use-vc\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n", ++ .res_options = "ndots:3 -edns0 -no-aaaa", ++ }, + {.name = "many search list entries (bug 19569)", + .conf = "nameserver 192.0.2.1\n" + "search corp.example.com support.example.com" diff --git a/SOURCES/glibc-RHEL-50662-5.patch b/SOURCES/glibc-RHEL-50662-5.patch new file mode 100644 index 0000000..c3722c2 --- /dev/null +++ b/SOURCES/glibc-RHEL-50662-5.patch @@ -0,0 +1,208 @@ +commit 765325951ac5c7d072278c9424930b29657e9758 +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Implement strict-error stub resolver option (bug 27929) + + For now, do not enable this mode by default due to the potential + impact on compatibility with existing deployments. + + Reviewed-by: DJ Delorie + +Conflicts: + NEWS + (Dropped) + +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 243532b3ad..b838dc7064 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -695,6 +695,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + { STRnLEN ("use-vc"), RES_USEVC }, + { STRnLEN ("trust-ad"), RES_TRUSTAD }, + { STRnLEN ("no-aaaa"), RES_NOAAAA }, ++ { STRnLEN ("strict-error"), RES_STRICTERR }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) + bool negate_option = *cp == '-'; +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 9c77613f37..9a284ed44a 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1234,21 +1234,38 @@ send_dg(res_state statp, + + if (thisansp_error) { + next_ns: +- if (recvresp1 || (buf2 != NULL && recvresp2)) { +- *resplen2 = 0; +- return resplen; +- } +- if (buf2 != NULL && !single_request) ++ /* Outside of strict-error mode, use the first ++ response even if the second response is an ++ error. This allows parallel resolution to ++ succeed even if the recursive resolver ++ always answers with SERVFAIL for AAAA ++ queries (which still happens in practice ++ unfortunately). ++ ++ In strict-error mode, always switch to the ++ next server and try to get a response from ++ there. */ ++ if ((statp->options & RES_STRICTERR) == 0) + { +- /* No data from the first reply. */ +- resplen = 0; +- /* We are waiting for a possible second reply. */ +- if (matching_query == 1) +- recvresp1 = 1; +- else +- recvresp2 = 1; +- +- goto wait; ++ if (recvresp1 || (buf2 != NULL && recvresp2)) ++ { ++ *resplen2 = 0; ++ return resplen; ++ } ++ ++ if (buf2 != NULL && !single_request) ++ { ++ /* No data from the first reply. */ ++ resplen = 0; ++ /* We are waiting for a possible ++ second reply. */ ++ if (matching_query == 1) ++ recvresp1 = 1; ++ else ++ recvresp2 = 1; ++ ++ goto wait; ++ } + } + + /* don't retry if called from dig */ +diff --git a/resolv/resolv.h b/resolv/resolv.h +index f40d6c58ce..b8a0f66a5f 100644 +--- a/resolv/resolv.h ++++ b/resolv/resolv.h +@@ -133,6 +133,7 @@ struct res_sym { + #define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */ + #define RES_TRUSTAD 0x04000000 /* Request AD bit, keep it in responses. */ + #define RES_NOAAAA 0x08000000 /* Suppress AAAA queries. */ ++#define RES_STRICTERR 0x10000000 /* Report more DNS errors as errors. */ + + #define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH) + +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index d3a19eb305..e41bcebd9d 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -129,6 +129,7 @@ print_resp (FILE *fp, res_state resp) + print_option_flag (fp, &options, RES_NORELOAD, "no-reload"); + print_option_flag (fp, &options, RES_TRUSTAD, "trust-ad"); + print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa"); ++ print_option_flag (fp, &options, RES_STRICTERR, "strict-error"); + fputc ('\n', fp); + if (options != 0) + fprintf (fp, "; error: unresolved option bits: 0x%x\n", options); +@@ -741,6 +742,15 @@ struct test_case test_cases[] = + "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n" + }, ++ {.name = "strict-error flag", ++ .conf = "options strict-error\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options strict-error\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, + { NULL } + }; + +diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c +index aa9798b5a7..b7681210f4 100644 +--- a/resolv/tst-resolv-semi-failure.c ++++ b/resolv/tst-resolv-semi-failure.c +@@ -67,6 +67,9 @@ response (const struct resolv_response_context *ctx, + resolv_response_close_record (b); + } + ++/* Set to 1 if strict error checking is enabled. */ ++static int do_strict_error; ++ + static void + check_one (void) + { +@@ -83,7 +86,10 @@ check_one (void) + struct addrinfo *ai; + int ret = getaddrinfo ("www.example", "80", &hints, &ai); + const char *expected; +- if (ret == 0 && ai->ai_next != NULL) ++ /* In strict-error mode, a switch to the second name server ++ happens, and both responses are received, so a single ++ response is a bug. */ ++ if (do_strict_error || (ret == 0 && ai->ai_next != NULL)) + expected = ("address: STREAM/TCP 192.0.2.17 80\n" + "address: STREAM/TCP 2001:db8::1 80\n"); + else +@@ -99,33 +105,36 @@ check_one (void) + static int + do_test (void) + { +- for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) +- { +- struct resolv_test *aux = resolv_test_start +- ((struct resolv_redirect_config) +- { +- .response_callback = response, +- }); ++ for (do_strict_error = 0; do_strict_error < 2; ++do_strict_error) ++ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); + +- if (do_single_lookup) +- _res.options |= RES_SNGLKUP; ++ if (do_strict_error) ++ _res.options |= RES_STRICTERR; ++ if (do_single_lookup) ++ _res.options |= RES_SNGLKUP; + +- for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) +- { +- fail_aaaa = do_fail_aaaa; ++ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) ++ { ++ fail_aaaa = do_fail_aaaa; + +- rcode = 2; /* SERVFAIL. */ +- check_one (); ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); + +- rcode = 4; /* NOTIMP. */ +- check_one (); ++ rcode = 4; /* NOTIMP. */ ++ check_one (); + +- rcode = 5; /* REFUSED. */ +- check_one (); +- } ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ } + +- resolv_test_end (aux); +- } ++ resolv_test_end (aux); ++ } + + return 0; + } diff --git a/SOURCES/glibc-RHEL-50662-6.patch b/SOURCES/glibc-RHEL-50662-6.patch new file mode 100644 index 0000000..d14093c --- /dev/null +++ b/SOURCES/glibc-RHEL-50662-6.patch @@ -0,0 +1,28 @@ +commit ec119972cb2598c04ec7d4219e20506006836f64 +Author: Florian Weimer +Date: Thu Aug 1 10:46:10 2024 +0200 + + resolv: Fix tst-resolv-short-response for older GCC (bug 32042) + + Previous GCC versions do not support the C23 change that + allows labels on declarations. + + Reviewed-by: Adhemerval Zanella + +diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +index be354ae1c7..9b06b0c176 100644 +--- a/resolv/tst-resolv-short-response.c ++++ b/resolv/tst-resolv-short-response.c +@@ -33,8 +33,10 @@ response (const struct resolv_response_context *ctx, + { + case 0: + /* First server times out. */ +- struct resolv_response_flags flags = {.rcode = rcode}; +- resolv_response_init (b, flags); ++ { ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ } + break; + case 1: + /* Second server sends reply. */ diff --git a/SOURCES/glibc-RHEL-54250.patch b/SOURCES/glibc-RHEL-54250.patch new file mode 100644 index 0000000..712376c --- /dev/null +++ b/SOURCES/glibc-RHEL-54250.patch @@ -0,0 +1,60 @@ +commit 3f54e459a633b4247be91b9d0f68a7e08720b8d8 +Author: Frédéric Bérat +Date: Tue Aug 13 12:01:26 2024 +0200 + + libio/tst-getdelim: Add new test covering NUL as a delimiter + + Add a new test to getdelim to verify that '\0' can be set as a + delimiter. + + Reviewed-by: Florian Weimer + +diff --git a/libio/tst-getdelim.c b/libio/tst-getdelim.c +index 44437326691228be..15e2d873a50df782 100644 +--- a/libio/tst-getdelim.c ++++ b/libio/tst-getdelim.c +@@ -1,4 +1,6 @@ +-/* Check that getdelim sets error indicator on error (BZ #29917) ++/* Test getdelim conforming to POSIX specifications. ++ ++ Note: Most getdelim use cases are covered by stdio-common/tst-getline. + + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. +@@ -18,18 +20,36 @@ + . */ + + #include ++#include + #include + + #include ++#include ++#include + + static int + do_test (void) + { ++ /* Check that getdelim sets error indicator on error (BZ #29917) */ + clearerr (stdin); + TEST_VERIFY (getdelim (0, 0, '\n', stdin) == -1); + TEST_VERIFY (ferror (stdin) != 0); + TEST_VERIFY (errno == EINVAL); + ++ /* Test getdelim with NUL as delimiter */ ++ verbose_printf ("Testing NUL delimiter\n"); ++ char *lineptr = NULL; ++ size_t linelen = 0; ++ char membuf[] = "abc\0d\nef\0"; ++ FILE *memstream = fmemopen (membuf, sizeof (membuf), "r"); ++ TEST_VERIFY_EXIT (memstream != NULL); ++ TEST_VERIFY (getdelim (&lineptr, &linelen, '\0', memstream) != -1); ++ TEST_COMPARE_BLOB (lineptr, 4, "abc\0", 4); ++ TEST_VERIFY (getdelim (&lineptr, &linelen, '\0', memstream) != -1); ++ TEST_COMPARE_BLOB (lineptr, 5, "d\nef\0", 5); ++ fclose (memstream); ++ free (lineptr); ++ + return 0; + } + diff --git a/SOURCES/glibc-RHEL-54413.patch b/SOURCES/glibc-RHEL-54413.patch new file mode 100644 index 0000000..17188df --- /dev/null +++ b/SOURCES/glibc-RHEL-54413.patch @@ -0,0 +1,630 @@ +commit 7f04bb4e49413bd57ac3215f3480b09ae7131968 +Author: Joseph Myers +Date: Wed Aug 21 19:58:14 2024 +0000 + + Add more tests of getline + + There is very little test coverage for getline (only a minimal + stdio-common/tstgetln.c which doesn't verify anything about the + results of the getline calls). Add some more thorough tests + (generally using fopencookie for convenience in testing various cases + for what the input and possible errors / EOF in the file read might + look like). + + Note the following regarding testing of error cases: + + * Nothing is said in the specifications about what if anything might + be written into the buffer, and whether it might be reallocated, in + error cases. The expectation of the tests (required to avoid memory + leaks on error) is that at least on error cases, the invariant that + lineptr points to at least n bytes is maintained. + + * The optional EOVERFLOW error case specified in POSIX, "The number of + bytes to be written into the buffer, including the delimiter + character (if encountered), would exceed {SSIZE_MAX}.", doesn't seem + practically testable, as any case reading so many characters (half + the address space) would also be liable to run into allocation + failure along (ENOMEM) the way. + + * If a read error occurs part way through reading an input line, it + seems unclear whether a partial line should be returned by getline + (avoid input getting lost), which is what glibc does at least in the + fopencookie case used in this test, or whether getline should return + -1 (error) (so avoiding the program misbehaving by processing a + truncated line as if it were complete). (There was a short, + inconclusive discussion about this on the Austin Group list on 9-10 + November 2014.) + + * The POSIX specification of getline inherits errors from fgetc. I + didn't try to cover fgetc errors systematically, just one example of + such an error. + + Tested for x86_64 and x86. + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index bc314af0617e1647..ea8598bbe3a6dfdd 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -177,6 +177,8 @@ tests := \ + tst-fread \ + tst-fseek \ + tst-fwrite \ ++ tst-getline \ ++ tst-getline-enomem \ + tst-gets \ + tst-grouping \ + tst-long-dbl-fphex \ +@@ -244,6 +246,8 @@ tests-special += \ + ifeq (yes,$(build-shared)) + ifneq ($(PERL),no) + tests-special += \ ++ $(objpfx)tst-getline-enomem-mem.out \ ++ $(objpfx)tst-getline-mem.out \ + $(objpfx)tst-printf-bz18872-mem.out \ + $(objpfx)tst-printf-bz25691-mem.out \ + $(objpfx)tst-printf-fp-free-mem.out \ +@@ -252,6 +256,10 @@ tests-special += \ + # tests-special + + generated += \ ++ tst-getline-enomem-mem.out \ ++ tst-getline-enomem.mtrace \ ++ tst-getline-mem.out \ ++ tst-getline.mtrace \ + tst-printf-bz18872-mem.out \ + tst-printf-bz18872.c \ + tst-printf-bz18872.mtrace \ +@@ -314,6 +322,12 @@ tst-scanf-bz27650-ENV = \ + tst-ungetc-leak-ENV = \ + MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \ + LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-getline-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-getline.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-getline-enomem-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-getline-enomem.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-getline-enomem.c b/stdio-common/tst-getline-enomem.c +new file mode 100644 +index 0000000000000000..7fc70ea9b51d1262 +--- /dev/null ++++ b/stdio-common/tst-getline-enomem.c +@@ -0,0 +1,78 @@ ++/* Test getline: ENOMEM on allocation 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Produce a stream of test data based on data in COOKIE (ignored), ++ storing up to SIZE bytes in BUF. */ ++ ++static ssize_t ++io_read (void *cookie, char *buf, size_t size) ++{ ++ memset (buf, 'x', size); ++ return size; ++} ++ ++/* Set up a test stream with fopencookie. */ ++ ++static FILE * ++open_test_stream (void) ++{ ++ static cookie_io_functions_t io_funcs = { .read = io_read }; ++ static int cookie; ++ FILE *fp = fopencookie (&cookie, "r", io_funcs); ++ TEST_VERIFY_EXIT (fp != NULL); ++ return fp; ++} ++ ++int ++do_test (void) ++{ ++ FILE *fp; ++ char *lineptr = NULL; ++ size_t size = 0; ++ ssize_t ret; ++ mtrace (); ++ /* Test ENOMEM (and error indicator for stream set) for memory ++ allocation failure. */ ++ verbose_printf ("Testing memory allocation failure\n"); ++ fp = open_test_stream (); ++ struct rlimit limit; ++ TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0); ++ limit.rlim_cur = 32 * 1024 * 1024; ++ TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0); ++ errno = 0; ++ ret = getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, ENOMEM); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ free (lineptr); ++ fclose (fp); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-getline.c b/stdio-common/tst-getline.c +new file mode 100644 +index 0000000000000000..29eb7cec0f344872 +--- /dev/null ++++ b/stdio-common/tst-getline.c +@@ -0,0 +1,451 @@ ++/* Test getline. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static struct test_data ++{ ++ /* Input test data for fopencookie stream. */ ++ const char *in_data; ++ ++ /* The amount of test data left. */ ++ size_t in_data_left; ++ ++ /* Error number for forcing an error on next read. */ ++ int in_error; ++ ++ /* Error number for forcing an error (rather than EOF) after all ++ bytes read. */ ++ int in_error_after; ++} the_cookie; ++ ++/* Produce a stream of test data based on data in COOKIE, storing up ++ to SIZE bytes in BUF. */ ++ ++static ssize_t ++io_read (void *cookie, char *buf, size_t size) ++{ ++ struct test_data *p = cookie; ++ if (p->in_error) ++ { ++ errno = p->in_error; ++ return -1; ++ } ++ if (size > p->in_data_left) ++ size = p->in_data_left; ++ memcpy (buf, p->in_data, size); ++ p->in_data += size; ++ p->in_data_left -= size; ++ if (p->in_data_left == 0) ++ p->in_error = p->in_error_after; ++ return size; ++} ++ ++/* Set up a test stream with fopencookie. */ ++ ++static FILE * ++open_test_stream (const char *in_data, size_t size) ++{ ++ static cookie_io_functions_t io_funcs = { .read = io_read }; ++ the_cookie.in_data = in_data; ++ the_cookie.in_data_left = size; ++ the_cookie.in_error = 0; ++ the_cookie.in_error_after = 0; ++ FILE *fp = fopencookie (&the_cookie, "r", io_funcs); ++ TEST_VERIFY_EXIT (fp != NULL); ++ return fp; ++} ++ ++/* Set up a test stream with fopencookie, using data from a string ++ literal. */ ++#define OPEN_TEST_STREAM(IN_DATA) open_test_stream (IN_DATA, sizeof (IN_DATA)) ++ ++/* Wrap getline to verify that (as per the glibc manual), *LINEPTR is ++ returned as non-null and with at least *N bytes (even on error or ++ EOF). Also clear errno for the benefit of tests that check the ++ value of errno after the call. */ ++ ++ssize_t ++wrap_getline (char **lineptr, size_t *n, FILE *stream) ++{ ++ errno = 0; ++ ssize_t ret = getline (lineptr, n, stream); ++ if (lineptr != NULL && n != NULL) ++ { ++ TEST_VERIFY (*lineptr != NULL); ++ TEST_VERIFY (malloc_usable_size (*lineptr) >= *n); ++ } ++ return ret; ++} ++ ++int ++do_test (void) ++{ ++ FILE *fp; ++ char *lineptr = NULL; ++ size_t size = 0; ++ ssize_t ret; ++ mtrace (); ++ /* Test failure with EINVAL (and error indicator for stream set) if ++ lineptr is a null pointer. */ ++ verbose_printf ("Testing lineptr == NULL\n"); ++ fp = OPEN_TEST_STREAM ("test"); ++ ret = wrap_getline (NULL, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ /* Test failure with EINVAL (and error indicator for stream set) if ++ n is a null pointer. */ ++ verbose_printf ("Testing n == NULL\n"); ++ fp = OPEN_TEST_STREAM ("test"); ++ ret = wrap_getline (&lineptr, NULL, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ /* Test failure with EINVAL (and error indicator for stream set) if ++ both lineptr and n are null pointers. */ ++ verbose_printf ("Testing lineptr == NULL and n == NULL\n"); ++ fp = OPEN_TEST_STREAM ("test"); ++ ret = wrap_getline (NULL, NULL, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ /* Test normal line, fitting in available space (including case with ++ null bytes). */ ++ verbose_printf ("Testing normal nonempty input\n"); ++ lineptr = xmalloc (10); ++ size = 10; ++ fp = OPEN_TEST_STREAM ("foo\nbar\0\n\0baz\nte\0st\n"); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "foo\n", 5); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "bar\0\n", 6); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "\0baz\n", 6); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 6); ++ TEST_COMPARE_BLOB (lineptr, 7, "te\0st\n", 7); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 1); ++ TEST_COMPARE_BLOB (lineptr, 1, "", 1); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (ferror (fp), 0); ++ TEST_COMPARE (!!feof (fp), 1); ++ fclose (fp); ++ /* Test normal line, with reallocation (including case with null bytes). */ ++ verbose_printf ("Testing normal nonempty input with reallocation\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = OPEN_TEST_STREAM ("foo\nbar\0\n\0baz\nte\0st\n" ++ "foo\nbar\0\n\0baz\nte\0st\n"); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "foo\n", 5); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "bar\0\n", 6); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "\0baz\n", 6); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 6); ++ TEST_COMPARE_BLOB (lineptr, 7, "te\0st\n", 7); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "foo\n", 5); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "bar\0\n", 6); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "\0baz\n", 6); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 6); ++ TEST_COMPARE_BLOB (lineptr, 7, "te\0st\n", 7); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 1); ++ TEST_COMPARE_BLOB (lineptr, 1, "", 1); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (ferror (fp), 0); ++ TEST_COMPARE (!!feof (fp), 1); ++ fclose (fp); ++ /* Test EOF before delimiter but after some bytes read, fitting in ++ available space (including case with null bytes). */ ++ verbose_printf ("Testing EOF before delimiter\n"); ++ free (lineptr); ++ lineptr = xmalloc (10); ++ size = 10; ++ fp = open_test_stream ("foo", 3); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 3); ++ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (10); ++ size = 10; ++ fp = open_test_stream ("bar\0", 4); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "bar\0", 5); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (10); ++ size = 10; ++ fp = open_test_stream ("\0baz", 4); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "\0baz", 5); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (10); ++ size = 10; ++ fp = open_test_stream ("te\0st", 5); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "te\0st", 6); ++ fclose (fp); ++ /* Test EOF before delimiter but after some bytes read, with ++ reallocation (including case with null bytes). */ ++ verbose_printf ("Testing EOF before delimiter with reallocation\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("foo", 3); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 3); ++ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4); ++ fclose (fp); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("bar\0", 4); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "bar\0", 5); ++ fclose (fp); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("\0baz", 4); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "\0baz", 5); ++ fclose (fp); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("te\0st", 5); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "te\0st", 6); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ fp = open_test_stream ("foo", 3); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 3); ++ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ fp = open_test_stream ("bar\0", 4); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "bar\0", 5); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ fp = open_test_stream ("\0baz", 4); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 4); ++ TEST_COMPARE_BLOB (lineptr, 5, "\0baz", 5); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ fp = open_test_stream ("te\0st", 5); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 5); ++ TEST_COMPARE_BLOB (lineptr, 6, "te\0st", 6); ++ fclose (fp); ++ /* Test EOF with no bytes read (nothing is specified about anything ++ written to the buffer), including EOF again when already at end ++ of file. */ ++ verbose_printf ("Testing EOF with no bytes read\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("", 0); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (ferror (fp), 0); ++ TEST_COMPARE (!!feof (fp), 1); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (ferror (fp), 0); ++ TEST_COMPARE (!!feof (fp), 1); ++ fclose (fp); ++ free (lineptr); ++ lineptr = xmalloc (1); ++ size = 1; ++ fp = open_test_stream ("", 0); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (ferror (fp), 0); ++ TEST_COMPARE (!!feof (fp), 1); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (ferror (fp), 0); ++ TEST_COMPARE (!!feof (fp), 1); ++ fclose (fp); ++ /* Test error occurring with no bytes read, including calling ++ wrap_getline again while the file is in error state. */ ++ verbose_printf ("Testing error with no bytes read\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("", 0); ++ the_cookie.in_error = EINVAL; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ /* Make sure error state is sticky. */ ++ the_cookie.in_error = 0; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ /* Test error occurring after some bytes read. Specifications are ++ ambiguous here; at least in the fopencookie case used for ++ testing, glibc returns the partial line (but with the error ++ indicator on the stream set). */ ++ verbose_printf ("Testing error after some bytes read\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = open_test_stream ("foo", 3); ++ the_cookie.in_error_after = EINVAL; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, 3); ++ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ /* Make sure error state is sticky. */ ++ the_cookie.in_error = 0; ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ /* Test EBADF error as a representative example of an fgetc error ++ resulting in an error from wrap_getline. We don't try to cover all ++ error cases for fgetc here. */ ++ verbose_printf ("Testing EBADF error\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ fp = xfopen ("/dev/null", "r"); ++ xclose (fileno (fp)); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EBADF); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ /* Test EAGAIN error as an example of an fgetc error on a valid file ++ descriptor. */ ++ verbose_printf ("Testing EAGAIN error\n"); ++ free (lineptr); ++ lineptr = NULL; ++ size = 0; ++ int pipefd[2]; ++ xpipe (pipefd); ++ ret = fcntl (pipefd[0], F_SETFL, O_NONBLOCK); ++ TEST_VERIFY_EXIT (ret == 0); ++ fp = fdopen (pipefd[0], "r"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EAGAIN); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ /* Make sure error state is sticky (even after more data is ++ available to read). */ ++ xwrite (pipefd[1], "x\n", 2); ++ ret = wrap_getline (&lineptr, &size, fp); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (!!ferror (fp), 1); ++ TEST_COMPARE (feof (fp), 0); ++ fclose (fp); ++ free (lineptr); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-54447-1.patch b/SOURCES/glibc-RHEL-54447-1.patch new file mode 100644 index 0000000..e625815 --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-1.patch @@ -0,0 +1,331 @@ +commit 5456af201d4c0a2950200ba756e5f8314ddbbccd +Author: Carlos O'Donell +Date: Thu May 11 14:00:41 2023 -0400 + + stdio-common: Reformat Makefile. + + Reflow Makefile. + Sort using scripts/sort-makefile-lines.py. + + Code generation is changed as routines are linked in sorted order + as expected. + + No regressions on x86_64 and i686. + + (cherry picked from commit c3004417afc98585089a9282d1d4d60cdef5317a) + (cherry picked from commit 5b4e90230b8147e273585bf296bf1a9fb6e2b4c2) + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 803f16dae030cb72..76d1d0a1193aa109 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -22,82 +22,241 @@ subdir := stdio-common + + include ../Makeconfig + +-headers := stdio_ext.h printf.h bits/printf-ldbl.h bits/stdio_lim.h +- +-routines := \ +- ctermid cuserid \ +- _itoa _itowa itoa-digits itoa-udigits itowa-digits \ +- vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex \ +- reg-modifier reg-type \ +- printf_size fprintf printf snprintf sprintf asprintf dprintf \ +- vfwprintf vfscanf vfwscanf \ +- fscanf scanf sscanf \ +- perror psignal \ +- tmpfile tmpfile64 tmpnam tmpnam_r tempnam tempname \ +- getline getw putw \ +- remove rename renameat renameat2 \ +- flockfile ftrylockfile funlockfile \ +- isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \ +- isoc99_vsscanf \ +- psiginfo gentempfd \ +- vfscanf-internal vfwscanf-internal iovfscanf \ +- vfprintf-internal vfwprintf-internal +- +-aux := errlist siglist printf-parsemb printf-parsewc fxprintf +- +-tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ +- temptest tst-fileno test-fwrite tst-ungetc tst-ferror \ +- xbug errnobug \ +- bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 bug11 bug12 bug13 \ +- tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \ +- scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \ +- scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \ +- tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \ +- tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 \ +- tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \ +- tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2 bug18 bug18a \ +- bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \ +- scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \ +- bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \ +- bug25 tst-printf-round bug23-2 bug23-3 bug23-4 bug26 tst-fmemopen3 \ +- tst-printf-bz18872 tst-vfprintf-width-prec tst-fmemopen4 \ +- tst-vfprintf-user-type \ +- tst-vfprintf-mbs-prec \ +- tst-scanf-round \ +- tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \ +- scanf14a scanf16a \ +- tst-printf-bz25691 \ +- tst-vfprintf-width-prec-alloc \ +- tst-printf-fp-free \ +- tst-printf-fp-leak \ +- test-strerr +- +- +-test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble ++headers := \ ++ bits/printf-ldbl.h \ ++ bits/stdio_lim.h \ ++ printf.h \ ++ stdio_ext.h \ ++ # headers ++ ++routines := \ ++ _itoa \ ++ _itowa \ ++ asprintf \ ++ ctermid \ ++ cuserid \ ++ dprintf \ ++ flockfile \ ++ fprintf \ ++ fscanf \ ++ ftrylockfile \ ++ funlockfile \ ++ gentempfd \ ++ getline \ ++ getw \ ++ iovfscanf \ ++ isoc99_fscanf \ ++ isoc99_scanf \ ++ isoc99_sscanf \ ++ isoc99_vfscanf \ ++ isoc99_vscanf \ ++ isoc99_vsscanf \ ++ itoa-digits \ ++ itoa-udigits \ ++ itowa-digits \ ++ perror \ ++ printf \ ++ printf-prs \ ++ printf_fp \ ++ printf_fphex \ ++ printf_size \ ++ psiginfo \ ++ psignal \ ++ putw \ ++ reg-modifier \ ++ reg-printf \ ++ reg-type \ ++ remove \ ++ rename \ ++ renameat \ ++ renameat2 \ ++ scanf \ ++ snprintf \ ++ sprintf \ ++ sscanf \ ++ tempnam \ ++ tempname \ ++ tmpfile \ ++ tmpfile64 tmpnam \ ++ tmpnam_r \ ++ vfprintf \ ++ vfprintf-internal \ ++ vfscanf \ ++ vfscanf-internal \ ++ vfwprintf \ ++ vfwprintf-internal \ ++ vfwscanf \ ++ vfwscanf-internal \ ++ vprintf \ ++ # routines ++ ++aux := \ ++ errlist \ ++ fxprintf \ ++ printf-parsemb \ ++ printf-parsewc \ ++ siglist \ ++ # aux ++ ++tests := \ ++ bug-vfprintf-nargs \ ++ bug1 \ ++ bug10 \ ++ bug11 \ ++ bug12 \ ++ bug13 \ ++ bug14 \ ++ bug16 \ ++ bug17 \ ++ bug18 \ ++ bug18a \ ++ bug19 \ ++ bug19a \ ++ bug2 \ ++ bug20 \ ++ bug21 \ ++ bug22 \ ++ bug23 \ ++ bug23-2 \ ++ bug23-3 \ ++ bug23-4 \ ++ bug24 \ ++ bug25 \ ++ bug26 \ ++ bug3 \ ++ bug4 \ ++ bug5 \ ++ bug6 \ ++ bug7 \ ++ bug8 \ ++ bug9 \ ++ errnobug \ ++ scanf1 \ ++ scanf10 \ ++ scanf11 \ ++ scanf12 \ ++ scanf13 \ ++ scanf14 \ ++ scanf14a \ ++ scanf15 \ ++ scanf16 \ ++ scanf16a \ ++ scanf17 \ ++ scanf2 \ ++ scanf3 \ ++ scanf4 \ ++ scanf5 \ ++ scanf7 \ ++ scanf8 \ ++ scanf9 \ ++ temptest \ ++ test-fseek \ ++ test-fwrite \ ++ test-popen \ ++ test-strerr \ ++ test-vfprintf \ ++ test_rdwr \ ++ tfformat \ ++ tiformat \ ++ tllformat \ ++ tst-bz11319 \ ++ tst-bz11319-fortify2 \ ++ tst-cookie \ ++ tst-fdopen \ ++ tst-ferror \ ++ tst-fgets \ ++ tst-fileno \ ++ tst-fmemopen \ ++ tst-fmemopen2 \ ++ tst-fmemopen3 \ ++ tst-fmemopen4 \ ++ tst-fphex \ ++ tst-fphex-wide \ ++ tst-fseek \ ++ tst-fwrite \ ++ tst-gets \ ++ tst-grouping \ ++ tst-long-dbl-fphex \ ++ tst-obprintf \ ++ 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 \ ++ tst-renameat2 \ ++ tst-rndseek \ ++ tst-scanf-round \ ++ tst-setvbuf1 \ ++ tst-sprintf \ ++ tst-sprintf2 \ ++ tst-sprintf3 \ ++ tst-sscanf \ ++ tst-swprintf \ ++ tst-swscanf \ ++ tst-tmpnam \ ++ tst-ungetc \ ++ tst-unlockedio \ ++ tst-vfprintf-mbs-prec \ ++ tst-vfprintf-user-type \ ++ tst-vfprintf-width-prec \ ++ tst-vfprintf-width-prec-alloc \ ++ tst-wc-printf \ ++ tstdiomisc \ ++ tstgetln \ ++ tstscanf \ ++ xbug \ ++ # tests ++ ++test-srcs = \ ++ tst-printf \ ++ tst-printfsz-islongdouble \ ++ tst-unbputc \ ++ # test-srcs + + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \ +- $(objpfx)tst-printf-bz18872-mem.out \ +- $(objpfx)tst-setvbuf1-cmp.out \ +- $(objpfx)tst-vfprintf-width-prec-mem.out \ +- $(objpfx)tst-printfsz-islongdouble.out \ +- $(objpfx)tst-printf-bz25691-mem.out \ +- $(objpfx)tst-printf-fp-free-mem.out \ +- $(objpfx)tst-printf-fp-leak-mem.out +-generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \ +- tst-printf-bz18872-mem.out \ +- tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \ +- tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out \ +- tst-printf-fp-free.mtrace tst-printf-fp-free-mem.out \ +- tst-printf-fp-leak.mtrace tst-printf-fp-leak-mem.out +-endif ++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-vfprintf-width-prec-mem.out \ ++ # tests-special ++ ++generated += \ ++ tst-printf-bz18872-mem.out \ ++ tst-printf-bz18872.c \ ++ tst-printf-bz18872.mtrace \ ++ tst-printf-bz25691-mem.out \ ++ tst-printf-bz25691.mtrace \ ++ tst-printf-fp-free-mem.out \ ++ tst-printf-fp-free.mtrace \ ++ tst-printf-fp-leak-mem.out \ ++ tst-printf-fp-leak.mtrace \ ++ tst-vfprintf-width-prec-mem.out \ ++ tst-vfprintf-width-prec.mtrace \ ++ # generated ++endif # $(run-built-tests) + + tests-special += $(objpfx)tst-errno-manual.out + + include ../Rules + + ifeq ($(run-built-tests),yes) +-LOCALES := de_DE.ISO-8859-1 de_DE.UTF-8 en_US.ISO-8859-1 ja_JP.EUC-JP ++LOCALES := \ ++ de_DE.ISO-8859-1 \ ++ de_DE.UTF-8 \ ++ en_US.ISO-8859-1 \ ++ ja_JP.EUC-JP \ ++ # LOCALES + include ../gen-locales.mk + + $(objpfx)bug14.out: $(gen-locales) diff --git a/SOURCES/glibc-RHEL-54447-10.patch b/SOURCES/glibc-RHEL-54447-10.patch new file mode 100644 index 0000000..6258b77 --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-10.patch @@ -0,0 +1,201 @@ +commit 9556acd249687ac562deb6309503165d66eb06fa +Author: Adhemerval Zanella +Date: Thu Dec 21 15:59:15 2023 -0300 + + debug: Adapt fortify tests to libsupport + + Checked on aarch64, armhf, x86_64, and i686. + Reviewed-by: Siddhesh Poyarekar + +diff --git a/debug/test-stpcpy_chk.c b/debug/test-stpcpy_chk.c +index 96ad600bc2760cbd..c3cb52d987f9db4f 100644 +--- a/debug/test-stpcpy_chk.c ++++ b/debug/test-stpcpy_chk.c +@@ -20,7 +20,7 @@ + #define STRCPY_RESULT(dst, len) ((dst) + (len)) + #define TEST_MAIN + #define TEST_NAME "stpcpy_chk" +-#include "../string/test-string.h" ++#include + + extern void __attribute__ ((noreturn)) __chk_fail (void); + char *simple_stpcpy_chk (char *, const char *, size_t); +diff --git a/debug/test-strcpy_chk.c b/debug/test-strcpy_chk.c +index 80c07482aaa54e3b..bb89e342caef470b 100644 +--- a/debug/test-strcpy_chk.c ++++ b/debug/test-strcpy_chk.c +@@ -21,7 +21,7 @@ + # define STRCPY_RESULT(dst, len) dst + # define TEST_MAIN + # define TEST_NAME "strcpy_chk" +-# include "../string/test-string.h" ++# include + + /* This test case implicitly tests the availability of the __chk_fail + symbol, which is part of the public ABI and may be used +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index fb02452f5993c594..01a8703de1e6e09a 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -24,6 +24,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -37,6 +38,10 @@ + #include + #include + #include ++#include ++ ++#include ++#include + + #ifndef _GNU_SOURCE + # define MEMPCPY memcpy +@@ -53,15 +58,10 @@ + #define obstack_chunk_alloc malloc + #define obstack_chunk_free free + +-char *temp_filename; +-static void do_prepare (void); +-static int do_test (void); +-#define PREPARE(argc, argv) do_prepare () +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++static char *temp_filename; + + static void +-do_prepare (void) ++do_prepare (int argc, char *argv[]) + { + int temp_fd = create_temp_file ("tst-chk1.", &temp_filename); + if (temp_fd == -1) +@@ -78,10 +78,11 @@ do_prepare (void) + exit (1); + } + } ++#define PREPARE do_prepare + +-volatile int chk_fail_ok; +-volatile int ret; +-jmp_buf chk_fail_buf; ++static volatile int chk_fail_ok; ++static volatile int ret; ++static jmp_buf chk_fail_buf; + + static void + handler (int sig) +@@ -103,22 +104,22 @@ wchar_t wbuf[10]; + #define buf_size sizeof (buf) + #endif + +-volatile size_t l0; +-volatile char *p; +-volatile wchar_t *wp; +-const char *str1 = "JIHGFEDCBA"; +-const char *str2 = "F"; +-const char *str3 = "%s%n%s%n"; +-const char *str4 = "Hello, "; +-const char *str5 = "World!\n"; +-const wchar_t *wstr1 = L"JIHGFEDCBA"; +-const wchar_t *wstr2 = L"F"; +-const wchar_t *wstr3 = L"%s%n%s%n"; +-const wchar_t *wstr4 = L"Hello, "; +-const wchar_t *wstr5 = L"World!\n"; +-char buf2[10] = "%s"; +-int num1 = 67; +-int num2 = 987654; ++static volatile size_t l0; ++static volatile char *p; ++static volatile wchar_t *wp; ++static const char *str1 = "JIHGFEDCBA"; ++static const char *str2 = "F"; ++static const char *str3 = "%s%n%s%n"; ++static const char *str4 = "Hello, "; ++static const char *str5 = "World!\n"; ++static const wchar_t *wstr1 = L"JIHGFEDCBA"; ++static const wchar_t *wstr2 = L"F"; ++static const wchar_t *wstr3 = L"%s%n%s%n"; ++static const wchar_t *wstr4 = L"Hello, "; ++static const wchar_t *wstr5 = L"World!\n"; ++static char buf2[10] = "%s"; ++static int num1 = 67; ++static int num2 = 987654; + + #define FAIL() \ + do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0) +@@ -1763,3 +1764,5 @@ do_test (void) + + return ret; + } ++ ++#include +diff --git a/debug/tst-longjmp_chk.c b/debug/tst-longjmp_chk.c +index e4e93d2a36b537d9..37f858606be4c4a2 100644 +--- a/debug/tst-longjmp_chk.c ++++ b/debug/tst-longjmp_chk.c +@@ -10,11 +10,7 @@ + #include + #include + +- +-static int do_test(void); +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" +- ++#include + + static jmp_buf b; + +@@ -76,3 +72,5 @@ do_test (void) + puts ("second longjmp returned"); + return 1; + } ++ ++#include +diff --git a/debug/tst-longjmp_chk2.c b/debug/tst-longjmp_chk2.c +index 23d3436d1d26d2d1..69c1ab9db73f14ae 100644 +--- a/debug/tst-longjmp_chk2.c ++++ b/debug/tst-longjmp_chk2.c +@@ -12,9 +12,7 @@ + #include + #include + +-static int do_test (void); +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include + + static jmp_buf mainloop; + static sigset_t mainsigset; +@@ -128,3 +126,5 @@ do_test (void) + + return 0; + } ++ ++#include +diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c +index 3155c7769fcbd83f..4434937c597dbe10 100644 +--- a/debug/tst-longjmp_chk3.c ++++ b/debug/tst-longjmp_chk3.c +@@ -20,10 +20,6 @@ + #include + #include + +-static int do_test (void); +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" +- + static char buf[SIGSTKSZ * 4]; + static jmp_buf jb; + +@@ -83,3 +79,5 @@ do_test (void) + puts ("longjmp returned and shouldn't"); + return 1; + } ++ ++#include diff --git a/SOURCES/glibc-RHEL-54447-2.patch b/SOURCES/glibc-RHEL-54447-2.patch new file mode 100644 index 0000000..1c39e95 --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-2.patch @@ -0,0 +1,195 @@ +commit 388c9d7294e5ee3b741aef2e8af63eb1f76ace86 +Author: Maciej W. Rozycki +Date: Fri Jul 26 13:21:34 2024 +0100 + + support: Add FAIL test failure helper + + Add a FAIL test failure helper analogous to FAIL_RET, that does not + cause the current function to return, providing a standardized way to + report a test failure with a message supplied while permitting the + caller to continue executing, for further reporting, cleaning up, etc. + + Update existing test cases that provide a conflicting definition of FAIL + by removing the local FAIL definition and then as follows: + + - tst-fortify-syslog: provide a meaningful message in addition to the + file name already added by ; 'support_record_failure' + is already called by 'support_print_failure_impl' invoked by the new + FAIL test failure helper. + + - tst-ctype: no update to FAIL calls required, with the name of the file + and the line number within of the failure site additionally included + by the new FAIL test failure helper, and error counting plus count + reporting upon test program termination also already provided by + 'support_record_failure' and 'support_report_failure' respectively, + called by 'support_print_failure_impl' and 'adjust_exit_status' also + respectively. However in a number of places 'printf' is called and + the error count adjusted by hand, so update these places to make use + of FAIL instead. And last but not least adjust the final summary just + to report completion, with any error count following as reported by + the test driver. + + - test-tgmath2: no update to FAIL calls required, with the name of the + file of the failure site additionally included by the new FAIL test + failure helper. Also there is no need to track the return status by + hand as any call to FAIL will eventually cause the test case to return + an unsuccesful exit status regardless of the return status from the + test function, via a call to 'adjust_exit_status' made by the test + driver. + + Reviewed-by: DJ Delorie + (cherry picked from commit 1b97a9f23bf605ca608162089c94187573fb2a9e) + (cherry picked from commit 28f358bc4209ab0425170cdccf65bb1fe861148f) + +diff --git a/localedata/tst-ctype.c b/localedata/tst-ctype.c +index 1e4fa132bb4e17c6..f8645e31db8a1691 100644 +--- a/localedata/tst-ctype.c ++++ b/localedata/tst-ctype.c +@@ -22,6 +22,8 @@ + #include + #include + ++#include ++ + + static const char lower[] = "abcdefghijklmnopqrstuvwxyz"; + static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +@@ -54,19 +56,11 @@ static struct classes + #define nclasses (sizeof (classes) / sizeof (classes[0])) + + +-#define FAIL(str, args...) \ +- { \ +- printf (" " str "\n", ##args); \ +- ++errors; \ +- } +- +- + static int + do_test (void) + { + const char *cp; + const char *cp2; +- int errors = 0; + char *inpline = NULL; + size_t inplinelen = 0; + char *resline = NULL; +@@ -395,11 +389,8 @@ punct = %04x alnum = %04x\n", + { + if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0) + != (*resp != '0')) +- { +- printf (" is%s('%c' = '\\x%02x') %s true\n", inpline, +- *inp, *inp, *resp == '1' ? "not" : "is"); +- ++errors; +- } ++ FAIL (" is%s('%c' = '\\x%02x') %s true\n", inpline, ++ *inp, *inp, *resp == '1' ? "not" : "is"); + ++inp; + ++resp; + } +@@ -409,11 +400,8 @@ punct = %04x alnum = %04x\n", + while (*inp != '\0') + { + if (tolower (*inp) != *resp) +- { +- printf (" tolower('%c' = '\\x%02x') != '%c'\n", +- *inp, *inp, *resp); +- ++errors; +- } ++ FAIL (" tolower('%c' = '\\x%02x') != '%c'\n", ++ *inp, *inp, *resp); + ++inp; + ++resp; + } +@@ -423,11 +411,8 @@ punct = %04x alnum = %04x\n", + while (*inp != '\0') + { + if (toupper (*inp) != *resp) +- { +- printf (" toupper('%c' = '\\x%02x') != '%c'\n", +- *inp, *inp, *resp); +- ++errors; +- } ++ FAIL (" toupper('%c' = '\\x%02x') != '%c'\n", ++ *inp, *inp, *resp); + ++inp; + ++resp; + } +@@ -437,14 +422,7 @@ punct = %04x alnum = %04x\n", + } + + +- if (errors != 0) +- { +- printf (" %d error%s for `%s' locale\n\n\n", errors, +- errors == 1 ? "" : "s", setlocale (LC_ALL, NULL)); +- return 1; +- } +- +- printf (" No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL)); ++ printf ("Completed testing for `%s' locale\n\n\n", setlocale (LC_ALL, NULL)); + return 0; + } + +diff --git a/math/test-tgmath2.c b/math/test-tgmath2.c +index b8fb00c566439ab0..e3b7a3a3615e083a 100644 +--- a/math/test-tgmath2.c ++++ b/math/test-tgmath2.c +@@ -25,6 +25,8 @@ + #include + #include + ++#include ++ + //#define DEBUG + + typedef complex float cfloat; +@@ -88,13 +90,6 @@ enum + int count; + int counts[Tlast][C_last]; + +-#define FAIL(str) \ +- do \ +- { \ +- printf ("%s failure on line %d\n", (str), __LINE__); \ +- result = 1; \ +- } \ +- while (0) + #define TEST_TYPE_ONLY(expr, rettype) \ + do \ + { \ +@@ -134,8 +129,6 @@ int counts[Tlast][C_last]; + int + test_cos (const int Vint4, const long long int Vllong4) + { +- int result = 0; +- + TEST (cos (vfloat1), float, cos); + TEST (cos (vdouble1), double, cos); + TEST (cos (vldouble1), ldouble, cos); +@@ -153,7 +146,7 @@ test_cos (const int Vint4, const long long int Vllong4) + TEST (cos (Vcdouble1), cdouble, cos); + TEST (cos (Vcldouble1), cldouble, cos); + +- return result; ++ return 0; + } + + int +diff --git a/support/check.h b/support/check.h +index 9b1844352f32513a..8e045dd9c0c36b4c 100644 +--- a/support/check.h ++++ b/support/check.h +@@ -24,6 +24,11 @@ + + __BEGIN_DECLS + ++/* Record a test failure, print the failure message to standard output ++ and pass the result of 1 through. */ ++#define FAIL(...) \ ++ support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__) ++ + /* Record a test failure, print the failure message to standard output + and return 1. */ + #define FAIL_RET(...) \ diff --git a/SOURCES/glibc-RHEL-54447-3.patch b/SOURCES/glibc-RHEL-54447-3.patch new file mode 100644 index 0000000..a7b2bdd --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-3.patch @@ -0,0 +1,169 @@ +commit 86f5cfe77d60ca4f78f270adc7ae2c15a1d8d4bc +Author: Maciej W. Rozycki +Date: Fri Jul 26 13:21:34 2024 +0100 + + stdio-common: Add test for vfscanf with matches longer than INT_MAX [BZ #27650] + + Complement commit b03e4d7bd25b ("stdio: fix vfscanf with matches longer + than INT_MAX (bug 27650)") and add a test case for the issue, inspired + by the reproducer provided with the bug report. + + This has been verified to succeed as from the commit referred and fail + beforehand. + + As the test requires 2GiB of data to be passed around its performance + has been evaluated using a choice of systems and the execution time + determined to be respectively in the range of 9s for POWER9@2.166GHz, + 24s for FU740@1.2GHz, and 40s for 74Kf@950MHz. As this is on the verge + of and beyond the default timeout it has been increased by the factor of + 8. Regardless, following recent practice the test has been added to the + standard rather than extended set. + + Reviewed-by: DJ Delorie + (cherry picked from commit 89cddc8a7096f3d9225868304d2bc0a1aaf07d63) + (cherry picked from commit 99ffa84bdcdc3d81e82f448279f0c8278dd30964) + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 76d1d0a1193aa109..08bedd01be61a55d 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -190,6 +190,7 @@ tests := \ + tst-put-error \ + tst-renameat2 \ + tst-rndseek \ ++ tst-scanf-bz27650 \ + tst-scanf-round \ + tst-setvbuf1 \ + tst-sprintf \ +@@ -241,6 +242,7 @@ generated += \ + tst-printf-fp-free.mtrace \ + tst-printf-fp-leak-mem.out \ + tst-printf-fp-leak.mtrace \ ++ tst-scanf-bz27650.mtrace \ + tst-vfprintf-width-prec-mem.out \ + tst-vfprintf-width-prec.mtrace \ + # generated +@@ -283,6 +285,9 @@ tst-printf-fp-free-ENV = \ + tst-printf-fp-leak-ENV = \ + MALLOC_TRACE=$(objpfx)tst-printf-fp-leak.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++tst-scanf-bz27650-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.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-scanf-bz27650.c b/stdio-common/tst-scanf-bz27650.c +new file mode 100644 +index 0000000000000000..3a742bc86556908c +--- /dev/null ++++ b/stdio-common/tst-scanf-bz27650.c +@@ -0,0 +1,108 @@ ++/* Test for BZ #27650, formatted input matching beyond INT_MAX. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++/* Produce a stream of more than INT_MAX characters via buffer BUF of ++ size SIZE according to bookkeeping in COOKIE and then return EOF. */ ++ ++static ssize_t ++io_read (void *cookie, char *buf, size_t size) ++{ ++ unsigned int *written = cookie; ++ unsigned int w = *written; ++ ++ if (w > INT_MAX) ++ return 0; ++ ++ memset (buf, 'a', size); ++ *written = w + size; ++ return size; ++} ++ ++/* Consume a stream of more than INT_MAX characters from an artificial ++ input stream of which none is the new line character. The call to ++ fscanf is supposed to complete upon the EOF condition of input, ++ however in the presence of BZ #27650 it will terminate prematurely ++ with characters still outstanding in input. Diagnose the condition ++ and return status accordingly. */ ++ ++int ++do_test (void) ++{ ++ static cookie_io_functions_t io_funcs = { .read = io_read }; ++ unsigned int written = 0; ++ FILE *in; ++ int v; ++ ++ mtrace (); ++ ++ in = fopencookie (&written, "r", io_funcs); ++ if (in == NULL) ++ { ++ FAIL ("fopencookie: %m"); ++ goto out; ++ } ++ ++ v = fscanf (in, "%*[^\n]"); ++ if (ferror (in)) ++ { ++ FAIL ("fscanf: input failure, at %u: %m", written); ++ goto out_close; ++ } ++ else if (v == EOF) ++ { ++ FAIL ("fscanf: unexpected end of file, at %u", written); ++ goto out_close; ++ } ++ ++ if (!feof (in)) ++ { ++ v = fgetc (in); ++ if (ferror (in)) ++ FAIL ("fgetc: input failure: %m"); ++ else if (v == EOF) ++ FAIL ("fgetc: unexpected end of file after missing end of file"); ++ else if (v == '\n') ++ FAIL ("unexpected new line character received"); ++ else ++ FAIL ("character received after end of file expected: \\x%02x", v); ++ } ++ ++out_close: ++ if (fclose (in) != 0) ++ FAIL ("fclose: %m"); ++ ++out: ++ return EXIT_SUCCESS; ++} ++ ++#define TIMEOUT (DEFAULT_TIMEOUT * 8) ++#include diff --git a/SOURCES/glibc-RHEL-54447-4.patch b/SOURCES/glibc-RHEL-54447-4.patch new file mode 100644 index 0000000..525ce22 --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-4.patch @@ -0,0 +1,143 @@ +commit af68f0f6755c3b82ecef6dd67079df64eee8d946 +Author: Siddhesh Poyarekar +Date: Wed Aug 14 19:20:04 2024 -0400 + + Make tst-ungetc use libsupport + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell + (cherry picked from commit 3f7df7e757f4efec38e45d4068e5492efcac4856) + (cherry picked from commit 87a1968a72e4b4e5436f3e2be1ed8a8d5a5862c7) + +diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c +index 1344b2b591e3d6b1..5c808f073419f00b 100644 +--- a/stdio-common/tst-ungetc.c ++++ b/stdio-common/tst-ungetc.c +@@ -1,70 +1,72 @@ +-/* Test for ungetc bugs. */ ++/* Test for ungetc bugs. ++ Copyright (C) 1996-2024 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 ++ 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 ++ . */ + + #include + #include +-#include +- +-#undef assert +-#define assert(x) \ +- if (!(x)) \ +- { \ +- fputs ("test failed: " #x "\n", stderr); \ +- retval = 1; \ +- goto the_end; \ +- } ++#include ++#include ++#include ++#include ++#include + +-int +-main (int argc, char *argv[]) ++static int ++do_test (void) + { +- char name[] = "/tmp/tst-ungetc.XXXXXX"; ++ char *name = NULL; + FILE *fp = NULL; +- int retval = 0; + int c; + char buffer[64]; + +- int fd = mkstemp (name); ++ int fd = create_temp_file ("tst-ungetc.", &name); + if (fd == -1) +- { +- printf ("mkstemp failed: %m\n"); +- return 1; +- } +- close (fd); +- fp = fopen (name, "w"); +- assert (fp != NULL) +- fputs ("bla", fp); +- fclose (fp); +- fp = NULL; ++ FAIL_EXIT1 ("cannot create temporary file: %m"); ++ xclose (fd); + +- fp = fopen (name, "r"); +- assert (fp != NULL); +- assert (ungetc ('z', fp) == 'z'); +- assert (getc (fp) == 'z'); +- assert (getc (fp) == 'b'); +- assert (getc (fp) == 'l'); +- assert (ungetc ('m', fp) == 'm'); +- assert (getc (fp) == 'm'); +- assert ((c = getc (fp)) == 'a'); +- assert (getc (fp) == EOF); +- assert (ungetc (c, fp) == c); +- assert (feof (fp) == 0); +- assert (getc (fp) == c); +- assert (getc (fp) == EOF); +- fclose (fp); +- fp = NULL; ++ fp = xfopen (name, "w"); ++ fputs ("bla", fp); ++ xfclose (fp); + +- fp = fopen (name, "r"); +- assert (fp != NULL); +- assert (getc (fp) == 'b'); +- assert (getc (fp) == 'l'); +- assert (ungetc ('b', fp) == 'b'); +- assert (fread (buffer, 1, 64, fp) == 2); +- assert (buffer[0] == 'b'); +- assert (buffer[1] == 'a'); ++ fp = xfopen (name, "r"); ++ TEST_VERIFY_EXIT (ungetc ('z', fp) == 'z'); ++ TEST_VERIFY_EXIT (getc (fp) == 'z'); ++ TEST_VERIFY_EXIT (getc (fp) == 'b'); ++ TEST_VERIFY_EXIT (getc (fp) == 'l'); ++ TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm'); ++ TEST_VERIFY_EXIT (getc (fp) == 'm'); ++ TEST_VERIFY_EXIT ((c = getc (fp)) == 'a'); ++ TEST_VERIFY_EXIT (getc (fp) == EOF); ++ TEST_VERIFY_EXIT (ungetc (c, fp) == c); ++ TEST_VERIFY_EXIT (feof (fp) == 0); ++ TEST_VERIFY_EXIT (getc (fp) == c); ++ TEST_VERIFY_EXIT (getc (fp) == EOF); ++ xfclose (fp); + +-the_end: +- if (fp != NULL) +- fclose (fp); +- unlink (name); ++ fp = xfopen (name, "r"); ++ TEST_VERIFY_EXIT (getc (fp) == 'b'); ++ TEST_VERIFY_EXIT (getc (fp) == 'l'); ++ TEST_VERIFY_EXIT (ungetc ('b', fp) == 'b'); ++ TEST_VERIFY_EXIT (fread (buffer, 1, 64, fp) == 2); ++ TEST_VERIFY_EXIT (buffer[0] == 'b'); ++ TEST_VERIFY_EXIT (buffer[1] == 'a'); ++ xfclose (fp); + +- return retval; ++ return 0; + } ++ ++#include diff --git a/SOURCES/glibc-RHEL-54447-5.patch b/SOURCES/glibc-RHEL-54447-5.patch new file mode 100644 index 0000000..d2d72aa --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-5.patch @@ -0,0 +1,71 @@ +commit 01a731da41a6d47cdd6b90f0da1d89dd8cf2b9cd +Author: Siddhesh Poyarekar +Date: Tue Aug 13 21:00:06 2024 -0400 + + ungetc: Fix uninitialized read when putting into unused streams [BZ #27821] + + When ungetc is called on an unused stream, the backup buffer is + allocated without the main get area being present. This results in + every subsequent ungetc (as the stream remains in the backup area) + checking uninitialized memory in the backup buffer when trying to put a + character back into the stream. + + Avoid comparing the input character with buffer contents when in backup + to avoid this uninitialized read. The uninitialized read is harmless in + this context since the location is promptly overwritten with the input + character, thus fulfilling ungetc functionality. + + Also adjust wording in the manual to drop the paragraph that says glibc + cannot do multiple ungetc back to back since with this change, ungetc + can actually do this. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell + (cherry picked from commit cdf0f88f97b0aaceb894cc02b21159d148d7065c) + (cherry picked from commit 804d3c8db79db204154dcf5e11a76f14fdddc570) + +diff --git a/libio/genops.c b/libio/genops.c +index fa509f6219abaf23..a5dd6a06d9e259d8 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -635,7 +635,7 @@ _IO_sputbackc (FILE *fp, int c) + { + int result; + +- if (fp->_IO_read_ptr > fp->_IO_read_base ++ if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp) + && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c) + { + fp->_IO_read_ptr--; +diff --git a/manual/stdio.texi b/manual/stdio.texi +index d3d855fc62b8768b..60ab7e7a5d505bb6 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -1467,11 +1467,9 @@ program; usually @code{ungetc} is used only to unread a character that + was just read from the same stream. @Theglibc{} supports this + even on files opened in binary mode, but other systems might not. + +-@Theglibc{} only supports one character of pushback---in other +-words, it does not work to call @code{ungetc} twice without doing input +-in between. Other systems might let you push back multiple characters; +-then reading from the stream retrieves the characters in the reverse +-order that they were pushed. ++@Theglibc{} supports pushing back multiple characters; subsequently ++reading from the stream retrieves the characters in the reverse order ++that they were pushed. + + Pushing back characters doesn't alter the file; only the internal + buffering for the stream is affected. If a file positioning function +diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c +index 5c808f073419f00b..388b202493ddd586 100644 +--- a/stdio-common/tst-ungetc.c ++++ b/stdio-common/tst-ungetc.c +@@ -48,6 +48,8 @@ do_test (void) + TEST_VERIFY_EXIT (getc (fp) == 'b'); + TEST_VERIFY_EXIT (getc (fp) == 'l'); + TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm'); ++ TEST_VERIFY_EXIT (ungetc ('n', fp) == 'n'); ++ TEST_VERIFY_EXIT (getc (fp) == 'n'); + TEST_VERIFY_EXIT (getc (fp) == 'm'); + TEST_VERIFY_EXIT ((c = getc (fp)) == 'a'); + TEST_VERIFY_EXIT (getc (fp) == EOF); diff --git a/SOURCES/glibc-RHEL-54447-6.patch b/SOURCES/glibc-RHEL-54447-6.patch new file mode 100644 index 0000000..006e312 --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-6.patch @@ -0,0 +1,136 @@ +commit a5cd39541396b91d90cc611858ee7b3355fcfe47 +Author: Siddhesh Poyarekar +Date: Tue Aug 13 21:08:49 2024 -0400 + + ungetc: Fix backup buffer leak on program exit [BZ #27821] + + If a file descriptor is left unclosed and is cleaned up by _IO_cleanup + on exit, its backup buffer remains unfreed, registering as a leak in + valgrind. This is not strictly an issue since (1) the program should + ideally be closing the stream once it's not in use and (2) the program + is about to exit anyway, so keeping the backup buffer around a wee bit + longer isn't a real problem. Free it anyway to keep valgrind happy + when the streams in question are the standard ones, i.e. stdout, stdin + or stderr. + + Also, the _IO_have_backup macro checks for _IO_save_base, + which is a roundabout way to check for a backup buffer instead of + directly looking for _IO_backup_base. The roundabout check breaks when + the main get area has not been used and user pushes a char into the + backup buffer with ungetc. Fix this to use the _IO_backup_base + directly. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Carlos O'Donell + (cherry picked from commit 3e1d8d1d1dca24ae90df2ea826a8916896fc7e77) + (cherry picked from commit b9f72bd5de931eac39219018c2fa319a449bb2cf) + +diff --git a/libio/genops.c b/libio/genops.c +index a5dd6a06d9e259d8..b5fc53fd1ef6e911 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -796,6 +796,12 @@ _IO_unbuffer_all (void) + legacy = 1; + #endif + ++ /* Free up the backup area if it was ever allocated. */ ++ if (_IO_have_backup (fp)) ++ _IO_free_backup_area (fp); ++ if (fp->_mode > 0 && _IO_have_wbackup (fp)) ++ _IO_free_wbackup_area (fp); ++ + if (! (fp->_flags & _IO_UNBUFFERED) + /* Iff stream is un-orientated, it wasn't used. */ + && (legacy || fp->_mode != 0)) +diff --git a/libio/libioP.h b/libio/libioP.h +index dc9a2ce9c8d7744c..bab5f3770f0760c4 100644 +--- a/libio/libioP.h ++++ b/libio/libioP.h +@@ -529,8 +529,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW; + ((__fp)->_wide_data->_IO_write_base \ + = (__fp)->_wide_data->_IO_write_ptr = __p, \ + (__fp)->_wide_data->_IO_write_end = (__ep)) +-#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL) +-#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL) ++#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL) ++#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL) + #define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP) + #define _IO_have_markers(fp) ((fp)->_markers != NULL) + #define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base) +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 08bedd01be61a55d..f10bf28878e0aebc 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -201,6 +201,7 @@ tests := \ + tst-swscanf \ + tst-tmpnam \ + tst-ungetc \ ++ tst-ungetc-leak \ + tst-unlockedio \ + tst-vfprintf-mbs-prec \ + tst-vfprintf-user-type \ +@@ -229,6 +230,7 @@ tests-special += \ + $(objpfx)tst-printfsz-islongdouble.out \ + $(objpfx)tst-setvbuf1-cmp.out \ + $(objpfx)tst-unbputc.out \ ++ $(objpfx)tst-ungetc-leak-mem.out \ + $(objpfx)tst-vfprintf-width-prec-mem.out \ + # tests-special + +@@ -243,6 +245,8 @@ generated += \ + tst-printf-fp-leak-mem.out \ + tst-printf-fp-leak.mtrace \ + tst-scanf-bz27650.mtrace \ ++ tst-ungetc-leak-mem.out \ ++ tst-ungetc-leak.mtrace \ + tst-vfprintf-width-prec-mem.out \ + tst-vfprintf-width-prec.mtrace \ + # generated +@@ -288,6 +292,9 @@ tst-printf-fp-leak-ENV = \ + tst-scanf-bz27650-ENV = \ + MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \ + LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-ungetc-leak-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-ungetc-leak.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-ungetc-leak.c b/stdio-common/tst-ungetc-leak.c +new file mode 100644 +index 0000000000000000..6c5152b43f80b217 +--- /dev/null ++++ b/stdio-common/tst-ungetc-leak.c +@@ -0,0 +1,32 @@ ++/* Test for memory leak with ungetc when stream is unused. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ TEST_COMPARE (ungetc('y', stdin), 'y'); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-54447-7.patch b/SOURCES/glibc-RHEL-54447-7.patch new file mode 100644 index 0000000..9446d2a --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-7.patch @@ -0,0 +1,83 @@ +commit 9d26e50364def249e483b1601beb6ecf9141ecc7 +Author: Maciej W. Rozycki +Date: Fri Jul 26 13:21:34 2024 +0100 + + posix: Use facilities in tst-truncate and tst-truncate64 + + Remove local FAIL macro in favor to FAIL_RET from , + which provides equivalent reporting, with the name of the file of the + failure site additionally included, for the tst-truncate-common core + shared between the tst-truncate and tst-truncate64 tests. + + Reviewed-by: DJ Delorie + (cherry picked from commit fe47595504a55e7bb992f8928533df154b510383) + +diff --git a/posix/tst-truncate-common.c b/posix/tst-truncate-common.c +index 00c999d372693bfa..1f6c4bd256a638f9 100644 +--- a/posix/tst-truncate-common.c ++++ b/posix/tst-truncate-common.c +@@ -21,6 +21,8 @@ + #include + #include + ++#include ++ + static void do_prepare (void); + #define PREPARE(argc, argv) do_prepare () + static int do_test (void); +@@ -42,9 +44,6 @@ do_prepare (void) + } + } + +-#define FAIL(str) \ +- do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0) +- + static int + do_test_with_offset (off_t offset) + { +@@ -54,35 +53,35 @@ do_test_with_offset (off_t offset) + memset (buf, 0xcf, sizeof (buf)); + + if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf)) +- FAIL ("write failed"); ++ FAIL_RET ("write failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf))) +- FAIL ("initial size wrong"); ++ FAIL_RET ("initial size wrong"); + + if (ftruncate (temp_fd, offset + 800) < 0) +- FAIL ("size reduction with ftruncate failed"); ++ FAIL_RET ("size reduction with ftruncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800)) +- FAIL ("size after reduction with ftruncate is incorrect"); ++ FAIL_RET ("size after reduction with ftruncate is incorrect"); + + /* The following test covers more than POSIX. POSIX does not require + that ftruncate() can increase the file size. But we are testing + Unix systems. */ + if (ftruncate (temp_fd, offset + 1200) < 0) +- FAIL ("size increate with ftruncate failed"); ++ FAIL_RET ("size increate with ftruncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200)) +- FAIL ("size after increase is incorrect"); ++ FAIL_RET ("size after increase is incorrect"); + + if (truncate (temp_filename, offset + 800) < 0) +- FAIL ("size reduction with truncate failed"); ++ FAIL_RET ("size reduction with truncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800)) +- FAIL ("size after reduction with truncate incorrect"); ++ FAIL_RET ("size after reduction with truncate incorrect"); + + /* The following test covers more than POSIX. POSIX does not require + that truncate() can increase the file size. But we are testing + Unix systems. */ + if (truncate (temp_filename, (offset + 1200)) < 0) +- FAIL ("size increase with truncate failed"); ++ FAIL_RET ("size increase with truncate failed"); + if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200)) +- FAIL ("size increase with truncate is incorrect"); ++ FAIL_RET ("size increase with truncate is incorrect"); + + return 0; + } diff --git a/SOURCES/glibc-RHEL-54447-8.patch b/SOURCES/glibc-RHEL-54447-8.patch new file mode 100644 index 0000000..b4e804f --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-8.patch @@ -0,0 +1,129 @@ +commit c21ca2a696c03ff3f3931768a3ada234eebf6337 +Author: Maciej W. Rozycki +Date: Fri Jul 26 13:21:34 2024 +0100 + + nptl: Use facilities in tst-setuid3 + + Remove local FAIL macro in favor to FAIL_EXIT1 from , + which provides equivalent reporting, with the name of the file and the + line number within of the failure site additionally included. Remove + FAIL_ERR altogether and include ": %m" explicitly with the format string + supplied to FAIL_EXIT1 as there seems little value to have a separate + macro just for this. + + Reviewed-by: DJ Delorie + (cherry picked from commit 8c98195af6e6f1ce21743fc26c723e0f7e45bcf2) + +diff --git a/sysdeps/pthread/tst-setuid3.c b/sysdeps/pthread/tst-setuid3.c +index 254555960e1ffe74..88a2a3ef20e273f7 100644 +--- a/sysdeps/pthread/tst-setuid3.c ++++ b/sysdeps/pthread/tst-setuid3.c +@@ -15,24 +15,19 @@ + License along with the GNU C Library; if not, see + . */ + +-#include + #include + #include + #include + #include + ++#include ++ + /* The test must run under a non-privileged user ID. */ + static const uid_t test_uid = 1; + + static pthread_barrier_t barrier1; + static pthread_barrier_t barrier2; + +-#define FAIL(fmt, ...) \ +- do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0) +- +-#define FAIL_ERR(fmt, ...) \ +- do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0) +- + /* True if x is not a successful return code from pthread_barrier_wait. */ + static inline bool + is_invalid_barrier_ret (int x) +@@ -45,10 +40,10 @@ thread_func (void *ctx __attribute__ ((unused))) + { + int ret = pthread_barrier_wait (&barrier1); + if (is_invalid_barrier_ret (ret)) +- FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret); ++ FAIL_EXIT1 ("pthread_barrier_wait (barrier1) (on thread): %d", ret); + ret = pthread_barrier_wait (&barrier2); + if (is_invalid_barrier_ret (ret)) +- FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret); ++ FAIL_EXIT1 ("pthread_barrier_wait (barrier2) (on thread): %d", ret); + return NULL; + } + +@@ -59,13 +54,13 @@ setuid_failure (int phase) + switch (ret) + { + case 0: +- FAIL ("setuid succeeded unexpectedly in phase %d", phase); ++ FAIL_EXIT1 ("setuid succeeded unexpectedly in phase %d", phase); + case -1: + if (errno != EPERM) +- FAIL_ERR ("setuid phase %d", phase); ++ FAIL_EXIT1 ("setuid phase %d: %m", phase); + break; + default: +- FAIL ("invalid setuid return value in phase %d: %d", phase, ret); ++ FAIL_EXIT1 ("invalid setuid return value in phase %d: %d", phase, ret); + } + } + +@@ -74,42 +69,42 @@ do_test (void) + { + if (getuid () == 0) + if (setuid (test_uid) != 0) +- FAIL_ERR ("setuid (%u)", (unsigned) test_uid); ++ FAIL_EXIT1 ("setuid (%u): %m", (unsigned) test_uid); + if (setuid (getuid ())) +- FAIL_ERR ("setuid (%s)", "getuid ()"); ++ FAIL_EXIT1 ("setuid (%s): %m", "getuid ()"); + setuid_failure (1); + + int ret = pthread_barrier_init (&barrier1, NULL, 2); + if (ret != 0) +- FAIL ("pthread_barrier_init (barrier1): %d", ret); ++ FAIL_EXIT1 ("pthread_barrier_init (barrier1): %d", ret); + ret = pthread_barrier_init (&barrier2, NULL, 2); + if (ret != 0) +- FAIL ("pthread_barrier_init (barrier2): %d", ret); ++ FAIL_EXIT1 ("pthread_barrier_init (barrier2): %d", ret); + + pthread_t thread; + ret = pthread_create (&thread, NULL, thread_func, NULL); + if (ret != 0) +- FAIL ("pthread_create: %d", ret); ++ FAIL_EXIT1 ("pthread_create: %d", ret); + + /* Ensure that the thread is running properly. */ + ret = pthread_barrier_wait (&barrier1); + if (is_invalid_barrier_ret (ret)) +- FAIL ("pthread_barrier_wait (barrier1): %d", ret); ++ FAIL_EXIT1 ("pthread_barrier_wait (barrier1): %d", ret); + + setuid_failure (2); + + /* Check success case. */ + if (setuid (getuid ()) != 0) +- FAIL_ERR ("setuid (%s)", "getuid ()"); ++ FAIL_EXIT1 ("setuid (%s): %m", "getuid ()"); + + /* Shutdown. */ + ret = pthread_barrier_wait (&barrier2); + if (is_invalid_barrier_ret (ret)) +- FAIL ("pthread_barrier_wait (barrier2): %d", ret); ++ FAIL_EXIT1 ("pthread_barrier_wait (barrier2): %d", ret); + + ret = pthread_join (thread, NULL); + if (ret != 0) +- FAIL ("pthread_join: %d", ret); ++ FAIL_EXIT1 ("pthread_join: %d", ret); + + return 0; + } diff --git a/SOURCES/glibc-RHEL-54447-9.patch b/SOURCES/glibc-RHEL-54447-9.patch new file mode 100644 index 0000000..18e63df --- /dev/null +++ b/SOURCES/glibc-RHEL-54447-9.patch @@ -0,0 +1,27 @@ +commit ae4d44b1d501421ad9a3af95279b8f4d1546f1ce +Author: Siddhesh Poyarekar +Date: Tue Sep 3 14:58:33 2024 -0400 + + libio: Attempt wide backup free only for non-legacy code + + _wide_data and _mode are not available in legacy code, so do not attempt + to free the wide backup buffer in legacy code. + + Resolves: BZ #32137 and BZ #27821 + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Florian Weimer + +diff --git a/libio/genops.c b/libio/genops.c +index b5fc53fd1ef6e911..99ef9d03505f3238 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -799,7 +799,7 @@ _IO_unbuffer_all (void) + /* Free up the backup area if it was ever allocated. */ + if (_IO_have_backup (fp)) + _IO_free_backup_area (fp); +- if (fp->_mode > 0 && _IO_have_wbackup (fp)) ++ if (!legacy && fp->_mode > 0 && _IO_have_wbackup (fp)) + _IO_free_wbackup_area (fp); + + if (! (fp->_flags & _IO_UNBUFFERED) diff --git a/SOURCES/glibc-RHEL-56032.patch b/SOURCES/glibc-RHEL-56032.patch new file mode 100644 index 0000000..a0e38e7 --- /dev/null +++ b/SOURCES/glibc-RHEL-56032.patch @@ -0,0 +1,845 @@ +From e1d3312015e8f70344620375aedf91afe7e7e7a4 Mon Sep 17 00:00:00 2001 +From: lijianglin +Date: Tue, 27 Jun 2023 20:15:49 +0800 +Subject: add GB18030-2022 charmap and test the entire GB18030 charmap [BZ + #30243] + +support GB18030-2022 after add and change some transcoding relationship +of GB18030-2022.Details are as follows: +add 25 transcoding relationship + UE81E 0x82359037 + UE826 0x82359038 + UE82B 0x82359039 + UE82C 0x82359130 + UE832 0x82359131 + UE843 0x82359132 + UE854 0x82359133 + UE864 0x82359134 + UE78D 0x84318236 + UE78F 0x84318237 + UE78E 0x84318238 + UE790 0x84318239 + UE791 0x84318330 + UE792 0x84318331 + UE793 0x84318332 + UE794 0x84318333 + UE795 0x84318334 + UE796 0x84318335 + UE816 0xfe51 + UE817 0xfe52 + UE818 0xfe53 + UE831 0xfe6c + UE83B 0xfe76 + UE855 0xfe91 +change 6 transcoding relationship + U20087 0x95329031 + U20089 0x95329033 + U200CC 0x95329730 + U215D7 0x9536b937 + U2298F 0x9630ba35 + U241FE 0x9635b630 +Test the entire GB18030 charmap, not only the Unicode BMP part. + +Co-authored-by: yangyanchao +Co-authored-by: liqingqing +Co-authored-by: Bruno Haible +Reviewed-by: Andreas Schwab +Reviewed-by: Mike FABIAN + +diff --git a/iconvdata/gb18030.c b/iconvdata/gb18030.c +index 9996a59eaf..be6cfe652c 100644 +--- a/iconvdata/gb18030.c ++++ b/iconvdata/gb18030.c +@@ -6009,49 +6009,50 @@ static const uint16_t __twobyte_to_ucs[] = + [0x5dc2] = 0xfa0e, [0x5dc3] = 0xfa0f, [0x5dc4] = 0xfa11, [0x5dc5] = 0xfa13, + [0x5dc6] = 0xfa14, [0x5dc7] = 0xfa18, [0x5dc8] = 0xfa1f, [0x5dc9] = 0xfa20, + [0x5dca] = 0xfa21, [0x5dcb] = 0xfa23, [0x5dcc] = 0xfa24, [0x5dcd] = 0xfa27, +- [0x5dce] = 0xfa28, [0x5dcf] = 0xfa29, [0x5dd0] = 0x2e81, [0x5dd4] = 0x2e84, +- [0x5dd5] = 0x3473, [0x5dd6] = 0x3447, [0x5dd7] = 0x2e88, [0x5dd8] = 0x2e8b, +- [0x5dd9] = 0x9fb4, [0x5dda] = 0x359e, [0x5ddb] = 0x361a, [0x5ddc] = 0x360e, +- [0x5ddd] = 0x2e8c, [0x5dde] = 0x2e97, [0x5ddf] = 0x396e, [0x5de0] = 0x3918, +- [0x5de1] = 0x9fb5, [0x5de2] = 0x39cf, [0x5de3] = 0x39df, [0x5de4] = 0x3a73, +- [0x5de5] = 0x39d0, [0x5de6] = 0x9fb6, [0x5de7] = 0x9fb7, [0x5de8] = 0x3b4e, +- [0x5de9] = 0x3c6e, [0x5dea] = 0x3ce0, [0x5deb] = 0x2ea7, [0x5ded] = 0x9fb8, ++ [0x5dce] = 0xfa28, [0x5dcf] = 0xfa29, [0x5dd0] = 0x2e81, [0x5dd1] = 0xe816, ++ [0x5dd2] = 0xe817, [0x5dd3] = 0xe818, [0x5dd4] = 0x2e84, [0x5dd5] = 0x3473, ++ [0x5dd6] = 0x3447, [0x5dd7] = 0x2e88, [0x5dd8] = 0x2e8b, [0x5dd9] = 0x9fb4, ++ [0x5dda] = 0x359e, [0x5ddb] = 0x361a, [0x5ddc] = 0x360e, [0x5ddd] = 0x2e8c, ++ [0x5dde] = 0x2e97, [0x5ddf] = 0x396e, [0x5de0] = 0x3918, [0x5de1] = 0x9fb5, ++ [0x5de2] = 0x39cf, [0x5de3] = 0x39df, [0x5de4] = 0x3a73, [0x5de5] = 0x39d0, ++ [0x5de6] = 0x9fb6, [0x5de7] = 0x9fb7, [0x5de8] = 0x3b4e, [0x5de9] = 0x3c6e, ++ [0x5dea] = 0x3ce0, [0x5deb] = 0x2ea7, [0x5dec] = 0xe831, [0x5ded] = 0x9fb8, + [0x5dee] = 0x2eaa, [0x5def] = 0x4056, [0x5df0] = 0x415f, [0x5df1] = 0x2eae, + [0x5df2] = 0x4337, [0x5df3] = 0x2eb3, [0x5df4] = 0x2eb6, [0x5df5] = 0x2eb7, +- [0x5df7] = 0x43b1, [0x5df8] = 0x43ac, [0x5df9] = 0x2ebb, [0x5dfa] = 0x43dd, +- [0x5dfb] = 0x44d6, [0x5dfc] = 0x4661, [0x5dfd] = 0x464c, [0x5dfe] = 0x9fb9, +- [0x5e00] = 0x4723, [0x5e01] = 0x4729, [0x5e02] = 0x477c, [0x5e03] = 0x478d, +- [0x5e04] = 0x2eca, [0x5e05] = 0x4947, [0x5e06] = 0x497a, [0x5e07] = 0x497d, +- [0x5e08] = 0x4982, [0x5e09] = 0x4983, [0x5e0a] = 0x4985, [0x5e0b] = 0x4986, +- [0x5e0c] = 0x499f, [0x5e0d] = 0x499b, [0x5e0e] = 0x49b7, [0x5e0f] = 0x49b6, +- [0x5e10] = 0x9fba, [0x5e12] = 0x4ca3, [0x5e13] = 0x4c9f, [0x5e14] = 0x4ca0, +- [0x5e15] = 0x4ca1, [0x5e16] = 0x4c77, [0x5e17] = 0x4ca2, [0x5e18] = 0x4d13, +- [0x5e19] = 0x4d14, [0x5e1a] = 0x4d15, [0x5e1b] = 0x4d16, [0x5e1c] = 0x4d17, +- [0x5e1d] = 0x4d18, [0x5e1e] = 0x4d19, [0x5e1f] = 0x4dae, [0x5e20] = 0x9fbb, +- [0x5e21] = 0xe468, [0x5e22] = 0xe469, [0x5e23] = 0xe46a, [0x5e24] = 0xe46b, +- [0x5e25] = 0xe46c, [0x5e26] = 0xe46d, [0x5e27] = 0xe46e, [0x5e28] = 0xe46f, +- [0x5e29] = 0xe470, [0x5e2a] = 0xe471, [0x5e2b] = 0xe472, [0x5e2c] = 0xe473, +- [0x5e2d] = 0xe474, [0x5e2e] = 0xe475, [0x5e2f] = 0xe476, [0x5e30] = 0xe477, +- [0x5e31] = 0xe478, [0x5e32] = 0xe479, [0x5e33] = 0xe47a, [0x5e34] = 0xe47b, +- [0x5e35] = 0xe47c, [0x5e36] = 0xe47d, [0x5e37] = 0xe47e, [0x5e38] = 0xe47f, +- [0x5e39] = 0xe480, [0x5e3a] = 0xe481, [0x5e3b] = 0xe482, [0x5e3c] = 0xe483, +- [0x5e3d] = 0xe484, [0x5e3e] = 0xe485, [0x5e3f] = 0xe486, [0x5e40] = 0xe487, +- [0x5e41] = 0xe488, [0x5e42] = 0xe489, [0x5e43] = 0xe48a, [0x5e44] = 0xe48b, +- [0x5e45] = 0xe48c, [0x5e46] = 0xe48d, [0x5e47] = 0xe48e, [0x5e48] = 0xe48f, +- [0x5e49] = 0xe490, [0x5e4a] = 0xe491, [0x5e4b] = 0xe492, [0x5e4c] = 0xe493, +- [0x5e4d] = 0xe494, [0x5e4e] = 0xe495, [0x5e4f] = 0xe496, [0x5e50] = 0xe497, +- [0x5e51] = 0xe498, [0x5e52] = 0xe499, [0x5e53] = 0xe49a, [0x5e54] = 0xe49b, +- [0x5e55] = 0xe49c, [0x5e56] = 0xe49d, [0x5e57] = 0xe49e, [0x5e58] = 0xe49f, +- [0x5e59] = 0xe4a0, [0x5e5a] = 0xe4a1, [0x5e5b] = 0xe4a2, [0x5e5c] = 0xe4a3, +- [0x5e5d] = 0xe4a4, [0x5e5e] = 0xe4a5, [0x5e5f] = 0xe4a6, [0x5e60] = 0xe4a7, +- [0x5e61] = 0xe4a8, [0x5e62] = 0xe4a9, [0x5e63] = 0xe4aa, [0x5e64] = 0xe4ab, +- [0x5e65] = 0xe4ac, [0x5e66] = 0xe4ad, [0x5e67] = 0xe4ae, [0x5e68] = 0xe4af, +- [0x5e69] = 0xe4b0, [0x5e6a] = 0xe4b1, [0x5e6b] = 0xe4b2, [0x5e6c] = 0xe4b3, +- [0x5e6d] = 0xe4b4, [0x5e6e] = 0xe4b5, [0x5e6f] = 0xe4b6, [0x5e70] = 0xe4b7, +- [0x5e71] = 0xe4b8, [0x5e72] = 0xe4b9, [0x5e73] = 0xe4ba, [0x5e74] = 0xe4bb, +- [0x5e75] = 0xe4bc, [0x5e76] = 0xe4bd, [0x5e77] = 0xe4be, [0x5e78] = 0xe4bf, +- [0x5e79] = 0xe4c0, [0x5e7a] = 0xe4c1, [0x5e7b] = 0xe4c2, [0x5e7c] = 0xe4c3, +- [0x5e7d] = 0xe4c4, [0x5e7e] = 0xe4c5, ++ [0x5df6] = 0xe83b, [0x5df7] = 0x43b1, [0x5df8] = 0x43ac, [0x5df9] = 0x2ebb, ++ [0x5dfa] = 0x43dd, [0x5dfb] = 0x44d6, [0x5dfc] = 0x4661, [0x5dfd] = 0x464c, ++ [0x5dfe] = 0x9fb9, [0x5e00] = 0x4723, [0x5e01] = 0x4729, [0x5e02] = 0x477c, ++ [0x5e03] = 0x478d, [0x5e04] = 0x2eca, [0x5e05] = 0x4947, [0x5e06] = 0x497a, ++ [0x5e07] = 0x497d, [0x5e08] = 0x4982, [0x5e09] = 0x4983, [0x5e0a] = 0x4985, ++ [0x5e0b] = 0x4986, [0x5e0c] = 0x499f, [0x5e0d] = 0x499b, [0x5e0e] = 0x49b7, ++ [0x5e0f] = 0x49b6, [0x5e10] = 0x9fba, [0x5e11] = 0xe855, [0x5e12] = 0x4ca3, ++ [0x5e13] = 0x4c9f, [0x5e14] = 0x4ca0, [0x5e15] = 0x4ca1, [0x5e16] = 0x4c77, ++ [0x5e17] = 0x4ca2, [0x5e18] = 0x4d13, [0x5e19] = 0x4d14, [0x5e1a] = 0x4d15, ++ [0x5e1b] = 0x4d16, [0x5e1c] = 0x4d17, [0x5e1d] = 0x4d18, [0x5e1e] = 0x4d19, ++ [0x5e1f] = 0x4dae, [0x5e20] = 0x9fbb, [0x5e21] = 0xe468, [0x5e22] = 0xe469, ++ [0x5e23] = 0xe46a, [0x5e24] = 0xe46b, [0x5e25] = 0xe46c, [0x5e26] = 0xe46d, ++ [0x5e27] = 0xe46e, [0x5e28] = 0xe46f, [0x5e29] = 0xe470, [0x5e2a] = 0xe471, ++ [0x5e2b] = 0xe472, [0x5e2c] = 0xe473, [0x5e2d] = 0xe474, [0x5e2e] = 0xe475, ++ [0x5e2f] = 0xe476, [0x5e30] = 0xe477, [0x5e31] = 0xe478, [0x5e32] = 0xe479, ++ [0x5e33] = 0xe47a, [0x5e34] = 0xe47b, [0x5e35] = 0xe47c, [0x5e36] = 0xe47d, ++ [0x5e37] = 0xe47e, [0x5e38] = 0xe47f, [0x5e39] = 0xe480, [0x5e3a] = 0xe481, ++ [0x5e3b] = 0xe482, [0x5e3c] = 0xe483, [0x5e3d] = 0xe484, [0x5e3e] = 0xe485, ++ [0x5e3f] = 0xe486, [0x5e40] = 0xe487, [0x5e41] = 0xe488, [0x5e42] = 0xe489, ++ [0x5e43] = 0xe48a, [0x5e44] = 0xe48b, [0x5e45] = 0xe48c, [0x5e46] = 0xe48d, ++ [0x5e47] = 0xe48e, [0x5e48] = 0xe48f, [0x5e49] = 0xe490, [0x5e4a] = 0xe491, ++ [0x5e4b] = 0xe492, [0x5e4c] = 0xe493, [0x5e4d] = 0xe494, [0x5e4e] = 0xe495, ++ [0x5e4f] = 0xe496, [0x5e50] = 0xe497, [0x5e51] = 0xe498, [0x5e52] = 0xe499, ++ [0x5e53] = 0xe49a, [0x5e54] = 0xe49b, [0x5e55] = 0xe49c, [0x5e56] = 0xe49d, ++ [0x5e57] = 0xe49e, [0x5e58] = 0xe49f, [0x5e59] = 0xe4a0, [0x5e5a] = 0xe4a1, ++ [0x5e5b] = 0xe4a2, [0x5e5c] = 0xe4a3, [0x5e5d] = 0xe4a4, [0x5e5e] = 0xe4a5, ++ [0x5e5f] = 0xe4a6, [0x5e60] = 0xe4a7, [0x5e61] = 0xe4a8, [0x5e62] = 0xe4a9, ++ [0x5e63] = 0xe4aa, [0x5e64] = 0xe4ab, [0x5e65] = 0xe4ac, [0x5e66] = 0xe4ad, ++ [0x5e67] = 0xe4ae, [0x5e68] = 0xe4af, [0x5e69] = 0xe4b0, [0x5e6a] = 0xe4b1, ++ [0x5e6b] = 0xe4b2, [0x5e6c] = 0xe4b3, [0x5e6d] = 0xe4b4, [0x5e6e] = 0xe4b5, ++ [0x5e6f] = 0xe4b6, [0x5e70] = 0xe4b7, [0x5e71] = 0xe4b8, [0x5e72] = 0xe4b9, ++ [0x5e73] = 0xe4ba, [0x5e74] = 0xe4bb, [0x5e75] = 0xe4bc, [0x5e76] = 0xe4bd, ++ [0x5e77] = 0xe4be, [0x5e78] = 0xe4bf, [0x5e79] = 0xe4c0, [0x5e7a] = 0xe4c1, ++ [0x5e7b] = 0xe4c2, [0x5e7c] = 0xe4c3, [0x5e7d] = 0xe4c4, [0x5e7e] = 0xe4c5, + }; + + /* Table for GB18030 -> UCS-4, containing the four-byte characters only, +@@ -8680,7 +8681,9 @@ static const uint16_t __fourbyte_to_ucs[0x99e2 - 6637 - 2110 - 14404 - 4295] = + [0x2838] = 0x9fa6, [0x2839] = 0x9fa7, [0x283a] = 0x9fa8, [0x283b] = 0x9fa9, + [0x283c] = 0x9faa, [0x283d] = 0x9fab, [0x283e] = 0x9fac, [0x283f] = 0x9fad, + [0x2840] = 0x9fae, [0x2841] = 0x9faf, [0x2842] = 0x9fb0, [0x2843] = 0x9fb1, +- [0x2844] = 0x9fb2, [0x2845] = 0x9fb3, [0x284e] = 0xe76c, [0x284f] = 0xe7c8, ++ [0x2844] = 0x9fb2, [0x2845] = 0x9fb3, [0x2846] = 0xe81e, [0x2847] = 0xe826, ++ [0x2848] = 0xe82b, [0x2849] = 0xe82c, [0x284a] = 0xe832, [0x284b] = 0xe843, ++ [0x284c] = 0xe854, [0x284d] = 0xe864, [0x284e] = 0xe76c, [0x284f] = 0xe7c8, + [0x2850] = 0xe7e7, [0x2851] = 0xe7e8, [0x2852] = 0xe7e9, [0x2853] = 0xe7ea, + [0x2854] = 0xe7eb, [0x2855] = 0xe7ec, [0x2856] = 0xe7ed, [0x2857] = 0xe7ee, + [0x2858] = 0xe7ef, [0x2859] = 0xe7f0, [0x285a] = 0xe7f1, [0x285b] = 0xe7f2, +@@ -9008,84 +9011,86 @@ static const uint16_t __fourbyte_to_ucs[0x99e2 - 6637 - 2110 - 14404 - 4295] = + [0x2d60] = 0xfe02, [0x2d61] = 0xfe03, [0x2d62] = 0xfe04, [0x2d63] = 0xfe05, + [0x2d64] = 0xfe06, [0x2d65] = 0xfe07, [0x2d66] = 0xfe08, [0x2d67] = 0xfe09, + [0x2d68] = 0xfe0a, [0x2d69] = 0xfe0b, [0x2d6a] = 0xfe0c, [0x2d6b] = 0xfe0d, +- [0x2d6c] = 0xfe0e, [0x2d6d] = 0xfe0f, [0x2d78] = 0xfe1a, [0x2d79] = 0xfe1b, +- [0x2d7a] = 0xfe1c, [0x2d7b] = 0xfe1d, [0x2d7c] = 0xfe1e, [0x2d7d] = 0xfe1f, +- [0x2d7e] = 0xfe20, [0x2d7f] = 0xfe21, [0x2d80] = 0xfe22, [0x2d81] = 0xfe23, +- [0x2d82] = 0xfe24, [0x2d83] = 0xfe25, [0x2d84] = 0xfe26, [0x2d85] = 0xfe27, +- [0x2d86] = 0xfe28, [0x2d87] = 0xfe29, [0x2d88] = 0xfe2a, [0x2d89] = 0xfe2b, +- [0x2d8a] = 0xfe2c, [0x2d8b] = 0xfe2d, [0x2d8c] = 0xfe2e, [0x2d8d] = 0xfe2f, +- [0x2d8e] = 0xfe32, [0x2d8f] = 0xfe45, [0x2d90] = 0xfe46, [0x2d91] = 0xfe47, +- [0x2d92] = 0xfe48, [0x2d93] = 0xfe53, [0x2d94] = 0xfe58, [0x2d95] = 0xfe67, +- [0x2d96] = 0xfe6c, [0x2d97] = 0xfe6d, [0x2d98] = 0xfe6e, [0x2d99] = 0xfe6f, +- [0x2d9a] = 0xfe70, [0x2d9b] = 0xfe71, [0x2d9c] = 0xfe72, [0x2d9d] = 0xfe73, +- [0x2d9e] = 0xfe74, [0x2d9f] = 0xfe75, [0x2da0] = 0xfe76, [0x2da1] = 0xfe77, +- [0x2da2] = 0xfe78, [0x2da3] = 0xfe79, [0x2da4] = 0xfe7a, [0x2da5] = 0xfe7b, +- [0x2da6] = 0xfe7c, [0x2da7] = 0xfe7d, [0x2da8] = 0xfe7e, [0x2da9] = 0xfe7f, +- [0x2daa] = 0xfe80, [0x2dab] = 0xfe81, [0x2dac] = 0xfe82, [0x2dad] = 0xfe83, +- [0x2dae] = 0xfe84, [0x2daf] = 0xfe85, [0x2db0] = 0xfe86, [0x2db1] = 0xfe87, +- [0x2db2] = 0xfe88, [0x2db3] = 0xfe89, [0x2db4] = 0xfe8a, [0x2db5] = 0xfe8b, +- [0x2db6] = 0xfe8c, [0x2db7] = 0xfe8d, [0x2db8] = 0xfe8e, [0x2db9] = 0xfe8f, +- [0x2dba] = 0xfe90, [0x2dbb] = 0xfe91, [0x2dbc] = 0xfe92, [0x2dbd] = 0xfe93, +- [0x2dbe] = 0xfe94, [0x2dbf] = 0xfe95, [0x2dc0] = 0xfe96, [0x2dc1] = 0xfe97, +- [0x2dc2] = 0xfe98, [0x2dc3] = 0xfe99, [0x2dc4] = 0xfe9a, [0x2dc5] = 0xfe9b, +- [0x2dc6] = 0xfe9c, [0x2dc7] = 0xfe9d, [0x2dc8] = 0xfe9e, [0x2dc9] = 0xfe9f, +- [0x2dca] = 0xfea0, [0x2dcb] = 0xfea1, [0x2dcc] = 0xfea2, [0x2dcd] = 0xfea3, +- [0x2dce] = 0xfea4, [0x2dcf] = 0xfea5, [0x2dd0] = 0xfea6, [0x2dd1] = 0xfea7, +- [0x2dd2] = 0xfea8, [0x2dd3] = 0xfea9, [0x2dd4] = 0xfeaa, [0x2dd5] = 0xfeab, +- [0x2dd6] = 0xfeac, [0x2dd7] = 0xfead, [0x2dd8] = 0xfeae, [0x2dd9] = 0xfeaf, +- [0x2dda] = 0xfeb0, [0x2ddb] = 0xfeb1, [0x2ddc] = 0xfeb2, [0x2ddd] = 0xfeb3, +- [0x2dde] = 0xfeb4, [0x2ddf] = 0xfeb5, [0x2de0] = 0xfeb6, [0x2de1] = 0xfeb7, +- [0x2de2] = 0xfeb8, [0x2de3] = 0xfeb9, [0x2de4] = 0xfeba, [0x2de5] = 0xfebb, +- [0x2de6] = 0xfebc, [0x2de7] = 0xfebd, [0x2de8] = 0xfebe, [0x2de9] = 0xfebf, +- [0x2dea] = 0xfec0, [0x2deb] = 0xfec1, [0x2dec] = 0xfec2, [0x2ded] = 0xfec3, +- [0x2dee] = 0xfec4, [0x2def] = 0xfec5, [0x2df0] = 0xfec6, [0x2df1] = 0xfec7, +- [0x2df2] = 0xfec8, [0x2df3] = 0xfec9, [0x2df4] = 0xfeca, [0x2df5] = 0xfecb, +- [0x2df6] = 0xfecc, [0x2df7] = 0xfecd, [0x2df8] = 0xfece, [0x2df9] = 0xfecf, +- [0x2dfa] = 0xfed0, [0x2dfb] = 0xfed1, [0x2dfc] = 0xfed2, [0x2dfd] = 0xfed3, +- [0x2dfe] = 0xfed4, [0x2dff] = 0xfed5, [0x2e00] = 0xfed6, [0x2e01] = 0xfed7, +- [0x2e02] = 0xfed8, [0x2e03] = 0xfed9, [0x2e04] = 0xfeda, [0x2e05] = 0xfedb, +- [0x2e06] = 0xfedc, [0x2e07] = 0xfedd, [0x2e08] = 0xfede, [0x2e09] = 0xfedf, +- [0x2e0a] = 0xfee0, [0x2e0b] = 0xfee1, [0x2e0c] = 0xfee2, [0x2e0d] = 0xfee3, +- [0x2e0e] = 0xfee4, [0x2e0f] = 0xfee5, [0x2e10] = 0xfee6, [0x2e11] = 0xfee7, +- [0x2e12] = 0xfee8, [0x2e13] = 0xfee9, [0x2e14] = 0xfeea, [0x2e15] = 0xfeeb, +- [0x2e16] = 0xfeec, [0x2e17] = 0xfeed, [0x2e18] = 0xfeee, [0x2e19] = 0xfeef, +- [0x2e1a] = 0xfef0, [0x2e1b] = 0xfef1, [0x2e1c] = 0xfef2, [0x2e1d] = 0xfef3, +- [0x2e1e] = 0xfef4, [0x2e1f] = 0xfef5, [0x2e20] = 0xfef6, [0x2e21] = 0xfef7, +- [0x2e22] = 0xfef8, [0x2e23] = 0xfef9, [0x2e24] = 0xfefa, [0x2e25] = 0xfefb, +- [0x2e26] = 0xfefc, [0x2e27] = 0xfefd, [0x2e28] = 0xfefe, [0x2e29] = 0xfeff, +- [0x2e2a] = 0xff00, [0x2e2b] = 0xff5f, [0x2e2c] = 0xff60, [0x2e2d] = 0xff61, +- [0x2e2e] = 0xff62, [0x2e2f] = 0xff63, [0x2e30] = 0xff64, [0x2e31] = 0xff65, +- [0x2e32] = 0xff66, [0x2e33] = 0xff67, [0x2e34] = 0xff68, [0x2e35] = 0xff69, +- [0x2e36] = 0xff6a, [0x2e37] = 0xff6b, [0x2e38] = 0xff6c, [0x2e39] = 0xff6d, +- [0x2e3a] = 0xff6e, [0x2e3b] = 0xff6f, [0x2e3c] = 0xff70, [0x2e3d] = 0xff71, +- [0x2e3e] = 0xff72, [0x2e3f] = 0xff73, [0x2e40] = 0xff74, [0x2e41] = 0xff75, +- [0x2e42] = 0xff76, [0x2e43] = 0xff77, [0x2e44] = 0xff78, [0x2e45] = 0xff79, +- [0x2e46] = 0xff7a, [0x2e47] = 0xff7b, [0x2e48] = 0xff7c, [0x2e49] = 0xff7d, +- [0x2e4a] = 0xff7e, [0x2e4b] = 0xff7f, [0x2e4c] = 0xff80, [0x2e4d] = 0xff81, +- [0x2e4e] = 0xff82, [0x2e4f] = 0xff83, [0x2e50] = 0xff84, [0x2e51] = 0xff85, +- [0x2e52] = 0xff86, [0x2e53] = 0xff87, [0x2e54] = 0xff88, [0x2e55] = 0xff89, +- [0x2e56] = 0xff8a, [0x2e57] = 0xff8b, [0x2e58] = 0xff8c, [0x2e59] = 0xff8d, +- [0x2e5a] = 0xff8e, [0x2e5b] = 0xff8f, [0x2e5c] = 0xff90, [0x2e5d] = 0xff91, +- [0x2e5e] = 0xff92, [0x2e5f] = 0xff93, [0x2e60] = 0xff94, [0x2e61] = 0xff95, +- [0x2e62] = 0xff96, [0x2e63] = 0xff97, [0x2e64] = 0xff98, [0x2e65] = 0xff99, +- [0x2e66] = 0xff9a, [0x2e67] = 0xff9b, [0x2e68] = 0xff9c, [0x2e69] = 0xff9d, +- [0x2e6a] = 0xff9e, [0x2e6b] = 0xff9f, [0x2e6c] = 0xffa0, [0x2e6d] = 0xffa1, +- [0x2e6e] = 0xffa2, [0x2e6f] = 0xffa3, [0x2e70] = 0xffa4, [0x2e71] = 0xffa5, +- [0x2e72] = 0xffa6, [0x2e73] = 0xffa7, [0x2e74] = 0xffa8, [0x2e75] = 0xffa9, +- [0x2e76] = 0xffaa, [0x2e77] = 0xffab, [0x2e78] = 0xffac, [0x2e79] = 0xffad, +- [0x2e7a] = 0xffae, [0x2e7b] = 0xffaf, [0x2e7c] = 0xffb0, [0x2e7d] = 0xffb1, +- [0x2e7e] = 0xffb2, [0x2e7f] = 0xffb3, [0x2e80] = 0xffb4, [0x2e81] = 0xffb5, +- [0x2e82] = 0xffb6, [0x2e83] = 0xffb7, [0x2e84] = 0xffb8, [0x2e85] = 0xffb9, +- [0x2e86] = 0xffba, [0x2e87] = 0xffbb, [0x2e88] = 0xffbc, [0x2e89] = 0xffbd, +- [0x2e8a] = 0xffbe, [0x2e8b] = 0xffbf, [0x2e8c] = 0xffc0, [0x2e8d] = 0xffc1, +- [0x2e8e] = 0xffc2, [0x2e8f] = 0xffc3, [0x2e90] = 0xffc4, [0x2e91] = 0xffc5, +- [0x2e92] = 0xffc6, [0x2e93] = 0xffc7, [0x2e94] = 0xffc8, [0x2e95] = 0xffc9, +- [0x2e96] = 0xffca, [0x2e97] = 0xffcb, [0x2e98] = 0xffcc, [0x2e99] = 0xffcd, +- [0x2e9a] = 0xffce, [0x2e9b] = 0xffcf, [0x2e9c] = 0xffd0, [0x2e9d] = 0xffd1, +- [0x2e9e] = 0xffd2, [0x2e9f] = 0xffd3, [0x2ea0] = 0xffd4, [0x2ea1] = 0xffd5, +- [0x2ea2] = 0xffd6, [0x2ea3] = 0xffd7, [0x2ea4] = 0xffd8, [0x2ea5] = 0xffd9, +- [0x2ea6] = 0xffda, [0x2ea7] = 0xffdb, [0x2ea8] = 0xffdc, [0x2ea9] = 0xffdd, +- [0x2eaa] = 0xffde, [0x2eab] = 0xffdf, ++ [0x2d6c] = 0xfe0e, [0x2d6d] = 0xfe0f, [0x2d6e] = 0xe78d, [0x2d6f] = 0xe78f, ++ [0x2d70] = 0xe78e, [0x2d71] = 0xe790, [0x2d72] = 0xe791, [0x2d73] = 0xe792, ++ [0x2d74] = 0xe793, [0x2d75] = 0xe794, [0x2d76] = 0xe795, [0x2d77] = 0xe796, ++ [0x2d78] = 0xfe1a, [0x2d79] = 0xfe1b, [0x2d7a] = 0xfe1c, [0x2d7b] = 0xfe1d, ++ [0x2d7c] = 0xfe1e, [0x2d7d] = 0xfe1f, [0x2d7e] = 0xfe20, [0x2d7f] = 0xfe21, ++ [0x2d80] = 0xfe22, [0x2d81] = 0xfe23, [0x2d82] = 0xfe24, [0x2d83] = 0xfe25, ++ [0x2d84] = 0xfe26, [0x2d85] = 0xfe27, [0x2d86] = 0xfe28, [0x2d87] = 0xfe29, ++ [0x2d88] = 0xfe2a, [0x2d89] = 0xfe2b, [0x2d8a] = 0xfe2c, [0x2d8b] = 0xfe2d, ++ [0x2d8c] = 0xfe2e, [0x2d8d] = 0xfe2f, [0x2d8e] = 0xfe32, [0x2d8f] = 0xfe45, ++ [0x2d90] = 0xfe46, [0x2d91] = 0xfe47, [0x2d92] = 0xfe48, [0x2d93] = 0xfe53, ++ [0x2d94] = 0xfe58, [0x2d95] = 0xfe67, [0x2d96] = 0xfe6c, [0x2d97] = 0xfe6d, ++ [0x2d98] = 0xfe6e, [0x2d99] = 0xfe6f, [0x2d9a] = 0xfe70, [0x2d9b] = 0xfe71, ++ [0x2d9c] = 0xfe72, [0x2d9d] = 0xfe73, [0x2d9e] = 0xfe74, [0x2d9f] = 0xfe75, ++ [0x2da0] = 0xfe76, [0x2da1] = 0xfe77, [0x2da2] = 0xfe78, [0x2da3] = 0xfe79, ++ [0x2da4] = 0xfe7a, [0x2da5] = 0xfe7b, [0x2da6] = 0xfe7c, [0x2da7] = 0xfe7d, ++ [0x2da8] = 0xfe7e, [0x2da9] = 0xfe7f, [0x2daa] = 0xfe80, [0x2dab] = 0xfe81, ++ [0x2dac] = 0xfe82, [0x2dad] = 0xfe83, [0x2dae] = 0xfe84, [0x2daf] = 0xfe85, ++ [0x2db0] = 0xfe86, [0x2db1] = 0xfe87, [0x2db2] = 0xfe88, [0x2db3] = 0xfe89, ++ [0x2db4] = 0xfe8a, [0x2db5] = 0xfe8b, [0x2db6] = 0xfe8c, [0x2db7] = 0xfe8d, ++ [0x2db8] = 0xfe8e, [0x2db9] = 0xfe8f, [0x2dba] = 0xfe90, [0x2dbb] = 0xfe91, ++ [0x2dbc] = 0xfe92, [0x2dbd] = 0xfe93, [0x2dbe] = 0xfe94, [0x2dbf] = 0xfe95, ++ [0x2dc0] = 0xfe96, [0x2dc1] = 0xfe97, [0x2dc2] = 0xfe98, [0x2dc3] = 0xfe99, ++ [0x2dc4] = 0xfe9a, [0x2dc5] = 0xfe9b, [0x2dc6] = 0xfe9c, [0x2dc7] = 0xfe9d, ++ [0x2dc8] = 0xfe9e, [0x2dc9] = 0xfe9f, [0x2dca] = 0xfea0, [0x2dcb] = 0xfea1, ++ [0x2dcc] = 0xfea2, [0x2dcd] = 0xfea3, [0x2dce] = 0xfea4, [0x2dcf] = 0xfea5, ++ [0x2dd0] = 0xfea6, [0x2dd1] = 0xfea7, [0x2dd2] = 0xfea8, [0x2dd3] = 0xfea9, ++ [0x2dd4] = 0xfeaa, [0x2dd5] = 0xfeab, [0x2dd6] = 0xfeac, [0x2dd7] = 0xfead, ++ [0x2dd8] = 0xfeae, [0x2dd9] = 0xfeaf, [0x2dda] = 0xfeb0, [0x2ddb] = 0xfeb1, ++ [0x2ddc] = 0xfeb2, [0x2ddd] = 0xfeb3, [0x2dde] = 0xfeb4, [0x2ddf] = 0xfeb5, ++ [0x2de0] = 0xfeb6, [0x2de1] = 0xfeb7, [0x2de2] = 0xfeb8, [0x2de3] = 0xfeb9, ++ [0x2de4] = 0xfeba, [0x2de5] = 0xfebb, [0x2de6] = 0xfebc, [0x2de7] = 0xfebd, ++ [0x2de8] = 0xfebe, [0x2de9] = 0xfebf, [0x2dea] = 0xfec0, [0x2deb] = 0xfec1, ++ [0x2dec] = 0xfec2, [0x2ded] = 0xfec3, [0x2dee] = 0xfec4, [0x2def] = 0xfec5, ++ [0x2df0] = 0xfec6, [0x2df1] = 0xfec7, [0x2df2] = 0xfec8, [0x2df3] = 0xfec9, ++ [0x2df4] = 0xfeca, [0x2df5] = 0xfecb, [0x2df6] = 0xfecc, [0x2df7] = 0xfecd, ++ [0x2df8] = 0xfece, [0x2df9] = 0xfecf, [0x2dfa] = 0xfed0, [0x2dfb] = 0xfed1, ++ [0x2dfc] = 0xfed2, [0x2dfd] = 0xfed3, [0x2dfe] = 0xfed4, [0x2dff] = 0xfed5, ++ [0x2e00] = 0xfed6, [0x2e01] = 0xfed7, [0x2e02] = 0xfed8, [0x2e03] = 0xfed9, ++ [0x2e04] = 0xfeda, [0x2e05] = 0xfedb, [0x2e06] = 0xfedc, [0x2e07] = 0xfedd, ++ [0x2e08] = 0xfede, [0x2e09] = 0xfedf, [0x2e0a] = 0xfee0, [0x2e0b] = 0xfee1, ++ [0x2e0c] = 0xfee2, [0x2e0d] = 0xfee3, [0x2e0e] = 0xfee4, [0x2e0f] = 0xfee5, ++ [0x2e10] = 0xfee6, [0x2e11] = 0xfee7, [0x2e12] = 0xfee8, [0x2e13] = 0xfee9, ++ [0x2e14] = 0xfeea, [0x2e15] = 0xfeeb, [0x2e16] = 0xfeec, [0x2e17] = 0xfeed, ++ [0x2e18] = 0xfeee, [0x2e19] = 0xfeef, [0x2e1a] = 0xfef0, [0x2e1b] = 0xfef1, ++ [0x2e1c] = 0xfef2, [0x2e1d] = 0xfef3, [0x2e1e] = 0xfef4, [0x2e1f] = 0xfef5, ++ [0x2e20] = 0xfef6, [0x2e21] = 0xfef7, [0x2e22] = 0xfef8, [0x2e23] = 0xfef9, ++ [0x2e24] = 0xfefa, [0x2e25] = 0xfefb, [0x2e26] = 0xfefc, [0x2e27] = 0xfefd, ++ [0x2e28] = 0xfefe, [0x2e29] = 0xfeff, [0x2e2a] = 0xff00, [0x2e2b] = 0xff5f, ++ [0x2e2c] = 0xff60, [0x2e2d] = 0xff61, [0x2e2e] = 0xff62, [0x2e2f] = 0xff63, ++ [0x2e30] = 0xff64, [0x2e31] = 0xff65, [0x2e32] = 0xff66, [0x2e33] = 0xff67, ++ [0x2e34] = 0xff68, [0x2e35] = 0xff69, [0x2e36] = 0xff6a, [0x2e37] = 0xff6b, ++ [0x2e38] = 0xff6c, [0x2e39] = 0xff6d, [0x2e3a] = 0xff6e, [0x2e3b] = 0xff6f, ++ [0x2e3c] = 0xff70, [0x2e3d] = 0xff71, [0x2e3e] = 0xff72, [0x2e3f] = 0xff73, ++ [0x2e40] = 0xff74, [0x2e41] = 0xff75, [0x2e42] = 0xff76, [0x2e43] = 0xff77, ++ [0x2e44] = 0xff78, [0x2e45] = 0xff79, [0x2e46] = 0xff7a, [0x2e47] = 0xff7b, ++ [0x2e48] = 0xff7c, [0x2e49] = 0xff7d, [0x2e4a] = 0xff7e, [0x2e4b] = 0xff7f, ++ [0x2e4c] = 0xff80, [0x2e4d] = 0xff81, [0x2e4e] = 0xff82, [0x2e4f] = 0xff83, ++ [0x2e50] = 0xff84, [0x2e51] = 0xff85, [0x2e52] = 0xff86, [0x2e53] = 0xff87, ++ [0x2e54] = 0xff88, [0x2e55] = 0xff89, [0x2e56] = 0xff8a, [0x2e57] = 0xff8b, ++ [0x2e58] = 0xff8c, [0x2e59] = 0xff8d, [0x2e5a] = 0xff8e, [0x2e5b] = 0xff8f, ++ [0x2e5c] = 0xff90, [0x2e5d] = 0xff91, [0x2e5e] = 0xff92, [0x2e5f] = 0xff93, ++ [0x2e60] = 0xff94, [0x2e61] = 0xff95, [0x2e62] = 0xff96, [0x2e63] = 0xff97, ++ [0x2e64] = 0xff98, [0x2e65] = 0xff99, [0x2e66] = 0xff9a, [0x2e67] = 0xff9b, ++ [0x2e68] = 0xff9c, [0x2e69] = 0xff9d, [0x2e6a] = 0xff9e, [0x2e6b] = 0xff9f, ++ [0x2e6c] = 0xffa0, [0x2e6d] = 0xffa1, [0x2e6e] = 0xffa2, [0x2e6f] = 0xffa3, ++ [0x2e70] = 0xffa4, [0x2e71] = 0xffa5, [0x2e72] = 0xffa6, [0x2e73] = 0xffa7, ++ [0x2e74] = 0xffa8, [0x2e75] = 0xffa9, [0x2e76] = 0xffaa, [0x2e77] = 0xffab, ++ [0x2e78] = 0xffac, [0x2e79] = 0xffad, [0x2e7a] = 0xffae, [0x2e7b] = 0xffaf, ++ [0x2e7c] = 0xffb0, [0x2e7d] = 0xffb1, [0x2e7e] = 0xffb2, [0x2e7f] = 0xffb3, ++ [0x2e80] = 0xffb4, [0x2e81] = 0xffb5, [0x2e82] = 0xffb6, [0x2e83] = 0xffb7, ++ [0x2e84] = 0xffb8, [0x2e85] = 0xffb9, [0x2e86] = 0xffba, [0x2e87] = 0xffbb, ++ [0x2e88] = 0xffbc, [0x2e89] = 0xffbd, [0x2e8a] = 0xffbe, [0x2e8b] = 0xffbf, ++ [0x2e8c] = 0xffc0, [0x2e8d] = 0xffc1, [0x2e8e] = 0xffc2, [0x2e8f] = 0xffc3, ++ [0x2e90] = 0xffc4, [0x2e91] = 0xffc5, [0x2e92] = 0xffc6, [0x2e93] = 0xffc7, ++ [0x2e94] = 0xffc8, [0x2e95] = 0xffc9, [0x2e96] = 0xffca, [0x2e97] = 0xffcb, ++ [0x2e98] = 0xffcc, [0x2e99] = 0xffcd, [0x2e9a] = 0xffce, [0x2e9b] = 0xffcf, ++ [0x2e9c] = 0xffd0, [0x2e9d] = 0xffd1, [0x2e9e] = 0xffd2, [0x2e9f] = 0xffd3, ++ [0x2ea0] = 0xffd4, [0x2ea1] = 0xffd5, [0x2ea2] = 0xffd6, [0x2ea3] = 0xffd7, ++ [0x2ea4] = 0xffd8, [0x2ea5] = 0xffd9, [0x2ea6] = 0xffda, [0x2ea7] = 0xffdb, ++ [0x2ea8] = 0xffdc, [0x2ea9] = 0xffdd, [0x2eaa] = 0xffde, [0x2eab] = 0xffdf, + }; + + /* Table for UCS-4 -> GB18030, for the range U+0080..U+9FBB. +@@ -23437,71 +23442,79 @@ static const unsigned char __ucs_to_gb18030_tab2[][2] = + [0x0783] = "\xa5\xfd", [0x0784] = "\xa5\xfe", [0x0785] = "\xa6\xb9", + [0x0786] = "\xa6\xba", [0x0787] = "\xa6\xbb", [0x0788] = "\xa6\xbc", + [0x0789] = "\xa6\xbd", [0x078a] = "\xa6\xbe", [0x078b] = "\xa6\xbf", +- [0x078c] = "\xa6\xc0", [0x0797] = "\xa6\xf6", [0x0798] = "\xa6\xf7", +- [0x0799] = "\xa6\xf8", [0x079a] = "\xa6\xf9", [0x079b] = "\xa6\xfa", +- [0x079c] = "\xa6\xfb", [0x079d] = "\xa6\xfc", [0x079e] = "\xa6\xfd", +- [0x079f] = "\xa6\xfe", [0x07a0] = "\xa7\xc2", [0x07a1] = "\xa7\xc3", +- [0x07a2] = "\xa7\xc4", [0x07a3] = "\xa7\xc5", [0x07a4] = "\xa7\xc6", +- [0x07a5] = "\xa7\xc7", [0x07a6] = "\xa7\xc8", [0x07a7] = "\xa7\xc9", +- [0x07a8] = "\xa7\xca", [0x07a9] = "\xa7\xcb", [0x07aa] = "\xa7\xcc", +- [0x07ab] = "\xa7\xcd", [0x07ac] = "\xa7\xce", [0x07ad] = "\xa7\xcf", +- [0x07ae] = "\xa7\xd0", [0x07af] = "\xa7\xf2", [0x07b0] = "\xa7\xf3", +- [0x07b1] = "\xa7\xf4", [0x07b2] = "\xa7\xf5", [0x07b3] = "\xa7\xf6", +- [0x07b4] = "\xa7\xf7", [0x07b5] = "\xa7\xf8", [0x07b6] = "\xa7\xf9", +- [0x07b7] = "\xa7\xfa", [0x07b8] = "\xa7\xfb", [0x07b9] = "\xa7\xfc", +- [0x07ba] = "\xa7\xfd", [0x07bb] = "\xa7\xfe", [0x07bc] = "\xa8\x96", +- [0x07bd] = "\xa8\x97", [0x07be] = "\xa8\x98", [0x07bf] = "\xa8\x99", +- [0x07c0] = "\xa8\x9a", [0x07c1] = "\xa8\x9b", [0x07c2] = "\xa8\x9c", +- [0x07c3] = "\xa8\x9d", [0x07c4] = "\xa8\x9e", [0x07c5] = "\xa8\x9f", +- [0x07c6] = "\xa8\xa0", [0x07c7] = "\x00\x01", [0x07c8] = "\x65\x9e", +- [0x07c9] = "\xa8\xc1", [0x07ca] = "\xa8\xc2", [0x07cb] = "\xa8\xc3", +- [0x07cc] = "\xa8\xc4", [0x07cd] = "\xa8\xea", [0x07ce] = "\xa8\xeb", +- [0x07cf] = "\xa8\xec", [0x07d0] = "\xa8\xed", [0x07d1] = "\xa8\xee", +- [0x07d2] = "\xa8\xef", [0x07d3] = "\xa8\xf0", [0x07d4] = "\xa8\xf1", +- [0x07d5] = "\xa8\xf2", [0x07d6] = "\xa8\xf3", [0x07d7] = "\xa8\xf4", +- [0x07d8] = "\xa8\xf5", [0x07d9] = "\xa8\xf6", [0x07da] = "\xa8\xf7", +- [0x07db] = "\xa8\xf8", [0x07dc] = "\xa8\xf9", [0x07dd] = "\xa8\xfa", +- [0x07de] = "\xa8\xfb", [0x07df] = "\xa8\xfc", [0x07e0] = "\xa8\xfd", +- [0x07e1] = "\xa8\xfe", [0x07e2] = "\xa9\x58", [0x07e3] = "\xa9\x5b", +- [0x07e4] = "\xa9\x5d", [0x07e5] = "\xa9\x5e", [0x07e6] = "\xa9\x5f", +- [0x07e7] = "\x65\x9f", [0x07e8] = "\x65\xa0", [0x07e9] = "\x65\xa1", +- [0x07ea] = "\x65\xa2", [0x07eb] = "\x65\xa3", [0x07ec] = "\x65\xa4", +- [0x07ed] = "\x65\xa5", [0x07ee] = "\x65\xa6", [0x07ef] = "\x65\xa7", +- [0x07f0] = "\x65\xa8", [0x07f1] = "\x65\xa9", [0x07f2] = "\x65\xaa", +- [0x07f3] = "\x65\xab", [0x07f4] = "\xa9\x97", [0x07f5] = "\xa9\x98", +- [0x07f6] = "\xa9\x99", [0x07f7] = "\xa9\x9a", [0x07f8] = "\xa9\x9b", +- [0x07f9] = "\xa9\x9c", [0x07fa] = "\xa9\x9d", [0x07fb] = "\xa9\x9e", +- [0x07fc] = "\xa9\x9f", [0x07fd] = "\xa9\xa0", [0x07fe] = "\xa9\xa1", +- [0x07ff] = "\xa9\xa2", [0x0800] = "\xa9\xa3", [0x0801] = "\xa9\xf0", +- [0x0802] = "\xa9\xf1", [0x0803] = "\xa9\xf2", [0x0804] = "\xa9\xf3", +- [0x0805] = "\xa9\xf4", [0x0806] = "\xa9\xf5", [0x0807] = "\xa9\xf6", +- [0x0808] = "\xa9\xf7", [0x0809] = "\xa9\xf8", [0x080a] = "\xa9\xf9", +- [0x080b] = "\xa9\xfa", [0x080c] = "\xa9\xfb", [0x080d] = "\xa9\xfc", +- [0x080e] = "\xa9\xfd", [0x080f] = "\xa9\xfe", [0x0810] = "\xd7\xfa", +- [0x0811] = "\xd7\xfb", [0x0812] = "\xd7\xfc", [0x0813] = "\xd7\xfd", +- [0x0814] = "\xd7\xfe", [0x0815] = "\x65\xac", [0x0819] = "\x65\xad", +- [0x081a] = "\x65\xae", [0x081b] = "\x65\xaf", [0x081c] = "\x65\xb0", +- [0x081d] = "\x65\xb1", [0x081f] = "\x65\xb2", [0x0820] = "\x65\xb3", +- [0x0821] = "\x65\xb4", [0x0822] = "\x65\xb5", [0x0823] = "\x65\xb6", +- [0x0824] = "\x65\xb7", [0x0825] = "\x65\xb8", [0x0827] = "\x65\xb9", ++ [0x078c] = "\xa6\xc0", [0x078d] = "\x7b\x84", [0x078e] = "\x7b\x86", ++ [0x078f] = "\x7b\x85", [0x0790] = "\x7b\x87", [0x0791] = "\x7b\x88", ++ [0x0792] = "\x7b\x89", [0x0793] = "\x7b\x8a", [0x0794] = "\x7b\x8b", ++ [0x0795] = "\x7b\x8c", [0x0796] = "\x7b\x8d", [0x0797] = "\xa6\xf6", ++ [0x0798] = "\xa6\xf7", [0x0799] = "\xa6\xf8", [0x079a] = "\xa6\xf9", ++ [0x079b] = "\xa6\xfa", [0x079c] = "\xa6\xfb", [0x079d] = "\xa6\xfc", ++ [0x079e] = "\xa6\xfd", [0x079f] = "\xa6\xfe", [0x07a0] = "\xa7\xc2", ++ [0x07a1] = "\xa7\xc3", [0x07a2] = "\xa7\xc4", [0x07a3] = "\xa7\xc5", ++ [0x07a4] = "\xa7\xc6", [0x07a5] = "\xa7\xc7", [0x07a6] = "\xa7\xc8", ++ [0x07a7] = "\xa7\xc9", [0x07a8] = "\xa7\xca", [0x07a9] = "\xa7\xcb", ++ [0x07aa] = "\xa7\xcc", [0x07ab] = "\xa7\xcd", [0x07ac] = "\xa7\xce", ++ [0x07ad] = "\xa7\xcf", [0x07ae] = "\xa7\xd0", [0x07af] = "\xa7\xf2", ++ [0x07b0] = "\xa7\xf3", [0x07b1] = "\xa7\xf4", [0x07b2] = "\xa7\xf5", ++ [0x07b3] = "\xa7\xf6", [0x07b4] = "\xa7\xf7", [0x07b5] = "\xa7\xf8", ++ [0x07b6] = "\xa7\xf9", [0x07b7] = "\xa7\xfa", [0x07b8] = "\xa7\xfb", ++ [0x07b9] = "\xa7\xfc", [0x07ba] = "\xa7\xfd", [0x07bb] = "\xa7\xfe", ++ [0x07bc] = "\xa8\x96", [0x07bd] = "\xa8\x97", [0x07be] = "\xa8\x98", ++ [0x07bf] = "\xa8\x99", [0x07c0] = "\xa8\x9a", [0x07c1] = "\xa8\x9b", ++ [0x07c2] = "\xa8\x9c", [0x07c3] = "\xa8\x9d", [0x07c4] = "\xa8\x9e", ++ [0x07c5] = "\xa8\x9f", [0x07c6] = "\xa8\xa0", [0x07c7] = "\x00\x01", ++ [0x07c8] = "\x65\x9e", [0x07c9] = "\xa8\xc1", [0x07ca] = "\xa8\xc2", ++ [0x07cb] = "\xa8\xc3", [0x07cc] = "\xa8\xc4", [0x07cd] = "\xa8\xea", ++ [0x07ce] = "\xa8\xeb", [0x07cf] = "\xa8\xec", [0x07d0] = "\xa8\xed", ++ [0x07d1] = "\xa8\xee", [0x07d2] = "\xa8\xef", [0x07d3] = "\xa8\xf0", ++ [0x07d4] = "\xa8\xf1", [0x07d5] = "\xa8\xf2", [0x07d6] = "\xa8\xf3", ++ [0x07d7] = "\xa8\xf4", [0x07d8] = "\xa8\xf5", [0x07d9] = "\xa8\xf6", ++ [0x07da] = "\xa8\xf7", [0x07db] = "\xa8\xf8", [0x07dc] = "\xa8\xf9", ++ [0x07dd] = "\xa8\xfa", [0x07de] = "\xa8\xfb", [0x07df] = "\xa8\xfc", ++ [0x07e0] = "\xa8\xfd", [0x07e1] = "\xa8\xfe", [0x07e2] = "\xa9\x58", ++ [0x07e3] = "\xa9\x5b", [0x07e4] = "\xa9\x5d", [0x07e5] = "\xa9\x5e", ++ [0x07e6] = "\xa9\x5f", [0x07e7] = "\x65\x9f", [0x07e8] = "\x65\xa0", ++ [0x07e9] = "\x65\xa1", [0x07ea] = "\x65\xa2", [0x07eb] = "\x65\xa3", ++ [0x07ec] = "\x65\xa4", [0x07ed] = "\x65\xa5", [0x07ee] = "\x65\xa6", ++ [0x07ef] = "\x65\xa7", [0x07f0] = "\x65\xa8", [0x07f1] = "\x65\xa9", ++ [0x07f2] = "\x65\xaa", [0x07f3] = "\x65\xab", [0x07f4] = "\xa9\x97", ++ [0x07f5] = "\xa9\x98", [0x07f6] = "\xa9\x99", [0x07f7] = "\xa9\x9a", ++ [0x07f8] = "\xa9\x9b", [0x07f9] = "\xa9\x9c", [0x07fa] = "\xa9\x9d", ++ [0x07fb] = "\xa9\x9e", [0x07fc] = "\xa9\x9f", [0x07fd] = "\xa9\xa0", ++ [0x07fe] = "\xa9\xa1", [0x07ff] = "\xa9\xa2", [0x0800] = "\xa9\xa3", ++ [0x0801] = "\xa9\xf0", [0x0802] = "\xa9\xf1", [0x0803] = "\xa9\xf2", ++ [0x0804] = "\xa9\xf3", [0x0805] = "\xa9\xf4", [0x0806] = "\xa9\xf5", ++ [0x0807] = "\xa9\xf6", [0x0808] = "\xa9\xf7", [0x0809] = "\xa9\xf8", ++ [0x080a] = "\xa9\xf9", [0x080b] = "\xa9\xfa", [0x080c] = "\xa9\xfb", ++ [0x080d] = "\xa9\xfc", [0x080e] = "\xa9\xfd", [0x080f] = "\xa9\xfe", ++ [0x0810] = "\xd7\xfa", [0x0811] = "\xd7\xfb", [0x0812] = "\xd7\xfc", ++ [0x0813] = "\xd7\xfd", [0x0814] = "\xd7\xfe", [0x0815] = "\x65\xac", ++ [0x0816] = "\xfe\x51", [0x0817] = "\xfe\x52", [0x0818] = "\xfe\x53", ++ [0x0819] = "\x65\xad", [0x081a] = "\x65\xae", [0x081b] = "\x65\xaf", ++ [0x081c] = "\x65\xb0", [0x081d] = "\x65\xb1", [0x081e] = "\x2d\x51", ++ [0x081f] = "\x65\xb2", [0x0820] = "\x65\xb3", [0x0821] = "\x65\xb4", ++ [0x0822] = "\x65\xb5", [0x0823] = "\x65\xb6", [0x0824] = "\x65\xb7", ++ [0x0825] = "\x65\xb8", [0x0826] = "\x2d\x52", [0x0827] = "\x65\xb9", + [0x0828] = "\x65\xba", [0x0829] = "\x65\xbb", [0x082a] = "\x65\xbc", +- [0x082d] = "\x65\xbd", [0x082e] = "\x65\xbe", [0x082f] = "\x65\xbf", +- [0x0830] = "\x65\xc0", [0x0833] = "\x65\xc1", [0x0834] = "\x65\xc2", +- [0x0835] = "\x65\xc3", [0x0836] = "\x65\xc4", [0x0837] = "\x65\xc5", +- [0x0838] = "\x65\xc6", [0x0839] = "\x65\xc7", [0x083a] = "\x65\xc8", +- [0x083c] = "\x65\xc9", [0x083d] = "\x65\xca", [0x083e] = "\x65\xcb", +- [0x083f] = "\x65\xcc", [0x0840] = "\x65\xcd", [0x0841] = "\x65\xce", +- [0x0842] = "\x65\xcf", [0x0844] = "\x65\xd0", [0x0845] = "\x65\xd1", ++ [0x082b] = "\x2d\x53", [0x082c] = "\x2d\x54", [0x082d] = "\x65\xbd", ++ [0x082e] = "\x65\xbe", [0x082f] = "\x65\xbf", [0x0830] = "\x65\xc0", ++ [0x0831] = "\xfe\x6c", [0x0832] = "\x2d\x55", [0x0833] = "\x65\xc1", ++ [0x0834] = "\x65\xc2", [0x0835] = "\x65\xc3", [0x0836] = "\x65\xc4", ++ [0x0837] = "\x65\xc5", [0x0838] = "\x65\xc6", [0x0839] = "\x65\xc7", ++ [0x083a] = "\x65\xc8", [0x083b] = "\xfe\x76", [0x083c] = "\x65\xc9", ++ [0x083d] = "\x65\xca", [0x083e] = "\x65\xcb", [0x083f] = "\x65\xcc", ++ [0x0840] = "\x65\xcd", [0x0841] = "\x65\xce", [0x0842] = "\x65\xcf", ++ [0x0843] = "\x2d\x56", [0x0844] = "\x65\xd0", [0x0845] = "\x65\xd1", + [0x0846] = "\x65\xd2", [0x0847] = "\x65\xd3", [0x0848] = "\x65\xd4", + [0x0849] = "\x65\xd5", [0x084a] = "\x65\xd6", [0x084b] = "\x65\xd7", + [0x084c] = "\x65\xd8", [0x084d] = "\x65\xd9", [0x084e] = "\x65\xda", + [0x084f] = "\x65\xdb", [0x0850] = "\x65\xdc", [0x0851] = "\x65\xdd", +- [0x0852] = "\x65\xde", [0x0853] = "\x65\xdf", [0x0856] = "\x65\xe0", +- [0x0857] = "\x65\xe1", [0x0858] = "\x65\xe2", [0x0859] = "\x65\xe3", +- [0x085a] = "\x65\xe4", [0x085b] = "\x65\xe5", [0x085c] = "\x65\xe6", +- [0x085d] = "\x65\xe7", [0x085e] = "\x65\xe8", [0x085f] = "\x65\xe9", +- [0x0860] = "\x65\xea", [0x0861] = "\x65\xeb", [0x0862] = "\x65\xec", +- [0x0863] = "\x65\xed", [0x0865] = "\xfd\x9c", [0x0866] = "\x76\xb5", ++ [0x0852] = "\x65\xde", [0x0853] = "\x65\xdf", [0x0854] = "\x2d\x57", ++ [0x0855] = "\xfe\x91", [0x0856] = "\x65\xe0", [0x0857] = "\x65\xe1", ++ [0x0858] = "\x65\xe2", [0x0859] = "\x65\xe3", [0x085a] = "\x65\xe4", ++ [0x085b] = "\x65\xe5", [0x085c] = "\x65\xe6", [0x085d] = "\x65\xe7", ++ [0x085e] = "\x65\xe8", [0x085f] = "\x65\xe9", [0x0860] = "\x65\xea", ++ [0x0861] = "\x65\xeb", [0x0862] = "\x65\xec", [0x0863] = "\x65\xed", ++ [0x0864] = "\x2d\x58", [0x0865] = "\xfd\x9c", [0x0866] = "\x76\xb5", + [0x0867] = "\x76\xb6", [0x0868] = "\x76\xb7", [0x0869] = "\x76\xb8", + [0x086a] = "\x76\xb9", [0x086b] = "\x76\xba", [0x086c] = "\x76\xbb", + [0x086d] = "\x76\xbc", [0x086e] = "\x76\xbd", [0x086f] = "\x76\xbe", +@@ -24211,24 +24224,8 @@ static const unsigned char __ucs_to_gb18030_tab2[][2] = + || (ch = __twobyte_to_ucs[idx], \ + ch == 0 && *inptr != '\0')) \ + { \ +- /* Handle a few special cases. */ \ +- if (idx == 0x5dd1) \ +- ch = 0x20087; \ +- else if (idx == 0x5dd2) \ +- ch = 0x20089; \ +- else if (idx == 0x5dd3) \ +- ch = 0x200cc; \ +- else if (idx == 0x5dec) \ +- ch = 0x215D7; \ +- else if (idx == 0x5df6) \ +- ch = 0x2298F; \ +- else if (idx == 0x5e11) \ +- ch = 0x241FE; \ +- else \ +- { \ +- /* This is an illegal character. */ \ +- STANDARD_FROM_LOOP_ERR_HANDLER (2); \ +- } \ ++ /* This is an illegal character. */ \ ++ STANDARD_FROM_LOOP_ERR_HANDLER (2); \ + } \ + \ + inptr += 2; \ +@@ -24320,17 +24317,35 @@ static const unsigned char __ucs_to_gb18030_tab2[][2] = + len = 4; \ + } \ + else if (ch == 0x20087) \ +- cp = (const unsigned char *) "\xfe\x51"; \ ++ { \ ++ idx = 0x3E2CF; \ ++ len = 4; \ ++ } \ + else if (ch == 0x20089) \ +- cp = (const unsigned char *) "\xfe\x52"; \ ++ { \ ++ idx = 0x3E2D1; \ ++ len = 4; \ ++ } \ + else if (ch == 0x200CC) \ +- cp = (const unsigned char *) "\xfe\x53"; \ ++ { \ ++ idx = 0x3E314; \ ++ len = 4; \ ++ } \ + else if (ch == 0x215d7) \ +- cp = (const unsigned char *) "\xfe\x6c"; \ ++ { \ ++ idx = 0x3F81F; \ ++ len = 4; \ ++ } \ + else if (ch == 0x2298F) \ +- cp = (const unsigned char *) "\xfe\x76"; \ ++ { \ ++ idx = 0x40BD7; \ ++ len = 4; \ ++ } \ + else if (ch == 0x241FE) \ +- cp = (const unsigned char *) "\xfe\x91"; \ ++ { \ ++ idx = 0x42446; \ ++ len = 4; \ ++ } \ + else if (ch >= 0x10000 && ch <= 0x10FFFF) \ + { \ + idx = ch + 0x1E248; \ +diff --git a/iconvdata/tst-table-from.c b/iconvdata/tst-table-from.c +index 09aaaf0942..55a7113d8c 100644 +--- a/iconvdata/tst-table-from.c ++++ b/iconvdata/tst-table-from.c +@@ -194,10 +194,9 @@ main (int argc, char *argv[]) + exit (1); + } + +- /* When testing UTF-8 or GB18030, stop at 0x10000, otherwise the output ++ /* When testing UTF-8, stop at 0x10000, otherwise the output + file gets too big. */ +- bmp_only = (strcmp (charset, "UTF-8") == 0 +- || strcmp (charset, "GB18030") == 0); ++ bmp_only = (strcmp (charset, "UTF-8") == 0); + search_depth = (strcmp (charset, "UTF-8") == 0 ? 3 : 4); + + { +diff --git a/iconvdata/tst-table-to.c b/iconvdata/tst-table-to.c +index 4dec4acad1..2b75f0c6e8 100644 +--- a/iconvdata/tst-table-to.c ++++ b/iconvdata/tst-table-to.c +@@ -32,6 +32,7 @@ main (int argc, char *argv[]) + const char *charset; + iconv_t cd; + int bmp_only; ++ int no_tags; + + if (argc != 2) + { +@@ -47,16 +48,19 @@ main (int argc, char *argv[]) + return 1; + } + +- /* When testing UTF-8 or GB18030, stop at 0x10000, otherwise the output ++ /* When testing UTF-8, stop at 0x10000, otherwise the output + file gets too big. */ +- bmp_only = (strcmp (charset, "UTF-8") == 0 ++ bmp_only = (strcmp (charset, "UTF-8") == 0); ++ /* When testing any encoding other than UTF-8 or GB18030, stop at 0xE0000, ++ because the conversion drops Unicode tag characters (range ++ U+E0000..U+E007F). */ ++ no_tags = !(strcmp (charset, "UTF-8") == 0 + || strcmp (charset, "GB18030") == 0); + + { + unsigned int i; + unsigned char buf[10]; +- +- for (i = 0; i < (bmp_only ? 0x10000 : 0x30000); i++) ++ for (i = 0; i < (bmp_only ? 0x10000 : no_tags ? 0xE0000 : 0x110000); i++) + { + unsigned char in[6]; + unsigned int incount = +diff --git a/iconvdata/tst-table.sh b/iconvdata/tst-table.sh +index bc6f542b24..7ba15bbf5c 100755 +--- a/iconvdata/tst-table.sh ++++ b/iconvdata/tst-table.sh +@@ -37,7 +37,8 @@ set -e + < ../localedata/charmaps/${charmap:-$charset} \ + > ${objpfx}tst-${charset}.charmap.table + # When the charset is GB18030, truncate this table because for this encoding, +-# the tst-table-from and tst-table-to programs scan the Unicode BMP only. ++# the charmap contains ranges (.. notation), which the ++# tst-table-charmap.sh script does not grok. + if test ${charset} = GB18030; then + grep '0x....$' < ${objpfx}tst-${charset}.charmap.table \ + > ${objpfx}tst-${charset}.truncated.table +@@ -73,25 +74,42 @@ diff ${objpfx}tst-${charset}.charmap.table ${objpfx}tst-${charset}.inverse.table + + # Check 1: charmap and iconv forward should be identical, except for + # precomposed characters. +-if test -f ${precomposed}; then +- cat ${objpfx}tst-${charset}.table ${precomposed} | sort | uniq -u \ +- > ${objpfx}tst-${charset}.tmp.table +- cmp -s ${objpfx}tst-${charset}.charmap.table ${objpfx}tst-${charset}.tmp.table || ++{ if test -f ${precomposed}; then ++ cat ${objpfx}tst-${charset}.table ${precomposed} | sort | uniq -u ++ else ++ cat ${objpfx}tst-${charset}.table ++ fi ++} | { if test ${charset} = GB18030; then grep '0x....$'; else cat; fi; } \ ++ > ${objpfx}tst-${charset}.tmp1.table ++cmp -s ${objpfx}tst-${charset}.charmap.table ${objpfx}tst-${charset}.tmp1.table || + exit 1 +-else +- cmp -s ${objpfx}tst-${charset}.charmap.table ${objpfx}tst-${charset}.table || +- exit 1 +-fi + + # Check 2: the difference between the charmap and iconv backward. +-if test -f ${irreversible}; then +- cat ${objpfx}tst-${charset}.charmap.table ${irreversible} | sort | uniq -u \ +- > ${objpfx}tst-${charset}.tmp.table +- cmp -s ${objpfx}tst-${charset}.tmp.table ${objpfx}tst-${charset}.inverse.table || +- exit 1 +-else +- cmp -s ${objpfx}tst-${charset}.charmap.table ${objpfx}tst-${charset}.inverse.table || ++{ if test -f ${irreversible}; then ++ cat ${objpfx}tst-${charset}.charmap.table ${irreversible} | sort | uniq -u ++ else ++ cat ${objpfx}tst-${charset}.charmap.table ++ fi ++} | { if test ${charset} = GB18030; then grep '0x....$'; else cat; fi; } \ ++ > ${objpfx}tst-${charset}.tmp2c.table ++cat ${objpfx}tst-${charset}.inverse.table \ ++ | { if test ${charset} = GB18030; then grep '0x....$'; else cat; fi; } \ ++ > ${objpfx}tst-${charset}.tmp2i.table ++cmp -s ${objpfx}tst-${charset}.tmp2c.table ${objpfx}tst-${charset}.tmp2i.table || + exit 1 ++ ++# Check 3: the difference between iconv forward and iconv backward. This is ++# necessary only for GB18030, because ${objpfx}tst-${charset}.charmap.table ++# is truncated for this encoding (see above). ++if test ${charset} = GB18030; then ++ { if test -f ${irreversible}; then ++ cat ${objpfx}tst-${charset}.table ${irreversible} | sort | uniq -u ++ else ++ cat ${objpfx}tst-${charset}.table ++ fi ++ } > ${objpfx}tst-${charset}.tmp3.table ++ cmp -s ${objpfx}tst-${charset}.tmp3.table ${objpfx}tst-${charset}.inverse.table || ++ exit 1 + fi + + exit 0 +diff --git a/localedata/charmaps/GB18030 b/localedata/charmaps/GB18030 +index ad6728c5bd..fc3b1d2d40 100644 +--- a/localedata/charmaps/GB18030 ++++ b/localedata/charmaps/GB18030 +@@ -57234,32 +57234,16 @@ CHARMAP + /xa6/xbe + /xa6/xbf + /xa6/xc0 +-% The newest GB 18030-2005 standard still uses some private use area +-% code points. Any implementation which has Unicode 4.1 or newer +-% support should not use these PUA code points, and instead should +-% map these entries to their equivalent non-PUA code points. There +-% are 24 idiograms in GB 18030-2005 which have non-PUA equivalents. +-% In glibc we only support roundtrip code points, and so must choose +-% between supporting the old PUA code points, or using the newer +-% non-PUA code points. We choose to use the non-PUA code points to +-% be compatible with ICU's similar choice. In choosing the non-PUA +-% code points we can no longer convert the old PUA code points back +-% to GB-18030-2005 (technically only fixable if we added support +-% for non-roundtrip code points e.g. ICU's "fallback mapping"). +-% The recommendation to use the non-PUA code points, where available, +-% is based on "CJKV Information Processing" 2nd Ed. by Dr. Ken Lunde. +-% +-% These 10 PUA mappings use equivalents from to . +-% /xa6/xd9 +-% /xa6/xda +-% /xa6/xdb +-% /xa6/xdc +-% /xa6/xdd +-% /xa6/xde +-% /xa6/xdf +-% /xa6/xec +-% /xa6/xed +-% /xa6/xf3 ++ /x84/x31/x82/x36 ++ /x84/x31/x82/x38 ++ /x84/x31/x82/x37 ++ /x84/x31/x82/x39 ++ /x84/x31/x83/x30 ++ /x84/x31/x83/x31 ++ /x84/x31/x83/x32 ++ /x84/x31/x83/x33 ++ /x84/x31/x83/x34 ++ /x84/x31/x83/x35 + /xa6/xf6 + /xa6/xf7 + /xa6/xf8 +@@ -57387,17 +57371,15 @@ CHARMAP + /xd7/xfd + /xd7/xfe + /x83/x36/xc9/x34 +-% These 3 PUA mappings use equivalents , and . +-% /xfe/x51 +-% /xfe/x52 +-% /xfe/x53 ++ /xfe/x51 ++ /xfe/x52 ++ /xfe/x53 + /x83/x36/xc9/x35 + /x83/x36/xc9/x36 + /x83/x36/xc9/x37 + /x83/x36/xc9/x38 + /x83/x36/xc9/x39 +-% This 1 PUA mapping uses the equivalent . +-% /xfe/x59 ++ /x82/x35/x90/x37 + /x83/x36/xca/x30 + /x83/x36/xca/x31 + /x83/x36/xca/x32 +@@ -57405,22 +57387,19 @@ CHARMAP + /x83/x36/xca/x34 + /x83/x36/xca/x35 + /x83/x36/xca/x36 +-% This 1 PUA mapping uses the equivalent . +-% /xfe/x61 ++ /x82/x35/x90/x38 + /x83/x36/xca/x37 + /x83/x36/xca/x38 + /x83/x36/xca/x39 + /x83/x36/xcb/x30 +-% These 2 PUA mappings use the equivalents and . +-% /xfe/x66 +-% /xfe/x67 ++ /x82/x35/x90/x39 ++ /x82/x35/x91/x30 + /x83/x36/xcb/x31 + /x83/x36/xcb/x32 + /x83/x36/xcb/x33 + /x83/x36/xcb/x34 +-% These 2 PUA mappings use the equivalents and . +-% /xfe/x6c +-% /xfe/x6d ++ /xfe/x6c ++ /x82/x35/x91/x31 + /x83/x36/xcb/x35 + /x83/x36/xcb/x36 + /x83/x36/xcb/x37 +@@ -57429,8 +57408,7 @@ CHARMAP + /x83/x36/xcc/x30 + /x83/x36/xcc/x31 + /x83/x36/xcc/x32 +-% This 1 PUA mapping uses the equivalent . +-% /xfe/x76 ++ /xfe/x76 + /x83/x36/xcc/x33 + /x83/x36/xcc/x34 + /x83/x36/xcc/x35 +@@ -57438,8 +57416,7 @@ CHARMAP + /x83/x36/xcc/x37 + /x83/x36/xcc/x38 + /x83/x36/xcc/x39 +-% This 1 PUA mapping uses the equivalent . +-% /xfe/x7e ++ /x82/x35/x91/x32 + /x83/x36/xcd/x30 + /x83/x36/xcd/x31 + /x83/x36/xcd/x32 +@@ -57456,9 +57433,8 @@ CHARMAP + /x83/x36/xce/x33 + /x83/x36/xce/x34 + /x83/x36/xce/x35 +-% These 2 PUA mappings use the equivalents and . +-% /xfe/x90 +-% /xfe/x91 ++ /x82/x35/x91/x33 ++ /xfe/x91 + /x83/x36/xce/x36 + /x83/x36/xce/x37 + /x83/x36/xce/x38 +@@ -57473,8 +57449,7 @@ CHARMAP + /x83/x36/xcf/x37 + /x83/x36/xcf/x38 + /x83/x36/xcf/x39 +-% This 1 PUA mapping uses the equivalent . +-% /xfe/xa0 ++ /x82/x35/x91/x34 + /x83/x36/xd0/x30 + /x83/x36/xd0/x31 + /x83/x36/xd0/x32 +@@ -70447,19 +70422,14 @@ CHARMAP + .. /x95/x32/x8d/x30 + .. /x95/x32/x8e/x30 + .. /x95/x32/x8f/x30 +- /x95/x32/x90/x30 +- /xfe/x51 +- /x95/x32/x90/x32 +- /xfe/x52 +-.. /x95/x32/x90/x34 ++.. /x95/x32/x90/x30 + .. /x95/x32/x91/x30 + .. /x95/x32/x92/x30 + .. /x95/x32/x93/x30 + .. /x95/x32/x94/x30 + .. /x95/x32/x95/x30 + .. /x95/x32/x96/x30 +- /xfe/x53 +-.. /x95/x32/x97/x31 ++.. /x95/x32/x97/x30 + .. /x95/x32/x98/x30 + .. /x95/x32/x99/x30 + .. /x95/x32/x9a/x30 +@@ -70998,8 +70968,7 @@ CHARMAP + .. /x95/x36/xb7/x30 + .. /x95/x36/xb8/x30 + .. /x95/x36/xb9/x30 +- /xfe/x6c +-.. /x95/x36/xb9/x38 ++.. /x95/x36/xb9/x37 + .. /x95/x36/xba/x30 + .. /x95/x36/xbb/x30 + .. /x95/x36/xbc/x30 +@@ -71505,8 +71474,7 @@ CHARMAP + .. /x96/x30/xb8/x30 + .. /x96/x30/xb9/x30 + .. /x96/x30/xba/x30 +- /xfe/x76 +-.. /x96/x30/xba/x36 ++.. /x96/x30/xba/x35 + .. /x96/x30/xbb/x30 + .. /x96/x30/xbc/x30 + .. /x96/x30/xbd/x30 +@@ -72132,8 +72100,7 @@ CHARMAP + .. /x96/x35/xb3/x30 + .. /x96/x35/xb4/x30 + .. /x96/x35/xb5/x30 +- /xfe/x91 +-.. /x96/x35/xb6/x31 ++.. /x96/x35/xb6/x30 + .. /x96/x35/xb7/x30 + .. /x96/x35/xb8/x30 + .. /x96/x35/xb9/x30 diff --git a/SOURCES/glibc-RHEL-56539.patch b/SOURCES/glibc-RHEL-56539.patch new file mode 100644 index 0000000..64d5b3f --- /dev/null +++ b/SOURCES/glibc-RHEL-56539.patch @@ -0,0 +1,146 @@ +commit f4ae345810942db891bddf9b482c72b3a120c3b2 +Author: Florian Weimer +Date: Thu Aug 29 11:06:08 2024 +0200 + + io: Add tst-lstat-nofollow, tst-lstat-nofollow-time64 + + They verify that lstat, lstat64 do not follow symbolic links. + + Reviewed-by: DJ Delorie + +Conflicts: + io/Makefile (new test added) + +diff --git a/io/Makefile b/io/Makefile +index cc78a438a8898ae3..05e6b798d669d1b1 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -81,7 +81,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-closefrom \ + tst-ftw-bz28126 \ + tst-fchmod-errors \ +- tst-fchmod-fuse ++ tst-fchmod-fuse \ ++ tst-lstat-nofollow \ + + tests-time64 := \ + tst-fcntl-time64 \ +@@ -90,6 +91,7 @@ tests-time64 := \ + tst-futimes-time64\ + tst-futimesat-time64 \ + tst-lchmod-time64 \ ++ tst-lstat-nofollow-time64 \ + tst-lutimes-time64 \ + tst-stat-time64 \ + tst-utime-time64 \ +diff --git a/io/tst-lstat-nofollow-time64.c b/io/tst-lstat-nofollow-time64.c +new file mode 100644 +index 0000000000000000..45feb3f13085ae44 +--- /dev/null ++++ b/io/tst-lstat-nofollow-time64.c +@@ -0,0 +1 @@ ++#include "tst-lstat-nofollow.c" +diff --git a/io/tst-lstat-nofollow.c b/io/tst-lstat-nofollow.c +new file mode 100644 +index 0000000000000000..5bbb557c72938a8a +--- /dev/null ++++ b/io/tst-lstat-nofollow.c +@@ -0,0 +1,98 @@ ++/* Test that lstat does not follow symbolic links. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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: ++ { ++ TEST_COMPARE (inh->nodeid, 1); ++ TEST_COMPARE_STRING (support_fuse_cast (LOOKUP, inh), "symlink"); ++ struct fuse_entry_out *out = support_fuse_prepare_entry (f, 2); ++ out->attr.mode = S_IFLNK | 0777; ++ out->attr.size = strlen ("target"); ++ support_fuse_reply_prepared (f); ++ } ++ break; ++ case FUSE_GETATTR: ++ { ++ TEST_COMPARE (inh->nodeid, 2); ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFLNK | 0777; ++ out->attr.size = strlen ("target"); ++ support_fuse_reply_prepared (f); ++ } ++ break; ++ case FUSE_READLINK: ++ /* The lstat operation must not attempt to look at the ++ symbolic link target. */ ++ FAIL ("attempt to obtain target of symblic link for node %llu", ++ (unsigned long long int) inh->nodeid); ++ break; ++ default: ++ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode)); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ char *symlink_path = xasprintf ("%s/symlink", support_fuse_mountpoint (f)); ++ ++ { ++ struct stat st = { 0, }; ++ TEST_COMPARE (lstat (symlink_path, &st), 0); ++ TEST_COMPARE (st.st_uid, getuid ()); ++ TEST_COMPARE (st.st_gid, getgid ()); ++ TEST_COMPARE (st.st_size, 6); ++ TEST_COMPARE (st.st_mode, S_IFLNK | 0777); ++ } ++ ++ { ++ struct stat64 st = { 0, }; ++ TEST_COMPARE (lstat64 (symlink_path, &st), 0); ++ TEST_COMPARE (st.st_uid, getuid ()); ++ TEST_COMPARE (st.st_gid, getgid ()); ++ TEST_COMPARE (st.st_size, 6); ++ TEST_COMPARE (st.st_mode, S_IFLNK | 0777); ++ } ++ ++ free (symlink_path); ++ support_fuse_unmount (f); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-56540-1.patch b/SOURCES/glibc-RHEL-56540-1.patch new file mode 100644 index 0000000..f1f1941 --- /dev/null +++ b/SOURCES/glibc-RHEL-56540-1.patch @@ -0,0 +1,526 @@ +commit 1251e9ea49fba9f53bbf4f290f3db90c01931fa7 +Author: Florian Weimer +Date: Thu Sep 12 09:40:25 2024 +0200 + + support: Add + + It allows to read directories using the six readdir variants + without writing type-specific code or using skeleton files + that are compiled four times. + + The readdir_r subtest for support_readdir_expect_error revealed + bug 32124. + + Reviewed-by: DJ Delorie + +diff --git a/support/Makefile b/support/Makefile +index c7e03b76cc64c805..3b8509c88db4662a 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -77,6 +77,7 @@ libsupport-routines = \ + support_quote_blob \ + support_quote_blob_wide \ + support_quote_string \ ++ support_readdir \ + support_readdir_check \ + support_readdir_r_check \ + support_record_failure \ +@@ -326,6 +327,7 @@ tests = \ + tst-support_quote_blob \ + tst-support_quote_blob_wide \ + tst-support_quote_string \ ++ tst-support_readdir \ + tst-support_record_failure \ + tst-test_compare \ + tst-test_compare_blob \ +diff --git a/support/readdir.h b/support/readdir.h +new file mode 100644 +index 0000000000000000..7d7c7650d42efb70 +--- /dev/null ++++ b/support/readdir.h +@@ -0,0 +1,85 @@ ++/* Type-generic wrapper for readdir 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 ++ 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 ++ . */ ++ ++#ifndef SUPPORT_READDIR_H ++#define SUPPORT_READDIR_H ++ ++#include ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Definition independent of _FILE_OFFSET_BITS. */ ++struct support_dirent ++{ ++ uint64_t d_ino; ++ uint64_t d_off; /* 0 if d_off is not supported. */ ++ uint32_t d_type; ++ char *d_name; ++}; ++ ++/* Operation to be performed by support_readdir below. */ ++enum support_readdir_op ++ { ++ SUPPORT_READDIR, ++ SUPPORT_READDIR64, ++ SUPPORT_READDIR_R, ++ SUPPORT_READDIR64_R, ++ SUPPORT_READDIR64_COMPAT, ++ SUPPORT_READDIR64_R_COMPAT, ++ }; ++ ++/* Returns the last supported function. May exclude ++ SUPPORT_READDIR64_R_COMPAT if not implemented. */ ++enum support_readdir_op support_readdir_op_last (void); ++ ++/* Returns the name of the function that corresponds to the OP constant. */ ++const char *support_readdir_function (enum support_readdir_op op); ++ ++/* Returns the d_ino field width for OP, in bits. */ ++unsigned int support_readdir_inode_width (enum support_readdir_op op); ++ ++/* Returns the d_off field width for OP, in bits. Zero if not present. */ ++unsigned int support_readdir_offset_width (enum support_readdir_op op); ++ ++/* Returns true if OP is an _r variant with name length restrictions. */ ++bool support_readdir_r_variant (enum support_readdir_op op); ++ ++/* First, free E->d_name and set the field to NULL. Then call the ++ readdir variant as specified by OP. If successfully, copy fields ++ to E, make a copy of the entry name using strdup, and write its ++ addres sto E->d_name. ++ ++ Return true if an entry was read, or false if the end of the ++ directory stream was reached. Terminates the process upon error. ++ The caller is expected to free E->d_name if the function is not ++ called again for this E. ++ ++ Note that this function assumes that E->d_name has been initialized ++ to NULL or has been allocated by a previous call to this function. */ ++bool support_readdir (DIR *stream, enum support_readdir_op op, ++ struct support_dirent *e) __nonnull ((1, 3)); ++ ++/* Checks that the readdir operation OP fails with errno value EXPECTED. */ ++void support_readdir_expect_error (DIR *stream, enum support_readdir_op op, ++ int expected) __nonnull ((1)); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_READDIR_H */ +diff --git a/support/support_readdir.c b/support/support_readdir.c +new file mode 100644 +index 0000000000000000..10d808416f7a0456 +--- /dev/null ++++ b/support/support_readdir.c +@@ -0,0 +1,318 @@ ++/* Type-generic wrapper for readdir 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 ++ 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Copied from . */ ++struct __old_dirent64 ++ { ++ __ino_t d_ino; ++ __off64_t d_off; ++ unsigned short int d_reclen; ++ unsigned char d_type; ++ char d_name[256]; ++ }; ++ ++static struct __old_dirent64 *(*readdir64_compat) (DIR *); ++static int (*readdir64_r_compat) (DIR *, struct __old_dirent64 *, ++ struct __old_dirent64 **); ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ /* These compat symbols exists on alpha, i386, m67k , powerpc, s390, ++ sparc. at the same GLIBC_2.1 version. */ ++ readdir64_compat = dlvsym (RTLD_DEFAULT, "readdir64", "GLIBC_2.1"); ++ readdir64_r_compat = dlvsym (RTLD_DEFAULT, "readdir64_r", "GLIBC_2.1"); ++} ++ ++enum support_readdir_op ++support_readdir_op_last (void) ++{ ++ if (readdir64_r_compat != NULL) ++ { ++ TEST_VERIFY (readdir64_compat != NULL); ++ return SUPPORT_READDIR64_R_COMPAT; ++ } ++ else ++ return SUPPORT_READDIR64_R; ++} ++ ++const char * ++support_readdir_function (enum support_readdir_op op) ++{ ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ return "readdir"; ++ case SUPPORT_READDIR64: ++ return "readdir64"; ++ case SUPPORT_READDIR_R: ++ return "readdir_r"; ++ case SUPPORT_READDIR64_R: ++ return "readdir64_r"; ++ case SUPPORT_READDIR64_COMPAT: ++ return "readdir64@GBLIC_2.1"; ++ case SUPPORT_READDIR64_R_COMPAT: ++ return "readdir64_r@GBLIC_2.1"; ++ } ++ FAIL_EXIT1 ("invalid support_readdir_op constant: %d", op); ++} ++ ++unsigned int ++support_readdir_inode_width (enum support_readdir_op op) ++{ ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ case SUPPORT_READDIR_R: ++ return sizeof ((struct dirent) { 0, }.d_ino) * 8; ++ case SUPPORT_READDIR64: ++ case SUPPORT_READDIR64_R: ++ return sizeof ((struct dirent64) { 0, }.d_ino) * 8; ++ case SUPPORT_READDIR64_COMPAT: ++ case SUPPORT_READDIR64_R_COMPAT: ++ return sizeof ((struct __old_dirent64) { 0, }.d_ino) * 8; ++ } ++ FAIL_EXIT1 ("invalid support_readdir_op constant: %d", op); ++} ++ ++unsigned int ++support_readdir_offset_width (enum support_readdir_op op) ++{ ++#ifdef _DIRENT_HAVE_D_OFF ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ case SUPPORT_READDIR_R: ++ return sizeof ((struct dirent) { 0, }.d_off) * 8; ++ case SUPPORT_READDIR64: ++ case SUPPORT_READDIR64_R: ++ return sizeof ((struct dirent64) { 0, }.d_off) * 8; ++ case SUPPORT_READDIR64_COMPAT: ++ case SUPPORT_READDIR64_R_COMPAT: ++ return sizeof ((struct __old_dirent64) { 0, }.d_off) * 8; ++ } ++#else ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ case SUPPORT_READDIR_R: ++ case SUPPORT_READDIR64: ++ case SUPPORT_READDIR64_R: ++ case SUPPORT_READDIR64_COMPAT: ++ case SUPPORT_READDIR64_R_COMPAT: ++ return 0; ++ } ++#endif ++ FAIL_EXIT1 ("invalid support_readdir_op constant: %d", op); ++} ++ ++bool ++support_readdir_r_variant (enum support_readdir_op op) ++{ ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ case SUPPORT_READDIR64: ++ case SUPPORT_READDIR64_COMPAT: ++ return false; ++ case SUPPORT_READDIR_R: ++ case SUPPORT_READDIR64_R: ++ case SUPPORT_READDIR64_R_COMPAT: ++ return true; ++ } ++ FAIL_EXIT1 ("invalid support_readdir_op constant: %d", op); ++} ++ ++static bool ++copy_dirent (struct support_dirent *dst, struct dirent *src) ++{ ++ if (src == NULL) ++ return false; ++ dst->d_ino = src->d_ino; ++#ifdef _DIRENT_HAVE_D_OFF ++ dst->d_off = src->d_off; ++#else ++ dst->d_off = 0; ++#endif ++ dst->d_type = src->d_type; ++ dst->d_name = xstrdup (src->d_name); ++ return true; ++} ++ ++static bool ++copy_dirent64 (struct support_dirent *dst, struct dirent64 *src) ++{ ++ if (src == NULL) ++ return false; ++ dst->d_ino = src->d_ino; ++#ifdef _DIRENT_HAVE_D_OFF ++ dst->d_off = src->d_off; ++#else ++ dst->d_off = 0; ++#endif ++ dst->d_type = src->d_type; ++ dst->d_name = xstrdup (src->d_name); ++ return true; ++} ++ ++static bool ++copy_old_dirent64 (struct support_dirent *dst, struct __old_dirent64 *src) ++{ ++ if (src == NULL) ++ return false; ++ dst->d_ino = src->d_ino; ++#ifdef _DIRENT_HAVE_D_OFF ++ dst->d_off = src->d_off; ++#else ++ dst->d_off = 0; ++#endif ++ dst->d_type = src->d_type; ++ dst->d_name = xstrdup (src->d_name); ++ return true; ++} ++ ++bool ++support_readdir (DIR *stream, enum support_readdir_op op, ++ struct support_dirent *e) ++{ ++ free (e->d_name); ++ e->d_name = NULL; ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ return copy_dirent (e, xreaddir (stream)); ++ case SUPPORT_READDIR64: ++ return copy_dirent64 (e, xreaddir64 (stream)); ++ ++ /* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); ++ ++ case SUPPORT_READDIR_R: ++ { ++ struct dirent buf; ++ if (!xreaddir_r (stream, &buf)) ++ return false; ++ return copy_dirent (e, &buf); ++ } ++ case SUPPORT_READDIR64_R: ++ { ++ struct dirent64 buf; ++ if (!xreaddir64_r (stream, &buf)) ++ return false; ++ return copy_dirent64 (e, &buf); ++ } ++ ++ DIAG_POP_NEEDS_COMMENT; ++ ++ case SUPPORT_READDIR64_COMPAT: ++ if (readdir64_compat == NULL) ++ FAIL_EXIT1 ("readdir64 compat function not implemented"); ++ return copy_old_dirent64 (e, readdir64_compat (stream)); ++ ++ case SUPPORT_READDIR64_R_COMPAT: ++ { ++ if (readdir64_r_compat == NULL) ++ FAIL_EXIT1 ("readdir64_r compat function not implemented"); ++ struct __old_dirent64 buf; ++ struct __old_dirent64 *e1; ++ int ret = readdir64_r_compat (stream, &buf, &e1); ++ if (ret != 0) ++ { ++ errno = ret; ++ FAIL ("readdir64_r@GLIBC_2.1: %m"); ++ return false; ++ } ++ if (e1 == NULL) ++ return false; ++ return copy_old_dirent64 (e, e1); ++ } ++ } ++ FAIL_EXIT1 ("support_readdir: invalid op argument %d", (int) op); ++} ++ ++void ++support_readdir_expect_error (DIR *stream, enum support_readdir_op op, ++ int expected) ++{ ++ switch (op) ++ { ++ case SUPPORT_READDIR: ++ errno = 0; ++ TEST_VERIFY (readdir (stream) == NULL); ++ TEST_COMPARE (errno, expected); ++ return; ++ case SUPPORT_READDIR64: ++ errno = 0; ++ TEST_VERIFY (readdir64 (stream) == NULL); ++ TEST_COMPARE (errno, expected); ++ return; ++ ++ /* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); ++ ++ case SUPPORT_READDIR_R: ++ { ++ struct dirent buf; ++ struct dirent *e; ++ errno = readdir_r (stream, &buf, &e); ++ TEST_COMPARE (errno, expected);; ++ } ++ return; ++ case SUPPORT_READDIR64_R: ++ { ++ struct dirent64 buf; ++ struct dirent64 *e; ++ errno = readdir64_r (stream, &buf, &e); ++ TEST_COMPARE (errno, expected);; ++ } ++ return; ++ ++ DIAG_POP_NEEDS_COMMENT; ++ ++ case SUPPORT_READDIR64_COMPAT: ++ if (readdir64_compat == NULL) ++ FAIL_EXIT1 ("readdir64_r compat function not implemented"); ++ errno = 0; ++ TEST_VERIFY (readdir64_compat (stream) == NULL); ++ TEST_COMPARE (errno, expected); ++ return; ++ case SUPPORT_READDIR64_R_COMPAT: ++ { ++ if (readdir64_r_compat == NULL) ++ FAIL_EXIT1 ("readdir64_r compat function not implemented"); ++ struct __old_dirent64 buf; ++ struct __old_dirent64 *e; ++ errno = readdir64_r_compat (stream, &buf, &e); ++ TEST_COMPARE (errno, expected); ++ } ++ return; ++ } ++ FAIL_EXIT1 ("support_readdir_expect_error: invalid op argument %d", ++ (int) op); ++} +diff --git a/support/tst-support_readdir.c b/support/tst-support_readdir.c +new file mode 100644 +index 0000000000000000..c0639571c7c3f516 +--- /dev/null ++++ b/support/tst-support_readdir.c +@@ -0,0 +1,70 @@ ++/* Test the support_readdir 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ DIR *reference_stream = xopendir ("."); ++ struct dirent64 *reference = xreaddir64 (reference_stream); ++ ++ for (enum support_readdir_op op = 0; op <= support_readdir_op_last (); ++op) ++ { ++ DIR *stream = xopendir ("."); ++ struct support_dirent e; ++ memset (&e, 0xcc, sizeof (e)); ++ e.d_name = NULL; ++ TEST_VERIFY (support_readdir (stream, op, &e)); ++ TEST_COMPARE (e.d_ino, reference->d_ino); ++ if (support_readdir_offset_width (op) != 0) ++ TEST_COMPARE (e.d_off, reference->d_off); ++ else ++ TEST_COMPARE (e.d_off, 0); ++ TEST_COMPARE (e.d_type, reference->d_type); ++ TEST_COMPARE_STRING (e.d_name, reference->d_name); ++ free (e.d_name); ++ xclosedir (stream); ++ } ++ ++ xclosedir (reference_stream); ++ ++ /* Error injection test. */ ++ int devnull = xopen ("/dev/null", O_RDONLY, 0); ++ for (enum support_readdir_op op = 0; op <= support_readdir_op_last (); ++op) ++ { ++ DIR *stream = xopendir ("."); ++ /* A descriptor incompatible with readdir. */ ++ xdup2 (devnull, dirfd (stream)); ++ errno = -1; ++ support_readdir_expect_error (stream, op, ENOTDIR); ++ xclosedir (stream); ++ } ++ xclose (devnull); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-56540-2.patch b/SOURCES/glibc-RHEL-56540-2.patch new file mode 100644 index 0000000..a4ccf82 --- /dev/null +++ b/SOURCES/glibc-RHEL-56540-2.patch @@ -0,0 +1,34 @@ +commit c9154cad66aa0b11ede62cc9190d3485c5ef6941 +Author: Florian Weimer +Date: Thu Sep 12 18:26:04 2024 +0200 + + support: Fix Hurd build of tst-support_readdir + + Check for the availability of the d_off member at compile time, not + run time. + + Fixes commit 1251e9ea49fba9f53bbf4f290f3db90c01931fa7 + ("support: Add "). + +diff --git a/support/tst-support_readdir.c b/support/tst-support_readdir.c +index c0639571c7c3f516..66be94fa802e727a 100644 +--- a/support/tst-support_readdir.c ++++ b/support/tst-support_readdir.c +@@ -39,10 +39,13 @@ do_test (void) + e.d_name = NULL; + TEST_VERIFY (support_readdir (stream, op, &e)); + TEST_COMPARE (e.d_ino, reference->d_ino); +- if (support_readdir_offset_width (op) != 0) +- TEST_COMPARE (e.d_off, reference->d_off); +- else +- TEST_COMPARE (e.d_off, 0); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_VERIFY (support_readdir_offset_width (op) != 0); ++ TEST_COMPARE (e.d_off, reference->d_off); ++#else ++ TEST_COMPARE (support_readdir_offset_width (op), 0); ++ TEST_COMPARE (e.d_off, 0); ++#endif + TEST_COMPARE (e.d_type, reference->d_type); + TEST_COMPARE_STRING (e.d_name, reference->d_name); + free (e.d_name); diff --git a/SOURCES/glibc-RHEL-56540-3.patch b/SOURCES/glibc-RHEL-56540-3.patch new file mode 100644 index 0000000..b35ccfc --- /dev/null +++ b/SOURCES/glibc-RHEL-56540-3.patch @@ -0,0 +1,241 @@ +commit 6aa1645f669322b36bda8e1fded6fd524d3e08ff +Author: Florian Weimer +Date: Sat Sep 21 19:32:34 2024 +0200 + + dirent: Add tst-rewinddir + + It verifies that rewinddir allows restarting the directory + iteration. + + Reviewed-by: DJ Delorie + +Conflicts: + dirent/Makefile (new test added) + +diff --git a/dirent/Makefile b/dirent/Makefile +index afc7226a5bf012d6..5bad3c112209a2ce 100644 +--- a/dirent/Makefile ++++ b/dirent/Makefile +@@ -31,7 +31,8 @@ routines := opendir closedir readdir readdir_r rewinddir \ + scandir-cancel scandir-tail scandir64-tail + + tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ +- tst-fdopendir2 tst-scandir tst-scandir64 ++ tst-fdopendir2 tst-scandir tst-scandir64 \ ++ tst-rewinddir \ + + CFLAGS-scandir.c += $(uses-callbacks) + CFLAGS-scandir64.c += $(uses-callbacks) +diff --git a/dirent/tst-rewinddir.c b/dirent/tst-rewinddir.c +new file mode 100644 +index 0000000000000000..1479766ebe8fc911 +--- /dev/null ++++ b/dirent/tst-rewinddir.c +@@ -0,0 +1,207 @@ ++/* Test for rewinddir, using FUSE. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Return the file name at the indicated directory offset. */ ++static char * ++name_at_offset (unsigned int offset) ++{ ++ if (offset <= 1) ++ return xstrdup (".." + !offset); /* "." or "..". */ ++ else ++ /* Pad the name with a lot of zeros, so that the dirent buffer gets ++ filled more quickly. */ ++ return xasprintf ("file%0240u", offset); ++} ++ ++/* This many directory entries, including "." and "..". */ ++enum { directory_entries = 200 }; ++ ++/* Add the directory entry at OFFSET to the stream D. */ ++static uint64_t ++add_directory_entry (struct support_fuse_dirstream *d, uint64_t offset) ++{ ++ if (offset >= directory_entries) ++ return 0; ++ ++ char *name = name_at_offset (offset); ++ uint64_t ino = 1000 + offset; /* Arbitrary value, distinct from 1. */ ++ uint32_t type = DT_REG; ++ if (offset <= 1) ++ { ++ type = DT_DIR; ++ ino = 1; ++ } ++ ++ ++offset; ++ bool added = support_fuse_dirstream_add (d, ino, offset, type, name); ++ free (name); ++ if (added) ++ return offset; ++ else ++ return 0; ++} ++ ++/* Set to true if getdents64 should produce only one entry. */ ++static bool one_entry_per_getdents64; ++ ++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_READDIR: ++ if (inh->nodeid == 1) ++ { ++ uint64_t offset = support_fuse_cast (READ, inh)->offset; ++ struct support_fuse_dirstream *d ++ = support_fuse_prepare_readdir (f); ++ while (true) ++ { ++ offset = add_directory_entry (d, offset); ++ if (offset == 0 || one_entry_per_getdents64) ++ break; ++ } ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ default: ++ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode)); ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++/* Lists the entire directory from start to end. */ ++static void ++verify_directory (DIR *dir, enum support_readdir_op op) ++{ ++ struct support_dirent e = { 0, }; ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "."); ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, ".."); ++ for (int i = 2; i < directory_entries; ++i) ++ { ++ char *expected = name_at_offset (i); ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, expected); ++ free (expected); ++ } ++ TEST_VERIFY (!support_readdir (dir, op, &e)); ++ free (e.d_name); ++} ++ ++/* Run tests with rewinding after ENTRIES readdir calls. */ ++static void ++rewind_after (unsigned int rewind_at) ++{ ++ for (enum support_readdir_op op = 0; op <= support_readdir_op_last (); ++op) ++ { ++ printf ("info: testing %s (rewind_at=%u)\n", ++ support_readdir_function (op), rewind_at); ++ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ struct support_dirent e = { 0, }; ++ ++ switch (rewind_at) ++ { ++ case 0: ++ break; ++ case 1: ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "."); ++ break; ++ default: ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "."); ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, ".."); ++ for (int i = 2; i < directory_entries; ++i) ++ { ++ if (i == rewind_at) ++ break; ++ char *expected = name_at_offset (i); ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, expected); ++ free (expected); ++ } ++ break; ++ } ++ ++ errno = 0; ++ rewinddir (dir); ++ TEST_COMPARE (errno, 0); ++ verify_directory (dir, op); ++ ++ free (e.d_name); ++ xclosedir (dir); ++ support_fuse_unmount (f); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ /* One pass without rewinding to verify that the generated directory ++ content matches expectations. */ ++ { ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ verify_directory (dir, SUPPORT_READDIR64); ++ xclosedir (dir); ++ support_fuse_unmount (f); ++ } ++ ++ for (int do_unbuffered = 0; do_unbuffered < 2; ++do_unbuffered) ++ { ++ one_entry_per_getdents64 = do_unbuffered; ++ ++ for (int i = 0; i < 20; ++i) ++ rewind_after (i); ++ rewind_after (50); ++ rewind_after (100); ++ rewind_after (150); ++ rewind_after (180); ++ rewind_after (199); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-56542-1.patch b/SOURCES/glibc-RHEL-56542-1.patch new file mode 100644 index 0000000..e0fe19d --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-1.patch @@ -0,0 +1,56 @@ +commit 0e12ca024119ec6c6d2ac852a65046002efa0e80 +Author: Steve Grubb +Date: Fri Mar 11 15:29:06 2022 -0500 + + associate a deallocation for opendir + + This patch associates closedir as a deallocation for opendir and fdopendir. + This required moving the closedir declaration above the other 2 functions. + + Reviewed-by: Paul Eggert + Reviewed-by: Siddhesh Poyarekar + +diff --git a/dirent/dirent.h b/dirent/dirent.h +index 1d1fab7e55cdad4d..84834e8db9dea874 100644 +--- a/dirent/dirent.h ++++ b/dirent/dirent.h +@@ -126,28 +126,30 @@ enum + The actual structure is opaque to users. */ + typedef struct __dirstream DIR; + ++/* Close the directory stream DIRP. ++ Return 0 if successful, -1 if not. ++ ++ This function is a possible cancellation point and therefore not ++ marked with __THROW. */ ++extern int closedir (DIR *__dirp) __nonnull ((1)); ++ + /* Open a directory stream on NAME. + Return a DIR stream on the directory, or NULL if it could not be opened. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +-extern DIR *opendir (const char *__name) __nonnull ((1)); ++extern DIR *opendir (const char *__name) __nonnull ((1)) ++ __attribute_malloc__ __attr_dealloc (closedir, 1); + + #ifdef __USE_XOPEN2K8 + /* Same as opendir, but open the stream on the file descriptor FD. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +-extern DIR *fdopendir (int __fd); ++extern DIR *fdopendir (int __fd) ++ __attribute_malloc__ __attr_dealloc (closedir, 1); + #endif + +-/* Close the directory stream DIRP. +- Return 0 if successful, -1 if not. +- +- This function is a possible cancellation point and therefore not +- marked with __THROW. */ +-extern int closedir (DIR *__dirp) __nonnull ((1)); +- + /* Read a directory entry from DIRP. Return a pointer to a `struct + dirent' describing the entry, or NULL for EOF or error. The + storage returned may be overwritten by a later readdir call on the diff --git a/SOURCES/glibc-RHEL-56542-2.patch b/SOURCES/glibc-RHEL-56542-2.patch new file mode 100644 index 0000000..ebdd4fb --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-2.patch @@ -0,0 +1,236 @@ +commit 766b73768b290b303f5b56268c6c0d588d5a9267 +Author: Florian Weimer +Date: Mon Sep 19 08:10:41 2022 +0200 + + Linux: Do not skip d_ino == 0 entries in readdir, readdir64 (bug 12165) + + POSIX does not say this value is special. For example, old XFS file + systems may still use inode number zero. + + Also update the comment regarding ENOENT. Linux may return ENOENT + for some file systems. + +diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c +index b4801351645d1236..ef95611f09e761a4 100644 +--- a/sysdeps/unix/sysv/linux/readdir.c ++++ b/sysdeps/unix/sysv/linux/readdir.c +@@ -28,48 +28,33 @@ __readdir_unlocked (DIR *dirp) + struct dirent *dp; + int saved_errno = errno; + +- do ++ if (dirp->offset >= dirp->size) + { +- size_t reclen; ++ /* We've emptied out our buffer. Refill it. */ + +- if (dirp->offset >= dirp->size) ++ size_t maxread = dirp->allocation; ++ ssize_t bytes; ++ ++ bytes = __getdents (dirp->fd, dirp->data, maxread); ++ if (bytes <= 0) + { +- /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- bytes = __getdents (dirp->fd, dirp->data, maxread); +- if (bytes <= 0) +- { +- /* On some systems getdents fails with ENOENT when the +- open directory has been rmdir'd already. POSIX.1 +- requires that we treat this condition like normal EOF. */ +- if (bytes < 0 && errno == ENOENT) +- bytes = 0; +- +- /* Don't modifiy errno when reaching EOF. */ +- if (bytes == 0) +- __set_errno (saved_errno); +- dp = NULL; +- break; +- } +- dirp->size = (size_t) bytes; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; ++ /* Linux may fail with ENOENT on some file systems if the ++ directory inode is marked as dead (deleted). POSIX ++ treats this as a regular end-of-directory condition, so ++ do not set errno in that case, to indicate success. */ ++ if (bytes == 0 || errno == ENOENT) ++ __set_errno (saved_errno); ++ return NULL; + } ++ dirp->size = (size_t) bytes; + +- dp = (struct dirent *) &dirp->data[dirp->offset]; +- +- reclen = dp->d_reclen; +- +- dirp->offset += reclen; +- +- dirp->filepos = dp->d_off; ++ /* Reset the offset into the buffer. */ ++ dirp->offset = 0; ++ } + +- /* Skip deleted files. */ +- } while (dp->d_ino == 0); ++ dp = (struct dirent *) &dirp->data[dirp->offset]; ++ dirp->offset += dp->d_reclen; ++ dirp->filepos = dp->d_off; + + return dp; + } +diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c +index 52b11eb9d91bb5fd..8a60504649aa54a2 100644 +--- a/sysdeps/unix/sysv/linux/readdir64.c ++++ b/sysdeps/unix/sysv/linux/readdir64.c +@@ -37,48 +37,36 @@ __readdir64 (DIR *dirp) + __libc_lock_lock (dirp->lock); + #endif + +- do ++ if (dirp->offset >= dirp->size) + { +- size_t reclen; ++ /* We've emptied out our buffer. Refill it. */ + +- if (dirp->offset >= dirp->size) ++ size_t maxread = dirp->allocation; ++ ssize_t bytes; ++ ++ bytes = __getdents64 (dirp->fd, dirp->data, maxread); ++ if (bytes <= 0) + { +- /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- bytes = __getdents64 (dirp->fd, dirp->data, maxread); +- if (bytes <= 0) +- { +- /* On some systems getdents fails with ENOENT when the +- open directory has been rmdir'd already. POSIX.1 +- requires that we treat this condition like normal EOF. */ +- if (bytes < 0 && errno == ENOENT) +- bytes = 0; +- +- /* Don't modifiy errno when reaching EOF. */ +- if (bytes == 0) +- __set_errno (saved_errno); +- dp = NULL; +- break; +- } +- dirp->size = (size_t) bytes; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; ++ /* Linux may fail with ENOENT on some file systems if the ++ directory inode is marked as dead (deleted). POSIX ++ treats this as a regular end-of-directory condition, so ++ do not set errno in that case, to indicate success. */ ++ if (bytes == 0 || errno == ENOENT) ++ __set_errno (saved_errno); ++#if IS_IN (libc) ++ __libc_lock_unlock (dirp->lock); ++#endif ++ return NULL; + } ++ dirp->size = (size_t) bytes; + +- dp = (struct dirent64 *) &dirp->data[dirp->offset]; +- +- reclen = dp->d_reclen; +- +- dirp->offset += reclen; +- +- dirp->filepos = dp->d_off; ++ /* Reset the offset into the buffer. */ ++ dirp->offset = 0; ++ } + +- /* Skip deleted files. */ +- } while (dp->d_ino == 0); ++ dp = (struct dirent64 *) &dirp->data[dirp->offset]; ++ dirp->offset += dp->d_reclen; ++ dirp->filepos = dp->d_off; + + #if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +@@ -115,48 +103,36 @@ __old_readdir64 (DIR *dirp) + __libc_lock_lock (dirp->lock); + #endif + +- do ++ if (dirp->offset >= dirp->size) + { +- size_t reclen; ++ /* We've emptied out our buffer. Refill it. */ + +- if (dirp->offset >= dirp->size) ++ size_t maxread = dirp->allocation; ++ ssize_t bytes; ++ ++ bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); ++ if (bytes <= 0) + { +- /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); +- if (bytes <= 0) +- { +- /* On some systems getdents fails with ENOENT when the +- open directory has been rmdir'd already. POSIX.1 +- requires that we treat this condition like normal EOF. */ +- if (bytes < 0 && errno == ENOENT) +- bytes = 0; +- +- /* Don't modifiy errno when reaching EOF. */ +- if (bytes == 0) +- __set_errno (saved_errno); +- dp = NULL; +- break; +- } +- dirp->size = (size_t) bytes; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; ++ /* Linux may fail with ENOENT on some file systems if the ++ directory inode is marked as dead (deleted). POSIX ++ treats this as a regular end-of-directory condition, so ++ do not set errno in that case, to indicate success. */ ++ if (bytes == 0 || errno == ENOENT) ++ __set_errno (saved_errno); ++#if IS_IN (libc) ++ __libc_lock_unlock (dirp->lock); ++#endif ++ return NULL; + } ++ dirp->size = (size_t) bytes; + +- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; +- +- reclen = dp->d_reclen; +- +- dirp->offset += reclen; +- +- dirp->filepos = dp->d_off; ++ /* Reset the offset into the buffer. */ ++ dirp->offset = 0; ++ } + +- /* Skip deleted files. */ +- } while (dp->d_ino == 0); ++ dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; ++ dirp->offset += dp->d_reclen; ++ dirp->filepos = dp->d_off; + + #if IS_IN (libc) + __libc_lock_unlock (dirp->lock); diff --git a/SOURCES/glibc-RHEL-56542-3.patch b/SOURCES/glibc-RHEL-56542-3.patch new file mode 100644 index 0000000..180b29e --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-3.patch @@ -0,0 +1,104 @@ +commit 4e16d89866e660426438238a47c2345bdc47dd97 +Author: Adhemerval Zanella +Date: Thu Aug 10 08:56:00 2023 -0300 + + linux: Make fdopendir fail with O_PATH (BZ 30373) + + It is not strictly required by the POSIX, since O_PATH is a Linux + extension, but it is QoI to fail early instead of at readdir. Also + the check is free, since fdopendir already checks if the file + descriptor is opened for read. + + Checked on x86_64-linux-gnu. + +Conflicts: + sysdeps/unix/sysv/linux/Makefile (new test added) + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 617f7718b2a5779d..74656e56038844aa 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -125,6 +125,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ + tst-prctl \ + tst-scm_rights \ + tst-getauxval \ ++ tst-fdopendir-o_path \ + # tests + + # Test for the symbol version of fcntl that was replaced in glibc 2.28. +diff --git a/sysdeps/unix/sysv/linux/fdopendir.c b/sysdeps/unix/sysv/linux/fdopendir.c +index 32ec10e206305e3c..d06eeb3cafa4966c 100644 +--- a/sysdeps/unix/sysv/linux/fdopendir.c ++++ b/sysdeps/unix/sysv/linux/fdopendir.c +@@ -37,10 +37,16 @@ __fdopendir (int fd) + return NULL; + } + +- /* Make sure the descriptor allows for reading. */ + int flags = __fcntl64_nocancel (fd, F_GETFL); + if (__glibc_unlikely (flags == -1)) + return NULL; ++ /* Fail early for descriptors opened with O_PATH. */ ++ if (__glibc_unlikely (flags & O_PATH)) ++ { ++ __set_errno (EBADF); ++ return NULL; ++ } ++ /* Make sure the descriptor allows for reading. */ + if (__glibc_unlikely ((flags & O_ACCMODE) == O_WRONLY)) + { + __set_errno (EINVAL); +diff --git a/sysdeps/unix/sysv/linux/tst-fdopendir-o_path.c b/sysdeps/unix/sysv/linux/tst-fdopendir-o_path.c +new file mode 100644 +index 0000000000000000..2531cf8ddb92ff45 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-fdopendir-o_path.c +@@ -0,0 +1,48 @@ ++/* Check if fdopendir fails with file descriptor opened with O_PATH (BZ 30737) ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char *dirname = support_create_temp_directory ("tst-fdopendir-o_path"); ++ ++ { ++ int fd = xopen (dirname, O_RDONLY | O_DIRECTORY, 0600); ++ DIR *dir = fdopendir (fd); ++ TEST_VERIFY_EXIT (dir != NULL); ++ closedir (dir); ++ } ++ ++ { ++ int fd = xopen (dirname, O_RDONLY | O_PATH | O_DIRECTORY, 0600); ++ TEST_VERIFY (fdopendir (fd) == NULL); ++ TEST_COMPARE (errno, EBADF); ++ xclose (fd); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-56542-4.patch b/SOURCES/glibc-RHEL-56542-4.patch new file mode 100644 index 0000000..18eb644 --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-4.patch @@ -0,0 +1,80 @@ +commit a4a12af5abe22d63fbebf0a219d8d13eff6db20c +Author: Carlos O'Donell +Date: Thu Jun 8 07:30:33 2023 -0400 + + dirent: Reformat Makefile. + + Reflow and sort Makefile. + + Code generation changes present due to link order changes. + + No regressions on x86_64 and i686. + +Conflicts: + dirent/Makefile (resorting) + +diff --git a/dirent/Makefile b/dirent/Makefile +index 5bad3c112209a2ce..450bcd5d8981f40b 100644 +--- a/dirent/Makefile ++++ b/dirent/Makefile +@@ -22,17 +22,49 @@ subdir := dirent + + include ../Makeconfig + +-headers := dirent.h bits/dirent.h bits/dirent_ext.h +-routines := opendir closedir readdir readdir_r rewinddir \ +- seekdir telldir scandir alphasort versionsort \ +- getdents getdents64 dirfd readdir64 readdir64_r scandir64 \ +- alphasort64 versionsort64 fdopendir \ +- scandirat scandirat64 \ +- scandir-cancel scandir-tail scandir64-tail +- +-tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ +- tst-fdopendir2 tst-scandir tst-scandir64 \ +- tst-rewinddir \ ++headers := \ ++ bits/dirent.h \ ++ bits/dirent_ext.h \ ++ dirent.h \ ++ # headers ++routines := \ ++ alphasort \ ++ alphasort64 \ ++ closedir \ ++ dirfd \ ++ fdopendir \ ++ getdents \ ++ getdents64 \ ++ opendir \ ++ readdir \ ++ readdir64 \ ++ readdir64_r \ ++ readdir_r \ ++ rewinddir \ ++ scandir \ ++ scandir-cancel \ ++ scandir-tail \ ++ scandir64 \ ++ scandir64-tail \ ++ scandirat \ ++ scandirat64 \ ++ seekdir \ ++ telldir \ ++ versionsort \ ++ versionsort64 \ ++ # routines ++ ++tests := \ ++ bug-readdir1 \ ++ list \ ++ opendir-tst1 \ ++ tst-fdopendir \ ++ tst-fdopendir2 \ ++ tst-rewinddir \ ++ tst-scandir \ ++ tst-scandir64 \ ++ tst-seekdir \ ++ # tests + + CFLAGS-scandir.c += $(uses-callbacks) + CFLAGS-scandir64.c += $(uses-callbacks) diff --git a/SOURCES/glibc-RHEL-56542-5.patch b/SOURCES/glibc-RHEL-56542-5.patch new file mode 100644 index 0000000..3c21fe0 --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-5.patch @@ -0,0 +1,48 @@ +commit 61f2c2e1d1287a791c22d86c943b44bcf66bb8ad +Author: Florian Weimer +Date: Fri Aug 30 21:52:23 2024 +0200 + + Linux: readdir_r needs to report getdents failures (bug 32124) + + Upon error, return the errno value set by the __getdents call + in __readdir_unlocked. Previously, kernel-reported errors + were ignored. + + Reviewed-by: DJ Delorie + +diff --git a/sysdeps/unix/sysv/linux/readdir_r.c b/sysdeps/unix/sysv/linux/readdir_r.c +index 4792d730eb2c1fa1..2a2491e5e3786746 100644 +--- a/sysdeps/unix/sysv/linux/readdir_r.c ++++ b/sysdeps/unix/sysv/linux/readdir_r.c +@@ -25,14 +25,22 @@ __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result) + { + struct dirent *dp; + size_t reclen; ++ int saved_errno = errno; + + __libc_lock_lock (dirp->lock); + + while (1) + { ++ /* If errno is changed from 0, the NULL return value indicates ++ an actual error. It overrides a pending ENAMETOOLONG error. */ ++ __set_errno (0); + dp = __readdir_unlocked (dirp); + if (dp == NULL) +- break; ++ { ++ if (errno != 0) ++ dirp->errcode = errno; ++ break; ++ } + + reclen = dp->d_reclen; + if (reclen <= offsetof (struct dirent, d_name) + NAME_MAX + 1) +@@ -61,6 +69,7 @@ __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result) + + __libc_lock_unlock (dirp->lock); + ++ __set_errno (saved_errno); + return dp != NULL ? 0 : dirp->errcode; + } + diff --git a/SOURCES/glibc-RHEL-56542-6.patch b/SOURCES/glibc-RHEL-56542-6.patch new file mode 100644 index 0000000..d2c7e9f --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-6.patch @@ -0,0 +1,136 @@ +commit 4c09aa31b1aeea1329674109eb02d4ba506b0ad2 +Author: Florian Weimer +Date: Sat Sep 21 19:32:34 2024 +0200 + + dirent: Add tst-closedir-leaks + + It verfies that closedir deallocates memory and closes + file descriptors. + + Reviewed-by: DJ Delorie + +diff --git a/dirent/Makefile b/dirent/Makefile +index 450bcd5d8981f40b..a0404b82b81ed9e8 100644 +--- a/dirent/Makefile ++++ b/dirent/Makefile +@@ -58,6 +58,7 @@ tests := \ + bug-readdir1 \ + list \ + opendir-tst1 \ ++ tst-closedir-leaks \ + tst-fdopendir \ + tst-fdopendir2 \ + tst-rewinddir \ +@@ -66,6 +67,18 @@ tests := \ + tst-seekdir \ + # tests + ++ifeq ($(run-built-tests),yes) ++ifneq ($(PERL),no) ++generated += \ ++ $(objpfx)tst-closedir-leaks-mem.out \ ++ # generated ++ ++tests-special += \ ++ $(objpfx)tst-closedir-leaks-mem.out \ ++ # tests-special ++endif # $(PERL) ! no ++endif # $(run-built-tests) == yes ++ + CFLAGS-scandir.c += $(uses-callbacks) + CFLAGS-scandir64.c += $(uses-callbacks) + CFLAGS-scandir-tail.c += $(uses-callbacks) +@@ -74,3 +87,10 @@ CFLAGS-scandir64-tail.c += $(uses-callbacks) + include ../Rules + + opendir-tst1-ARGS = --test-dir=${common-objpfx}dirent ++ ++tst-closedir-leaks-ENV += MALLOC_TRACE=$(objpfx)tst-closedir-leaks.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++ ++$(objpfx)tst-closedir-leaks-mem.out: $(objpfx)tst-closedir-leaks.out ++ $(common-objpfx)malloc/mtrace $(objpfx)tst-closedir-leaks.mtrace > $@; \ ++ $(evaluate-test) +diff --git a/dirent/tst-closedir-leaks.c b/dirent/tst-closedir-leaks.c +new file mode 100644 +index 0000000000000000..d9de119b637ea623 +--- /dev/null ++++ b/dirent/tst-closedir-leaks.c +@@ -0,0 +1,77 @@ ++/* Test for resource leaks in 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++one_test (enum support_readdir_op op, unsigned int read_limit, ++ bool use_fdopendir) ++{ ++ struct support_descriptors *fds = support_descriptors_list (); ++ struct support_dirent e = { 0, }; ++ ++ DIR *stream; ++ if (use_fdopendir) ++ { ++ int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0); ++ stream = xfdopendir (fd); ++ /* The descriptor fd will be closed by closedir below. */ ++ } ++ else ++ stream = xopendir ("."); ++ for (unsigned int i = 0; i < read_limit; ++i) ++ if (!support_readdir (stream, op, &e)) ++ break; ++ TEST_COMPARE (closedir (stream), 0); ++ ++ free (e.d_name); ++ support_descriptors_check (fds); ++ support_descriptors_free (fds); ++} ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ ++ for (int use_fdopendir = 0; use_fdopendir < 2; ++use_fdopendir) ++ { ++ /* No reads, operation does not matter. */ ++ one_test (SUPPORT_READDIR, 0, use_fdopendir); ++ ++ for (enum support_readdir_op op = 0; op <= support_readdir_op_last(); ++ ++op) ++ { ++ one_test (op, 1, use_fdopendir); ++ one_test (op, UINT_MAX, use_fdopendir); /* Unlimited reads. */ ++ } ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-56542-7.patch b/SOURCES/glibc-RHEL-56542-7.patch new file mode 100644 index 0000000..fffcfc6 --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-7.patch @@ -0,0 +1,389 @@ +commit e92718552e1d17b8eccbffb88bf5bbb2235c4596 +Author: Florian Weimer +Date: Sat Sep 21 19:32:34 2024 +0200 + + Linux: Use readdir64_r for compat __old_readdir64_r (bug 32128) + + It is not necessary to do the conversion at the getdents64 + layer for readdir64_r. Doing it piecewise for readdir64 + is slightly simpler and allows deleting __old_getdents64. + + This fixes bug 32128 because readdir64_r handles the length + check correctly. + + Reviewed-by: DJ Delorie + +diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c +index 6323e003b30ae0e6..6f8e9147fbfb79bc 100644 +--- a/sysdeps/unix/sysv/linux/getdents64.c ++++ b/sysdeps/unix/sysv/linux/getdents64.c +@@ -33,100 +33,3 @@ __getdents64 (int fd, void *buf, size_t nbytes) + } + libc_hidden_def (__getdents64) + weak_alias (__getdents64, getdents64) +- +-#if _DIRENT_MATCHES_DIRENT64 +-strong_alias (__getdents64, __getdents) +-#else +-# include +- +-# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) +-# include +-# include +- +-static ssize_t +-handle_overflow (int fd, __off64_t offset, ssize_t count) +-{ +- /* If this is the first entry in the buffer, we can report the +- error. */ +- if (offset == 0) +- { +- __set_errno (EOVERFLOW); +- return -1; +- } +- +- /* Otherwise, seek to the overflowing entry, so that the next call +- will report the error, and return the data read so far. */ +- if (__lseek64 (fd, offset, SEEK_SET) != 0) +- return -1; +- return count; +-} +- +-ssize_t +-__old_getdents64 (int fd, char *buf, size_t nbytes) +-{ +- /* We do not move the individual directory entries. This is only +- possible if the target type (struct __old_dirent64) is smaller +- than the source type. */ +- _Static_assert (offsetof (struct __old_dirent64, d_name) +- <= offsetof (struct dirent64, d_name), +- "__old_dirent64 is larger than dirent64"); +- _Static_assert (__alignof__ (struct __old_dirent64) +- <= __alignof__ (struct dirent64), +- "alignment of __old_dirent64 is larger than dirent64"); +- +- ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); +- if (retval > 0) +- { +- /* This is the marker for the first entry. Offset 0 is reserved +- for the first entry (see rewinddir). Here, we use it as a +- marker for the first entry in the buffer. We never actually +- seek to offset 0 because handle_overflow reports the error +- directly, so it does not matter that the offset is incorrect +- if entries have been read from the descriptor before (so that +- the descriptor is not actually at offset 0). */ +- __off64_t previous_offset = 0; +- +- char *p = buf; +- char *end = buf + retval; +- while (p < end) +- { +- struct dirent64 *source = (struct dirent64 *) p; +- +- /* Copy out the fixed-size data. */ +- __ino_t ino = source->d_ino; +- __off64_t offset = source->d_off; +- unsigned int reclen = source->d_reclen; +- unsigned char type = source->d_type; +- +- /* Check for ino_t overflow. */ +- if (__glibc_unlikely (ino != source->d_ino)) +- return handle_overflow (fd, previous_offset, p - buf); +- +- /* Convert to the target layout. Use a separate struct and +- memcpy to side-step aliasing issues. */ +- struct __old_dirent64 result; +- result.d_ino = ino; +- result.d_off = offset; +- result.d_reclen = reclen; +- result.d_type = type; +- +- /* Write the fixed-sized part of the result to the +- buffer. */ +- size_t result_name_offset = offsetof (struct __old_dirent64, d_name); +- memcpy (p, &result, result_name_offset); +- +- /* Adjust the position of the name if necessary. Copy +- everything until the end of the record, including the +- terminating NUL byte. */ +- if (result_name_offset != offsetof (struct dirent64, d_name)) +- memmove (p + result_name_offset, source->d_name, +- reclen - offsetof (struct dirent64, d_name)); +- +- p += reclen; +- previous_offset = offset; +- } +- } +- return retval; +-} +-# endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */ +-#endif /* _DIRENT_MATCHES_DIRENT64 */ +diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h +index 3e672d47f5a5e421..d1a486e855e744c3 100644 +--- a/sysdeps/unix/sysv/linux/olddirent.h ++++ b/sysdeps/unix/sysv/linux/olddirent.h +@@ -34,8 +34,6 @@ extern struct __old_dirent64 *__old_readdir64 (DIR *__dirp); + libc_hidden_proto (__old_readdir64); + extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, + struct __old_dirent64 **__result); +-extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) +- attribute_hidden; + int __old_scandir64 (const char * __dir, + struct __old_dirent64 *** __namelist, + int (*__selector) (const struct __old_dirent64 *), +diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c +index 8a60504649aa54a2..c3450b083b6b64cf 100644 +--- a/sysdeps/unix/sysv/linux/readdir64.c ++++ b/sysdeps/unix/sysv/linux/readdir64.c +@@ -26,17 +26,13 @@ + #undef __readdir + #undef readdir + +-/* Read a directory entry from DIRP. */ +-struct dirent64 * +-__readdir64 (DIR *dirp) ++/* Read a directory entry from DIRP. No locking. */ ++static struct dirent64 * ++__readdir64_unlocked (DIR *dirp) + { + struct dirent64 *dp; + int saved_errno = errno; + +-#if IS_IN (libc) +- __libc_lock_lock (dirp->lock); +-#endif +- + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ +@@ -53,9 +49,6 @@ __readdir64 (DIR *dirp) + do not set errno in that case, to indicate success. */ + if (bytes == 0 || errno == ENOENT) + __set_errno (saved_errno); +-#if IS_IN (libc) +- __libc_lock_unlock (dirp->lock); +-#endif + return NULL; + } + dirp->size = (size_t) bytes; +@@ -68,10 +61,16 @@ __readdir64 (DIR *dirp) + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; + +-#if IS_IN (libc) +- __libc_lock_unlock (dirp->lock); +-#endif ++ return dp; ++} + ++/* Read a directory entry from DIRP. */ ++struct dirent64 * ++__readdir64 (DIR *dirp) ++{ ++ __libc_lock_lock (dirp->lock); ++ struct dirent64 *dp = __readdir64_unlocked (dirp); ++ __libc_lock_unlock (dirp->lock); + return dp; + } + libc_hidden_def (__readdir64) +@@ -99,45 +98,54 @@ __old_readdir64 (DIR *dirp) + struct __old_dirent64 *dp; + int saved_errno = errno; + +-#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +-#endif + +- if (dirp->offset >= dirp->size) ++ while (1) + { +- /* We've emptied out our buffer. Refill it. */ ++ errno = 0; ++ struct dirent64 *newdp = __readdir64_unlocked (dirp); ++ if (newdp == NULL) ++ { ++ if (errno == 0 && dirp->errcode != 0) ++ __set_errno (dirp->errcode); ++ else if (errno == 0) ++ __set_errno (saved_errno); ++ dp = NULL; ++ break; ++ } + +- size_t maxread = dirp->allocation; +- ssize_t bytes; ++ /* Convert to the target layout. Use a separate struct and ++ memcpy to side-step aliasing issues. */ ++ struct __old_dirent64 result; ++ result.d_ino = newdp->d_ino; ++ result.d_off = newdp->d_off; ++ result.d_reclen = newdp->d_reclen; ++ result.d_type = newdp->d_type; + +- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); +- if (bytes <= 0) ++ /* Check for ino_t overflow. */ ++ if (__glibc_unlikely (result.d_ino != newdp->d_ino)) + { +- /* Linux may fail with ENOENT on some file systems if the +- directory inode is marked as dead (deleted). POSIX +- treats this as a regular end-of-directory condition, so +- do not set errno in that case, to indicate success. */ +- if (bytes == 0 || errno == ENOENT) +- __set_errno (saved_errno); +-#if IS_IN (libc) +- __libc_lock_unlock (dirp->lock); +-#endif +- return NULL; ++ dirp->errcode = ENAMETOOLONG; ++ continue; + } +- dirp->size = (size_t) bytes; + +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; +- } ++ /* Overwrite the fixed-sized part. */ ++ dp = (struct __old_dirent64 *) newdp; ++ memcpy (dp, &result, offsetof (struct __old_dirent64, d_name)); + +- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; +- dirp->offset += dp->d_reclen; +- dirp->filepos = dp->d_off; ++ /* Move the name. */ ++ _Static_assert (offsetof (struct __old_dirent64, d_name) ++ <= offsetof (struct dirent64, d_name), ++ "old struct must be smaller"); ++ if (offsetof (struct __old_dirent64, d_name) ++ != offsetof (struct dirent64, d_name)) ++ memmove (dp->d_name, newdp->d_name, strlen (newdp->d_name) + 1); + +-#if IS_IN (libc) +- __libc_lock_unlock (dirp->lock); +-#endif ++ __set_errno (saved_errno); ++ break; ++ } + ++ __libc_lock_unlock (dirp->lock); + return dp; + } + libc_hidden_def (__old_readdir64) +diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c +index 073a6453d1bbbd61..0c60987343b1f37f 100644 +--- a/sysdeps/unix/sysv/linux/readdir64_r.c ++++ b/sysdeps/unix/sysv/linux/readdir64_r.c +@@ -135,91 +135,37 @@ attribute_compat_text_section + __old_readdir64_r (DIR *dirp, struct __old_dirent64 *entry, + struct __old_dirent64 **result) + { +- struct __old_dirent64 *dp; +- size_t reclen; +- const int saved_errno = errno; +- int ret; +- +- __libc_lock_lock (dirp->lock); +- +- do ++ while (1) + { +- if (dirp->offset >= dirp->size) +- { +- /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- maxread = dirp->allocation; +- +- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); +- if (bytes <= 0) +- { +- /* On some systems getdents fails with ENOENT when the +- open directory has been rmdir'd already. POSIX.1 +- requires that we treat this condition like normal EOF. */ +- if (bytes < 0 && errno == ENOENT) +- { +- bytes = 0; +- __set_errno (saved_errno); +- } +- if (bytes < 0) +- dirp->errcode = errno; ++ struct dirent64 new_entry; ++ struct dirent64 *newp; ++ int ret = __readdir64_r (dirp, &new_entry, &newp); + +- dp = NULL; +- break; +- } +- dirp->size = (size_t) bytes; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; ++ if (ret != 0) ++ return ret; ++ else if (newp == NULL) ++ { ++ *result = NULL; ++ return 0; + } +- +- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; +- +- reclen = dp->d_reclen; +- +- dirp->offset += reclen; +- +- dirp->filepos = dp->d_off; +- +- if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) ++ else + { +- /* The record is very long. It could still fit into the +- caller-supplied buffer if we can skip padding at the +- end. */ +- size_t namelen = _D_EXACT_NAMLEN (dp); +- if (namelen <= NAME_MAX) +- reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1; +- else ++ entry->d_ino = newp->d_ino; ++ if (entry->d_ino != newp->d_ino) + { +- /* The name is too long. Ignore this file. */ +- dirp->errcode = ENAMETOOLONG; +- dp->d_ino = 0; ++ dirp->errcode = EOVERFLOW; + continue; + } ++ size_t namelen = strlen (newp->d_name); ++ entry->d_off = newp->d_off; ++ entry->d_reclen = (offsetof (struct __old_dirent64, d_name) ++ + namelen + 1); ++ entry->d_type = newp->d_type; ++ memcpy (entry->d_name, newp->d_name, namelen + 1); ++ *result = entry; ++ return 0; + } +- +- /* Skip deleted and ignored files. */ +- } +- while (dp->d_ino == 0); +- +- if (dp != NULL) +- { +- *result = memcpy (entry, dp, reclen); +- entry->d_reclen = reclen; +- ret = 0; + } +- else +- { +- *result = NULL; +- ret = dirp->errcode; +- } +- +- __libc_lock_unlock (dirp->lock); +- +- return ret; + } + + compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); diff --git a/SOURCES/glibc-RHEL-56542-8.patch b/SOURCES/glibc-RHEL-56542-8.patch new file mode 100644 index 0000000..cc4f908 --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-8.patch @@ -0,0 +1,264 @@ +commit 4ec355af454695556db1212d1c9ca9c3789cddf4 +Author: Florian Weimer +Date: Sat Sep 21 19:32:34 2024 +0200 + + dirent: Add tst-readdir-long + + It tests long names and ENAMETOOLONG handling, specifically + for readdir_r. This is a regression test for bug 14699, + bug 32124, and bug 32128. + + Reviewed-by: DJ Delorie + +Conflicts: + dirent/Makefile (fixup context) + +diff --git a/dirent/Makefile b/dirent/Makefile +index a0404b82b81ed9e8..d12be2f0384b184f 100644 +--- a/dirent/Makefile ++++ b/dirent/Makefile +@@ -61,6 +61,7 @@ tests := \ + tst-closedir-leaks \ + tst-fdopendir \ + tst-fdopendir2 \ ++ tst-readdir-long \ + tst-rewinddir \ + tst-scandir \ + tst-scandir64 \ +diff --git a/dirent/tst-readdir-long.c b/dirent/tst-readdir-long.c +new file mode 100644 +index 0000000000000000..409318fa52fc664f +--- /dev/null ++++ b/dirent/tst-readdir-long.c +@@ -0,0 +1,231 @@ ++/* Test readdir (+variants) behavior with file names of varying length. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* If positive, at this length an EMSGSIZE error is injected. */ ++static _Atomic int inject_error_at_length; ++ ++/* Return a file name, LENGTH bytes long. */ ++static char * ++name_of_length (size_t length) ++{ ++ char *result = xmalloc (length + 1); ++ unsigned int prefix = snprintf (result, length + 1, "%zu-", length); ++ for (size_t i = prefix; i < length; ++i) ++ result[i] = 'A' + ((length + i) % 26); ++ result[length] = '\0'; ++ return result; ++} ++ ++/* Add the directory entry at OFFSET to the stream D. */ ++static uint64_t ++add_directory_entry (struct support_fuse_dirstream *d, uint64_t offset) ++{ ++ unsigned int length = offset + 1; ++ if (length > 1000) ++ /* Longer than what is possible to produce with 256 ++ UTF-8-encoded Unicode code points. */ ++ return 0; ++ ++ char *to_free = NULL; ++ const char *name; ++ uint64_t ino = 1000 + length; /* Arbitrary value, distinct from 1. */ ++ uint32_t type = DT_REG; ++ if (offset <= 1) ++ { ++ type = DT_DIR; ++ name = ".." + !offset; /* "." or "..". */ ++ ino = 1; ++ } ++ else if (length == 1000) ++ name = "short"; ++ else ++ { ++ to_free = name_of_length (length); ++ name = to_free; ++ } ++ ++ ++offset; ++ bool added = support_fuse_dirstream_add (d, ino, offset, type, name); ++ free (to_free); ++ if (added) ++ return offset; ++ else ++ return 0; ++} ++ ++/* Set to true if getdents64 should produce only one entry. */ ++static _Atomic bool one_entry_per_getdents64; ++ ++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_READDIR: ++ if (inh->nodeid == 1) ++ { ++ uint64_t offset = support_fuse_cast (READ, inh)->offset; ++ if (inject_error_at_length == offset + 1) ++ support_fuse_reply_error (f, EMSGSIZE); ++ else ++ { ++ struct support_fuse_dirstream *d ++ = support_fuse_prepare_readdir (f); ++ while (true) ++ { ++ offset = add_directory_entry (d, offset); ++ if (offset == 0 || one_entry_per_getdents64 ++ /* Error will be reported at next READDIR. */ ++ || offset + 1 == inject_error_at_length) ++ break; ++ } ++ support_fuse_reply_prepared (f); ++ } ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ default: ++ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode)); ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++/* Run the tests for the specified readdir variant OP. */ ++static void ++run_readdir_tests (struct support_fuse *f, enum support_readdir_op op) ++{ ++ printf ("info: testing %s (inject_error=%d unbuffered=%d)\n", ++ support_readdir_function (op), inject_error_at_length, ++ (int) one_entry_per_getdents64); ++ ++ bool testing_r = support_readdir_r_variant (op); ++ ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ struct support_dirent e = { 0, }; ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE (e.d_ino, 1); ++ TEST_COMPARE_STRING (e.d_name, "."); ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE (e.d_ino, 1); ++ TEST_COMPARE_STRING (e.d_name, ".."); ++ ++ for (unsigned int i = 3; i < 1000; ++i) ++ { ++ if (i == inject_error_at_length) ++ /* Error expected below. */ ++ break; ++ ++ if (i >= sizeof ((struct dirent) { 0, }.d_name) && testing_r) ++ /* This is a readir_r test. The longer names are not ++ available because they do not fit into struct dirent. */ ++ break; ++ ++ char *expected_name = name_of_length (i); ++ TEST_COMPARE (strlen (expected_name), i); ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE (e.d_ino, 1000 + i); ++ TEST_COMPARE_STRING (e.d_name, expected_name); ++ free (expected_name); ++ } ++ ++ if (inject_error_at_length == 0) ++ { ++ /* Check that the ENAMETOOLONG error does not prevent reading a ++ later short name. */ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE (e.d_ino, 2000); ++ TEST_COMPARE_STRING (e.d_name, "short"); ++ ++ if (testing_r) ++ /* An earlier name was too long. */ ++ support_readdir_expect_error (dir, op, ENAMETOOLONG); ++ else ++ /* Entire directory read without error. */ ++ TEST_VERIFY (!support_readdir (dir, op, &e)); ++ } ++ else ++ support_readdir_expect_error (dir, op, EMSGSIZE); ++ ++ free (e.d_name); ++ xclosedir (dir); ++} ++ ++/* Run all readdir variants for both fully-buffered an unbuffered ++ (one-at-a-time) directory streams. */ ++static void ++run_fully_buffered_and_singleton_buffers (struct support_fuse *f) ++{ ++ for (int do_one_entry = 0; do_one_entry < 2; ++do_one_entry) ++ { ++ one_entry_per_getdents64 = do_one_entry; ++ for (enum support_readdir_op op = 0; op <= support_readdir_op_last(); ++ ++op) ++ run_readdir_tests (f, op); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* Smoke test for name_of_length. */ ++ { ++ char *name = name_of_length (5); ++ TEST_COMPARE_STRING (name, "5-HIJ"); ++ free (name); ++ ++ name = name_of_length (6); ++ TEST_COMPARE_STRING (name, "6-IJKL"); ++ free (name); ++ } ++ ++ support_fuse_init (); ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ ++ run_fully_buffered_and_singleton_buffers (f); ++ ++ inject_error_at_length = 100; ++ run_fully_buffered_and_singleton_buffers (f); ++ ++ inject_error_at_length = 300; ++ run_fully_buffered_and_singleton_buffers (f); ++ ++ support_fuse_unmount (f); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-56542-9.patch b/SOURCES/glibc-RHEL-56542-9.patch new file mode 100644 index 0000000..4c41176 --- /dev/null +++ b/SOURCES/glibc-RHEL-56542-9.patch @@ -0,0 +1,214 @@ +commit 6f3f6c506cdaf981a4374f1f12863b98ac7fea1a +Author: Florian Weimer +Date: Sat Sep 21 19:32:34 2024 +0200 + + Linux: readdir64_r should not skip d_ino == 0 entries (bug 32126) + + This is the same bug as bug 12165, but for readdir_r. The + regression test covers both bug 12165 and bug 32126. + + Reviewed-by: DJ Delorie + +diff --git a/dirent/Makefile b/dirent/Makefile +index d12be2f0384b184f..4cecd169b42c540b 100644 +--- a/dirent/Makefile ++++ b/dirent/Makefile +@@ -62,6 +62,7 @@ tests := \ + tst-fdopendir \ + tst-fdopendir2 \ + tst-readdir-long \ ++ tst-readdir-zero-inode \ + tst-rewinddir \ + tst-scandir \ + tst-scandir64 \ +diff --git a/dirent/tst-readdir-zero-inode.c b/dirent/tst-readdir-zero-inode.c +new file mode 100644 +index 0000000000000000..af9fb946abe6c483 +--- /dev/null ++++ b/dirent/tst-readdir-zero-inode.c +@@ -0,0 +1,134 @@ ++/* Test that readdir does not skip entries with d_ino == 0 (bug 12165). ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Add the directory entry at OFFSET to the stream D. */ ++static uint64_t ++add_directory_entry (struct support_fuse_dirstream *d, uint64_t offset) ++{ ++ bool added = false; ++ ++offset; ++ switch (offset - 1) ++ { ++ case 0: ++ added = support_fuse_dirstream_add (d, 1, offset, DT_DIR, "."); ++ break; ++ case 1: ++ added = support_fuse_dirstream_add (d, 1, offset, DT_DIR, ".."); ++ break; ++ case 2: ++ added = support_fuse_dirstream_add (d, 2, offset, DT_REG, "before"); ++ break; ++ case 3: ++ added = support_fuse_dirstream_add (d, 0, offset, DT_REG, "zero"); ++ break; ++ case 4: ++ added = support_fuse_dirstream_add (d, 3, offset, DT_REG, "after"); ++ break; ++ } ++ if (added) ++ return offset; ++ else ++ return 0; ++} ++ ++/* Set to true if getdents64 should produce only one entry. */ ++static bool one_entry_per_getdents64; ++ ++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_READDIR: ++ if (inh->nodeid == 1) ++ { ++ uint64_t offset = support_fuse_cast (READ, inh)->offset; ++ struct support_fuse_dirstream *d ++ = support_fuse_prepare_readdir (f); ++ while (true) ++ { ++ offset = add_directory_entry (d, offset); ++ if (offset == 0 || one_entry_per_getdents64) ++ break; ++ } ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ default: ++ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode)); ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ for (enum support_readdir_op op = 0; op <= support_readdir_op_last (); ++op) ++ { ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ struct support_dirent e = { 0, }; ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "."); ++ TEST_COMPARE (e.d_ino, 1); ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, ".."); ++ TEST_COMPARE (e.d_ino, 1); ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "before"); ++ TEST_COMPARE (e.d_ino, 2); ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "zero"); ++ TEST_COMPARE (e.d_ino, 0); ++ ++ TEST_VERIFY (support_readdir (dir, op, &e)); ++ TEST_COMPARE_STRING (e.d_name, "after"); ++ TEST_COMPARE (e.d_ino, 3); ++ ++ TEST_VERIFY (!support_readdir (dir, op, &e)); ++ ++ free (e.d_name); ++ xclosedir (dir); ++ support_fuse_unmount (f); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c +index 0c60987343b1f37f..2e188364ff5aa143 100644 +--- a/sysdeps/unix/sysv/linux/readdir64_r.c ++++ b/sysdeps/unix/sysv/linux/readdir64_r.c +@@ -37,7 +37,7 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result) + + __libc_lock_lock (dirp->lock); + +- do ++ while (1) + { + if (dirp->offset >= dirp->size) + { +@@ -79,26 +79,21 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result) + + dirp->filepos = dp->d_off; + +- if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1) ++ if (reclen <= offsetof (struct dirent64, d_name) + NAME_MAX + 1) ++ break; ++ ++ /* The record is very long. It could still fit into the ++ caller-supplied buffer if we can skip padding at the end. */ ++ size_t namelen = _D_EXACT_NAMLEN (dp); ++ if (namelen <= NAME_MAX) + { +- /* The record is very long. It could still fit into the +- caller-supplied buffer if we can skip padding at the +- end. */ +- size_t namelen = _D_EXACT_NAMLEN (dp); +- if (namelen <= NAME_MAX) +- reclen = offsetof (struct dirent64, d_name) + namelen + 1; +- else +- { +- /* The name is too long. Ignore this file. */ +- dirp->errcode = ENAMETOOLONG; +- dp->d_ino = 0; +- continue; +- } ++ reclen = offsetof (struct dirent64, d_name) + namelen + 1; ++ break; + } + +- /* Skip deleted and ignored files. */ ++ /* The name is too long. Ignore this file. */ ++ dirp->errcode = ENAMETOOLONG; + } +- while (dp->d_ino == 0); + + if (dp != NULL) + { diff --git a/SOURCES/glibc-RHEL-56743.patch b/SOURCES/glibc-RHEL-56743.patch new file mode 100644 index 0000000..e7b1bda --- /dev/null +++ b/SOURCES/glibc-RHEL-56743.patch @@ -0,0 +1,79 @@ +commit 55cd51d971b84fbb2cc0fe8140cc8581f98582c7 +Author: Joseph Myers +Date: Thu Aug 22 11:25:14 2024 +0000 + + Test mkdirat use of mode argument + + The test io/tst-mkdirat doesn't verify the permissions on the created + directory (thus, doesn't verify at all anything about how mkdirat uses + the mode argument). Add checks of this to the existing test. + + Tested for x86_64. + +diff --git a/io/tst-mkdirat.c b/io/tst-mkdirat.c +index 605e51ef1e966b42..b97bc3ca6d0cdf23 100644 +--- a/io/tst-mkdirat.c ++++ b/io/tst-mkdirat.c +@@ -53,6 +53,10 @@ prepare (void) + static int + do_test (void) + { ++ /* Find the current umask. */ ++ mode_t mask = umask (022); ++ umask (mask); ++ + /* fdopendir takes over the descriptor, make a copy. */ + int dupfd = dup (dir_fd); + if (dupfd == -1) +@@ -107,6 +111,13 @@ do_test (void) + puts ("mkdirat did not create a directory"); + return 1; + } ++ if ((st1.st_mode & 01777) != (~mask & 0777)) ++ { ++ printf ("mkdirat created directory with wrong mode %o, expected %o\n", ++ (unsigned int) (st1.st_mode & 01777), ++ (unsigned int) (~mask & 0777)); ++ return 1; ++ } + + dupfd = dup (dir_fd); + if (dupfd == -1) +@@ -156,6 +167,37 @@ do_test (void) + return 1; + } + ++ /* Test again with a different mode. */ ++ umask (0); ++ e = mkdirat (dir_fd, "some-dir", 01755); ++ umask (mask); ++ if (e == -1) ++ { ++ puts ("directory creation (different mode) failed"); ++ return 1; ++ } ++ if (fstatat64 (dir_fd, "some-dir", &st1, 0) != 0) ++ { ++ puts ("fstat64 (different mode) failed"); ++ return 1; ++ } ++ if (!S_ISDIR (st1.st_mode)) ++ { ++ puts ("mkdirat (different mode) did not create a directory"); ++ return 1; ++ } ++ if ((st1.st_mode & 01777) != 01755) ++ { ++ printf ("mkdirat (different mode) created directory with wrong mode %o\n", ++ (unsigned int) (st1.st_mode & 01777)); ++ return 1; ++ } ++ if (unlinkat (dir_fd, "some-dir", AT_REMOVEDIR) != 0) ++ { ++ puts ("unlinkat (different mode) failed"); ++ return 1; ++ } ++ + close (dir_fd); + + return 0; diff --git a/SOURCES/glibc-RHEL-57586.patch b/SOURCES/glibc-RHEL-57586.patch new file mode 100644 index 0000000..259060a --- /dev/null +++ b/SOURCES/glibc-RHEL-57586.patch @@ -0,0 +1,36 @@ +commit 6efd6cd46bf2257e674be4933a034542d80944eb +Author: Florian Weimer +Date: Fri Sep 6 14:07:00 2024 +0200 + + manual: Safety annotations for clock_gettime, clock_getres + + The annotations are preliminary, for consistency with existing + annotations on gettimeofday etc. + + Reviewed-by: Carlos O'Donell + +Conflicts: + manual/time.texi (fixing typo in context) + +diff --git a/manual/time.texi b/manual/time.texi +index 0c7a942b4c16946a..404d124d1bfdca5c 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -503,7 +503,8 @@ Systems may support more than just these two clocks. + + @deftypefun int clock_gettime (clockid_t @var{clock}, struct timespec *@var{ts}) + @standards{POSIX.1, time.h} +-Get the current time accoding to the clock identified by @var{clock}, ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++Get the current time according to the clock identified by @var{clock}, + storing it as seconds and nanoseconds in @code{*@var{ts}}. + @xref{Time Types}, for a description of @code{struct timespec}. + +@@ -524,6 +525,7 @@ clock: + + @deftypefun int clock_getres (clockid_t @var{clock}, struct timespec *@var{res}) + @standards{POSIX.1, time.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + Get the actual resolution of the clock identified by @var{clock}, + storing it in @code{*@var{ts}}. + diff --git a/SOURCES/glibc-RHEL-58671.patch b/SOURCES/glibc-RHEL-58671.patch new file mode 100644 index 0000000..a991ece --- /dev/null +++ b/SOURCES/glibc-RHEL-58671.patch @@ -0,0 +1,90 @@ +commit 83fd4149ffdae86c8864a6828f39dd942956636f +Author: Aaron Merey +Date: Thu Sep 19 11:11:39 2024 -0400 + + Test that errno is set to 0 at program startup + + Add new testcase elf/tst-startup-errno.c which tests that errno is set + to 0 at first ELF constructor execution and at the start of the + program's main function. + + Tested for x86_64 + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/Makefile b/elf/Makefile +index ffadf1c61f66bef8..ff59287519433b8d 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -434,6 +434,7 @@ tests += \ + tst-single_threaded-pthread \ + tst-sonamemove-dlopen \ + tst-sonamemove-link \ ++ tst-startup-errno \ + tst-thrlock \ + tst-tls10 \ + tst-tls11 \ +diff --git a/elf/tst-startup-errno.c b/elf/tst-startup-errno.c +new file mode 100644 +index 0000000000000000..59a1005fb674a5c3 +--- /dev/null ++++ b/elf/tst-startup-errno.c +@@ -0,0 +1,58 @@ ++/* Test the value of errno at program startup. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Verify that errno is 0 at first ELF constructor execution and at ++ the start of main. */ ++ ++static void set_ctor_errno (void) __attribute__((constructor)); ++static int ctor_errno = -1; ++ ++static void ++set_ctor_errno (void) ++{ ++ ctor_errno = errno; ++} ++ ++static int ++get_ctor_errno (void) ++{ ++ return ctor_errno; ++} ++ ++int ++main (void) ++{ ++ if (errno != 0) ++ { ++ printf ("At start of main errno set to %d != 0\n", errno); ++ exit (1); ++ } ++ ++ if (get_ctor_errno () != 0) ++ { ++ printf ("At ctor exec errno set to %d != 0\n", get_ctor_errno ()); ++ exit (1); ++ } ++ ++ return 0; ++} ++ diff --git a/SOURCES/glibc-RHEL-58979.patch b/SOURCES/glibc-RHEL-58979.patch new file mode 100644 index 0000000..37cf6a3 --- /dev/null +++ b/SOURCES/glibc-RHEL-58979.patch @@ -0,0 +1,1527 @@ +commit 6ae9836ed24e4dc625b452a1472f1c150f3058cf +Author: Joseph Myers +Date: Fri Nov 29 16:43:56 2024 +0000 + + Add test of ELF hash collisions + + Add tests that the dynamic linker works correctly with symbol names + involving hash collisions, for both choices of hash style (and + --hash-style=both as well). I note that there weren't actually any + previous tests using --hash-style (so tests would only cover the + default linker configuration in that regard). Also test symbol + versions involving hash collisions. + + Tested for x86_64. + +Conflicts: + elf/Makefile (fixup context) + +diff --git a/elf/Makefile b/elf/Makefile +index ff59287519433b8d..7d686ca7d190c921 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -414,6 +414,12 @@ tests += \ + tst-glibc-hwcaps-mask \ + tst-glibc-hwcaps-prepend \ + tst-global1 \ ++ tst-hash-collision1 \ ++ tst-hash-collision1-gnu \ ++ tst-hash-collision1-sysv \ ++ tst-hash-collision2 \ ++ tst-hash-collision2-gnu \ ++ tst-hash-collision2-sysv \ + tst-initfinilazyfail \ + tst-initorder \ + tst-initorder2 \ +@@ -488,6 +494,7 @@ tests-internal += \ + tst-create_format1 \ + tst-dl-hwcaps_split \ + tst-dlmopen2 \ ++ tst-hash-collision3 \ + tst-ptrguard1 \ + tst-stackguard1 \ + tst-tls-surplus \ +@@ -770,6 +777,16 @@ modules-names = \ + tst-filterobj-filtee \ + tst-filterobj-flt \ + tst-finilazyfailmod \ ++ tst-hash-collision1-mod \ ++ tst-hash-collision1-mod-gnu \ ++ tst-hash-collision1-mod-sysv \ ++ tst-hash-collision2-mod1 \ ++ tst-hash-collision2-mod1-gnu \ ++ tst-hash-collision2-mod1-sysv \ ++ tst-hash-collision2-mod2 \ ++ tst-hash-collision2-mod2-gnu \ ++ tst-hash-collision2-mod2-sysv \ ++ tst-hash-collision3-mod \ + tst-initlazyfailmod \ + tst-initorder2a \ + tst-initorder2b \ +@@ -923,7 +940,8 @@ modules-names += \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +-modules-names-tests = $(filter-out ifuncmod% tst-tlsmod%,\ ++modules-names-tests = $(filter-out ifuncmod% tst-tlsmod% \ ++ tst-hash-collision3-mod,\ + $(modules-names)) + + ifeq (yes,$(have-mtls-dialect-gnu2)) +@@ -2781,3 +2799,25 @@ $(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so + tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + $(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so + tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so ++ ++LDFLAGS-tst-hash-collision1-mod.so = -Wl,--hash-style=both ++$(objpfx)tst-hash-collision1: $(objpfx)tst-hash-collision1-mod.so ++LDFLAGS-tst-hash-collision1-mod-gnu.so = -Wl,--hash-style=gnu ++$(objpfx)tst-hash-collision1-gnu: $(objpfx)tst-hash-collision1-mod-gnu.so ++LDFLAGS-tst-hash-collision1-mod-sysv.so = -Wl,--hash-style=sysv ++$(objpfx)tst-hash-collision1-sysv: $(objpfx)tst-hash-collision1-mod-sysv.so ++LDFLAGS-tst-hash-collision2-mod1.so = -Wl,--hash-style=both ++LDFLAGS-tst-hash-collision2-mod2.so = -Wl,--hash-style=both ++$(objpfx)tst-hash-collision2: $(objpfx)tst-hash-collision2-mod1.so \ ++ $(objpfx)tst-hash-collision2-mod2.so ++LDFLAGS-tst-hash-collision2-mod1-gnu.so = -Wl,--hash-style=gnu ++LDFLAGS-tst-hash-collision2-mod2-gnu.so = -Wl,--hash-style=gnu ++$(objpfx)tst-hash-collision2-gnu: $(objpfx)tst-hash-collision2-mod1-gnu.so \ ++ $(objpfx)tst-hash-collision2-mod2-gnu.so ++LDFLAGS-tst-hash-collision2-mod1-sysv.so = -Wl,--hash-style=sysv ++LDFLAGS-tst-hash-collision2-mod2-sysv.so = -Wl,--hash-style=sysv ++$(objpfx)tst-hash-collision2-sysv: $(objpfx)tst-hash-collision2-mod1-sysv.so \ ++ $(objpfx)tst-hash-collision2-mod2-sysv.so ++LDFLAGS-tst-hash-collision3-mod.so = \ ++ -Wl,--version-script=tst-hash-collision3-mod.map ++$(objpfx)tst-hash-collision3: $(objpfx)tst-hash-collision3-mod.so +diff --git a/elf/tst-hash-collision1-gnu.c b/elf/tst-hash-collision1-gnu.c +new file mode 100644 +index 0000000000000000..92f0862e914a9dbe +--- /dev/null ++++ b/elf/tst-hash-collision1-gnu.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1.c" +diff --git a/elf/tst-hash-collision1-mod-gnu.c b/elf/tst-hash-collision1-mod-gnu.c +new file mode 100644 +index 0000000000000000..e4d03dd9bfd3520f +--- /dev/null ++++ b/elf/tst-hash-collision1-mod-gnu.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1-mod.c" +diff --git a/elf/tst-hash-collision1-mod-sysv.c b/elf/tst-hash-collision1-mod-sysv.c +new file mode 100644 +index 0000000000000000..e4d03dd9bfd3520f +--- /dev/null ++++ b/elf/tst-hash-collision1-mod-sysv.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1-mod.c" +diff --git a/elf/tst-hash-collision1-mod.c b/elf/tst-hash-collision1-mod.c +new file mode 100644 +index 0000000000000000..c848af8ae103f8ab +--- /dev/null ++++ b/elf/tst-hash-collision1-mod.c +@@ -0,0 +1,448 @@ ++/* Test ELF hash collisions: shared object. ++ 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 ++ . */ ++ ++#include ++ ++/* Names with hash collisions for classic ELF hash. */ ++ ++int ++foo (void) ++{ ++ return 1; ++} ++ ++int ++Hxxxynpfoo (void) ++{ ++ return 2; ++} ++ ++int ++HxxxynpHxxxynpfoo (void) ++{ ++ return 3; ++} ++ ++int ++HxxxynpHxxxynpHxxxynpfoo (void) ++{ ++ return 4; ++} ++ ++int ++HxxxynpHxxxynpHxxxynpHxxxynpfoo (void) ++{ ++ return 5; ++} ++ ++ ++/* Names with hash collisions for GNU hash. */ ++ ++int ++bar (void) ++{ ++ return 10; ++} ++ ++int ++gliinmbar (void) ++{ ++ return 9; ++} ++ ++int ++gliinmgliinmbar (void) ++{ ++ return 8; ++} ++ ++int ++gliinmgliinmgliinmbar (void) ++{ ++ return 7; ++} ++ ++int ++gliinmgliinmgliinmgliinmbar (void) ++{ ++ return 6; ++} ++ ++ ++/* Names with specific hash values for each hash (see ++ tst-hash-collision1.c for details). */ ++ ++int ++Hxxxynp (void) ++{ ++ return 11; ++} ++ ++int ++HxxxypP (void) ++{ ++ return 12; ++} ++ ++int ++Hxxyinp (void) ++{ ++ return 13; ++} ++ ++int ++HxxyipP (void) ++{ ++ return 14; ++} ++ ++int ++HxxykNp (void) ++{ ++ return 15; ++} ++ ++int ++Hxxxyoa (void) ++{ ++ return 16; ++} ++ ++int ++HxxxypQ (void) ++{ ++ return 17; ++} ++ ++int ++HxxxyqA (void) ++{ ++ return 18; ++} ++ ++int ++HxxxzaA (void) ++{ ++ return 19; ++} ++ ++int ++Hxxxz_a (void) ++{ ++ return 20; ++} ++ ++int ++Hxxxyob (void) ++{ ++ return 21; ++} ++ ++int ++HxxxypR (void) ++{ ++ return 22; ++} ++ ++int ++HxxxyqB (void) ++{ ++ return 23; ++} ++ ++int ++HxxxzaB (void) ++{ ++ return 24; ++} ++ ++int ++Hxxxz_b (void) ++{ ++ return 25; ++} ++ ++int ++glidpk (void) ++{ ++ return 26; ++} ++ ++int ++glidqJ (void) ++{ ++ return 27; ++} ++ ++int ++glieOk (void) ++{ ++ return 28; ++} ++ ++int ++gliePJ (void) ++{ ++ return 29; ++} ++ ++int ++gljCpk (void) ++{ ++ return 30; ++} ++ ++int ++glidpl (void) ++{ ++ return 31; ++} ++ ++int ++glidqK (void) ++{ ++ return 32; ++} ++ ++int ++glieOl (void) ++{ ++ return 33; ++} ++ ++int ++gliePK (void) ++{ ++ return 34; ++} ++ ++int ++gljCpl (void) ++{ ++ return 35; ++} ++ ++int ++glidpm (void) ++{ ++ return 36; ++} ++ ++int ++glidqL (void) ++{ ++ return 37; ++} ++ ++int ++glieOm (void) ++{ ++ return 38; ++} ++ ++int ++gliePL (void) ++{ ++ return 39; ++} ++ ++int ++gljCpm (void) ++{ ++ return 40; ++} ++ ++int ++AdfmZru (void) ++{ ++ return 41; ++} ++ ++int ++AdfmZsT (void) ++{ ++ return 42; ++} ++ ++int ++AdfmZt3 (void) ++{ ++ return 43; ++} ++ ++int ++Adfn9ru (void) ++{ ++ return 44; ++} ++ ++int ++Adfn9sT (void) ++{ ++ return 45; ++} ++ ++int ++AdfmZrv (void) ++{ ++ return 46; ++} ++ ++int ++AdfmZsU (void) ++{ ++ return 47; ++} ++ ++int ++AdfmZt4 (void) ++{ ++ return 48; ++} ++ ++int ++Adfn9rv (void) ++{ ++ return 49; ++} ++ ++int ++Adfn9sU (void) ++{ ++ return 50; ++} ++ ++int ++AdfmZrw (void) ++{ ++ return 51; ++} ++ ++int ++AdfmZsV (void) ++{ ++ return 52; ++} ++ ++int ++AdfmZt5 (void) ++{ ++ return 53; ++} ++ ++int ++Adfn9rw (void) ++{ ++ return 54; ++} ++ ++int ++Adfn9sV (void) ++{ ++ return 55; ++} ++ ++int ++AdfmZrx (void) ++{ ++ return 56; ++} ++ ++int ++AdfmZsW (void) ++{ ++ return 57; ++} ++ ++int ++AdfmZt6 (void) ++{ ++ return 58; ++} ++ ++int ++Adfn9rx (void) ++{ ++ return 59; ++} ++ ++int ++Adfn9sW (void) ++{ ++ return 60; ++} ++ ++int ++glidpi (void) ++{ ++ return 61; ++} ++ ++int ++glidqH (void) ++{ ++ return 62; ++} ++ ++int ++glieOi (void) ++{ ++ return 63; ++} ++ ++int ++gliePH (void) ++{ ++ return 64; ++} ++ ++int ++gljCpi (void) ++{ ++ return 65; ++} ++ ++int ++glidpj (void) ++{ ++ return 66; ++} ++ ++int ++glidqI (void) ++{ ++ return 67; ++} ++ ++int ++glieOj (void) ++{ ++ return 68; ++} ++ ++int ++gliePI (void) ++{ ++ return 69; ++} ++ ++int ++gljCpj (void) ++{ ++ return 70; ++} +diff --git a/elf/tst-hash-collision1-sysv.c b/elf/tst-hash-collision1-sysv.c +new file mode 100644 +index 0000000000000000..92f0862e914a9dbe +--- /dev/null ++++ b/elf/tst-hash-collision1-sysv.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1.c" +diff --git a/elf/tst-hash-collision1.c b/elf/tst-hash-collision1.c +new file mode 100644 +index 0000000000000000..80ab0da8f56ca9a3 +--- /dev/null ++++ b/elf/tst-hash-collision1.c +@@ -0,0 +1,196 @@ ++/* Test ELF hash collisions. ++ 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 ++ . */ ++ ++#include ++ ++/* Names with hash collisions for classic ELF hash. */ ++extern int foo (void); ++extern int Hxxxynpfoo (void); ++extern int HxxxynpHxxxynpfoo (void); ++extern int HxxxynpHxxxynpHxxxynpfoo (void); ++extern int HxxxynpHxxxynpHxxxynpHxxxynpfoo (void); ++ ++/* Names with hash collisions for GNU hash. */ ++extern int bar (void); ++extern int gliinmbar (void); ++extern int gliinmgliinmbar (void); ++extern int gliinmgliinmgliinmbar (void); ++extern int gliinmgliinmgliinmgliinmbar (void); ++ ++/* Classic ELF hash 0. */ ++extern int Hxxxynp (void); ++extern int HxxxypP (void); ++extern int Hxxyinp (void); ++extern int HxxyipP (void); ++extern int HxxykNp (void); ++ ++/* Classic ELF hash 1. */ ++extern int Hxxxyoa (void); ++extern int HxxxypQ (void); ++extern int HxxxyqA (void); ++extern int HxxxzaA (void); ++extern int Hxxxz_a (void); ++ ++/* Classic ELF hash 2. */ ++extern int Hxxxyob (void); ++extern int HxxxypR (void); ++extern int HxxxyqB (void); ++extern int HxxxzaB (void); ++extern int Hxxxz_b (void); ++ ++/* GNU hash 0. */ ++extern int glidpk (void); ++extern int glidqJ (void); ++extern int glieOk (void); ++extern int gliePJ (void); ++extern int gljCpk (void); ++ ++/* GNU hash 1. */ ++extern int glidpl (void); ++extern int glidqK (void); ++extern int glieOl (void); ++extern int gliePK (void); ++extern int gljCpl (void); ++ ++/* GNU hash 2. */ ++extern int glidpm (void); ++extern int glidqL (void); ++extern int glieOm (void); ++extern int gliePL (void); ++extern int gljCpm (void); ++ ++/* GNU hash 0x7ffffffe. */ ++extern int AdfmZru (void); ++extern int AdfmZsT (void); ++extern int AdfmZt3 (void); ++extern int Adfn9ru (void); ++extern int Adfn9sT (void); ++ ++/* GNU hash 0x7fffffff. */ ++extern int AdfmZrv (void); ++extern int AdfmZsU (void); ++extern int AdfmZt4 (void); ++extern int Adfn9rv (void); ++extern int Adfn9sU (void); ++ ++/* GNU hash 0x80000000. */ ++extern int AdfmZrw (void); ++extern int AdfmZsV (void); ++extern int AdfmZt5 (void); ++extern int Adfn9rw (void); ++extern int Adfn9sV (void); ++ ++/* GNU hash 0x80000001. */ ++extern int AdfmZrx (void); ++extern int AdfmZsW (void); ++extern int AdfmZt6 (void); ++extern int Adfn9rx (void); ++extern int Adfn9sW (void); ++ ++/* GNU hash 0xfffffffe. */ ++extern int glidpi (void); ++extern int glidqH (void); ++extern int glieOi (void); ++extern int gliePH (void); ++extern int gljCpi (void); ++ ++/* GNU hash 0xffffffff. */ ++extern int glidpj (void); ++extern int glidqI (void); ++extern int glieOj (void); ++extern int gliePI (void); ++extern int gljCpj (void); ++ ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (foo (), 1); ++ TEST_COMPARE (Hxxxynpfoo (), 2); ++ TEST_COMPARE (HxxxynpHxxxynpfoo (), 3); ++ TEST_COMPARE (HxxxynpHxxxynpHxxxynpfoo (), 4); ++ TEST_COMPARE (HxxxynpHxxxynpHxxxynpHxxxynpfoo (), 5); ++ TEST_COMPARE (gliinmgliinmgliinmgliinmbar (), 6); ++ TEST_COMPARE (gliinmgliinmgliinmbar (), 7); ++ TEST_COMPARE (gliinmgliinmbar (), 8); ++ TEST_COMPARE (gliinmbar (), 9); ++ TEST_COMPARE (bar (), 10); ++ TEST_COMPARE (Hxxxynp (), 11); ++ TEST_COMPARE (HxxxypP (), 12); ++ TEST_COMPARE (Hxxyinp (), 13); ++ TEST_COMPARE (HxxyipP (), 14); ++ TEST_COMPARE (HxxykNp (), 15); ++ TEST_COMPARE (Hxxxyoa (), 16); ++ TEST_COMPARE (HxxxypQ (), 17); ++ TEST_COMPARE (HxxxyqA (), 18); ++ TEST_COMPARE (HxxxzaA (), 19); ++ TEST_COMPARE (Hxxxz_a (), 20); ++ TEST_COMPARE (Hxxxyob (), 21); ++ TEST_COMPARE (HxxxypR (), 22); ++ TEST_COMPARE (HxxxyqB (), 23); ++ TEST_COMPARE (HxxxzaB (), 24); ++ TEST_COMPARE (Hxxxz_b (), 25); ++ TEST_COMPARE (glidpk (), 26); ++ TEST_COMPARE (glidqJ (), 27); ++ TEST_COMPARE (glieOk (), 28); ++ TEST_COMPARE (gliePJ (), 29); ++ TEST_COMPARE (gljCpk (), 30); ++ TEST_COMPARE (glidpl (), 31); ++ TEST_COMPARE (glidqK (), 32); ++ TEST_COMPARE (glieOl (), 33); ++ TEST_COMPARE (gliePK (), 34); ++ TEST_COMPARE (gljCpl (), 35); ++ TEST_COMPARE (glidpm (), 36); ++ TEST_COMPARE (glidqL (), 37); ++ TEST_COMPARE (glieOm (), 38); ++ TEST_COMPARE (gliePL (), 39); ++ TEST_COMPARE (gljCpm (), 40); ++ TEST_COMPARE (AdfmZru (), 41); ++ TEST_COMPARE (AdfmZsT (), 42); ++ TEST_COMPARE (AdfmZt3 (), 43); ++ TEST_COMPARE (Adfn9ru (), 44); ++ TEST_COMPARE (Adfn9sT (), 45); ++ TEST_COMPARE (AdfmZrv (), 46); ++ TEST_COMPARE (AdfmZsU (), 47); ++ TEST_COMPARE (AdfmZt4 (), 48); ++ TEST_COMPARE (Adfn9rv (), 49); ++ TEST_COMPARE (Adfn9sU (), 50); ++ TEST_COMPARE (AdfmZrw (), 51); ++ TEST_COMPARE (AdfmZsV (), 52); ++ TEST_COMPARE (AdfmZt5 (), 53); ++ TEST_COMPARE (Adfn9rw (), 54); ++ TEST_COMPARE (Adfn9sV (), 55); ++ TEST_COMPARE (AdfmZrx (), 56); ++ TEST_COMPARE (AdfmZsW (), 57); ++ TEST_COMPARE (AdfmZt6 (), 58); ++ TEST_COMPARE (Adfn9rx (), 59); ++ TEST_COMPARE (Adfn9sW (), 60); ++ TEST_COMPARE (glidpi (), 61); ++ TEST_COMPARE (glidqH (), 62); ++ TEST_COMPARE (glieOi (), 63); ++ TEST_COMPARE (gliePH (), 64); ++ TEST_COMPARE (gljCpi (), 65); ++ TEST_COMPARE (glidpj (), 66); ++ TEST_COMPARE (glidqI (), 67); ++ TEST_COMPARE (glieOj (), 68); ++ TEST_COMPARE (gliePI (), 69); ++ TEST_COMPARE (gljCpj (), 70); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-hash-collision2-gnu.c b/elf/tst-hash-collision2-gnu.c +new file mode 100644 +index 0000000000000000..92f0862e914a9dbe +--- /dev/null ++++ b/elf/tst-hash-collision2-gnu.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1.c" +diff --git a/elf/tst-hash-collision2-mod1-gnu.c b/elf/tst-hash-collision2-mod1-gnu.c +new file mode 100644 +index 0000000000000000..9aa5cc1477166c0f +--- /dev/null ++++ b/elf/tst-hash-collision2-mod1-gnu.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision2-mod1.c" +diff --git a/elf/tst-hash-collision2-mod1-sysv.c b/elf/tst-hash-collision2-mod1-sysv.c +new file mode 100644 +index 0000000000000000..9aa5cc1477166c0f +--- /dev/null ++++ b/elf/tst-hash-collision2-mod1-sysv.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision2-mod1.c" +diff --git a/elf/tst-hash-collision2-mod1.c b/elf/tst-hash-collision2-mod1.c +new file mode 100644 +index 0000000000000000..6adf75eb35117d69 +--- /dev/null ++++ b/elf/tst-hash-collision2-mod1.c +@@ -0,0 +1,280 @@ ++/* Test ELF hash collisions: shared object 1. ++ 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 ++ . */ ++ ++#include ++ ++/* Names with hash collisions for classic ELF hash. */ ++ ++int ++foo (void) ++{ ++ return 1; ++} ++ ++int ++Hxxxynpfoo (void) ++{ ++ return 2; ++} ++ ++int ++HxxxynpHxxxynpfoo (void) ++{ ++ return 3; ++} ++ ++ ++/* Names with hash collisions for GNU hash. */ ++ ++int ++bar (void) ++{ ++ return 10; ++} ++ ++int ++gliinmbar (void) ++{ ++ return 9; ++} ++ ++int ++gliinmgliinmbar (void) ++{ ++ return 8; ++} ++ ++ ++/* Names with specific hash values for each hash (see ++ tst-hash-collision1.c for details). */ ++ ++int ++Hxxxynp (void) ++{ ++ return 11; ++} ++ ++int ++HxxxypP (void) ++{ ++ return 12; ++} ++ ++int ++Hxxyinp (void) ++{ ++ return 13; ++} ++ ++int ++Hxxxyoa (void) ++{ ++ return 16; ++} ++ ++int ++HxxxypQ (void) ++{ ++ return 17; ++} ++ ++int ++HxxxyqA (void) ++{ ++ return 18; ++} ++ ++int ++Hxxxyob (void) ++{ ++ return 21; ++} ++ ++int ++HxxxypR (void) ++{ ++ return 22; ++} ++ ++int ++HxxxyqB (void) ++{ ++ return 23; ++} ++ ++int ++glidpk (void) ++{ ++ return 26; ++} ++ ++int ++glidqJ (void) ++{ ++ return 27; ++} ++ ++int ++glieOk (void) ++{ ++ return 28; ++} ++ ++int ++glidpl (void) ++{ ++ return 31; ++} ++ ++int ++glidqK (void) ++{ ++ return 32; ++} ++ ++int ++glieOl (void) ++{ ++ return 33; ++} ++ ++int ++glidpm (void) ++{ ++ return 36; ++} ++ ++int ++glidqL (void) ++{ ++ return 37; ++} ++ ++int ++glieOm (void) ++{ ++ return 38; ++} ++ ++int ++AdfmZru (void) ++{ ++ return 41; ++} ++ ++int ++AdfmZsT (void) ++{ ++ return 42; ++} ++ ++int ++AdfmZt3 (void) ++{ ++ return 43; ++} ++ ++int ++AdfmZrv (void) ++{ ++ return 46; ++} ++ ++int ++AdfmZsU (void) ++{ ++ return 47; ++} ++ ++int ++AdfmZt4 (void) ++{ ++ return 48; ++} ++ ++int ++AdfmZrw (void) ++{ ++ return 51; ++} ++ ++int ++AdfmZsV (void) ++{ ++ return 52; ++} ++ ++int ++AdfmZt5 (void) ++{ ++ return 53; ++} ++ ++int ++AdfmZrx (void) ++{ ++ return 56; ++} ++ ++int ++AdfmZsW (void) ++{ ++ return 57; ++} ++ ++int ++AdfmZt6 (void) ++{ ++ return 58; ++} ++ ++int ++glidpi (void) ++{ ++ return 61; ++} ++ ++int ++glidqH (void) ++{ ++ return 62; ++} ++ ++int ++glieOi (void) ++{ ++ return 63; ++} ++ ++int ++glidpj (void) ++{ ++ return 66; ++} ++ ++int ++glidqI (void) ++{ ++ return 67; ++} ++ ++int ++glieOj (void) ++{ ++ return 68; ++} +diff --git a/elf/tst-hash-collision2-mod2-gnu.c b/elf/tst-hash-collision2-mod2-gnu.c +new file mode 100644 +index 0000000000000000..39579f6736fe366d +--- /dev/null ++++ b/elf/tst-hash-collision2-mod2-gnu.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision2-mod2.c" +diff --git a/elf/tst-hash-collision2-mod2-sysv.c b/elf/tst-hash-collision2-mod2-sysv.c +new file mode 100644 +index 0000000000000000..39579f6736fe366d +--- /dev/null ++++ b/elf/tst-hash-collision2-mod2-sysv.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision2-mod2.c" +diff --git a/elf/tst-hash-collision2-mod2.c b/elf/tst-hash-collision2-mod2.c +new file mode 100644 +index 0000000000000000..e0bb90e60bc477b7 +--- /dev/null ++++ b/elf/tst-hash-collision2-mod2.c +@@ -0,0 +1,196 @@ ++/* Test ELF hash collisions: shared object 2. ++ 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 ++ . */ ++ ++#include ++ ++/* Names with hash collisions for classic ELF hash. */ ++ ++int ++HxxxynpHxxxynpHxxxynpfoo (void) ++{ ++ return 4; ++} ++ ++int ++HxxxynpHxxxynpHxxxynpHxxxynpfoo (void) ++{ ++ return 5; ++} ++ ++ ++/* Names with hash collisions for GNU hash. */ ++ ++int ++gliinmgliinmgliinmbar (void) ++{ ++ return 7; ++} ++ ++int ++gliinmgliinmgliinmgliinmbar (void) ++{ ++ return 6; ++} ++ ++ ++/* Names with specific hash values for each hash (see ++ tst-hash-collision1.c for details). */ ++ ++int ++HxxyipP (void) ++{ ++ return 14; ++} ++ ++int ++HxxykNp (void) ++{ ++ return 15; ++} ++ ++int ++HxxxzaA (void) ++{ ++ return 19; ++} ++ ++int ++Hxxxz_a (void) ++{ ++ return 20; ++} ++ ++int ++HxxxzaB (void) ++{ ++ return 24; ++} ++ ++int ++Hxxxz_b (void) ++{ ++ return 25; ++} ++ ++int ++gliePJ (void) ++{ ++ return 29; ++} ++ ++int ++gljCpk (void) ++{ ++ return 30; ++} ++ ++int ++gliePK (void) ++{ ++ return 34; ++} ++ ++int ++gljCpl (void) ++{ ++ return 35; ++} ++ ++int ++gliePL (void) ++{ ++ return 39; ++} ++ ++int ++gljCpm (void) ++{ ++ return 40; ++} ++ ++int ++Adfn9ru (void) ++{ ++ return 44; ++} ++ ++int ++Adfn9sT (void) ++{ ++ return 45; ++} ++ ++int ++Adfn9rv (void) ++{ ++ return 49; ++} ++ ++int ++Adfn9sU (void) ++{ ++ return 50; ++} ++ ++int ++Adfn9rw (void) ++{ ++ return 54; ++} ++ ++int ++Adfn9sV (void) ++{ ++ return 55; ++} ++ ++int ++Adfn9rx (void) ++{ ++ return 59; ++} ++ ++int ++Adfn9sW (void) ++{ ++ return 60; ++} ++ ++int ++gliePH (void) ++{ ++ return 64; ++} ++ ++int ++gljCpi (void) ++{ ++ return 65; ++} ++ ++int ++gliePI (void) ++{ ++ return 69; ++} ++ ++int ++gljCpj (void) ++{ ++ return 70; ++} +diff --git a/elf/tst-hash-collision2-sysv.c b/elf/tst-hash-collision2-sysv.c +new file mode 100644 +index 0000000000000000..92f0862e914a9dbe +--- /dev/null ++++ b/elf/tst-hash-collision2-sysv.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1.c" +diff --git a/elf/tst-hash-collision2.c b/elf/tst-hash-collision2.c +new file mode 100644 +index 0000000000000000..92f0862e914a9dbe +--- /dev/null ++++ b/elf/tst-hash-collision2.c +@@ -0,0 +1 @@ ++#include "tst-hash-collision1.c" +diff --git a/elf/tst-hash-collision3-mod.c b/elf/tst-hash-collision3-mod.c +new file mode 100644 +index 0000000000000000..f24a15c7d3b78aa7 +--- /dev/null ++++ b/elf/tst-hash-collision3-mod.c +@@ -0,0 +1,88 @@ ++/* Test ELF symbol version hash collisions: shared object. ++ 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 ++ . */ ++ ++int ++foo1 (void) ++{ ++ return 1; ++} ++ ++int ++foo2 (void) ++{ ++ return 2; ++} ++ ++int ++foo3 (void) ++{ ++ return 3; ++} ++ ++int ++foo4 (void) ++{ ++ return 4; ++} ++ ++int ++foo5 (void) ++{ ++ return 5; ++} ++ ++int ++bar1 (void) ++{ ++ return 6; ++} ++ ++int ++bar2 (void) ++{ ++ return 7; ++} ++ ++int ++bar3 (void) ++{ ++ return 8; ++} ++ ++int ++bar4 (void) ++{ ++ return 9; ++} ++ ++int ++bar5 (void) ++{ ++ return 10; ++} ++ ++symbol_version (foo1, foo, Hxxxyoa); ++symbol_version (foo2, foo, HxxxypQ); ++symbol_version (foo3, foo, HxxxyqA); ++symbol_version (foo4, foo, HxxxzaA); ++symbol_version (foo5, foo, Hxxxz_a); ++symbol_version (bar1, bar, Hxxxyob); ++symbol_version (bar2, bar, HxxxypR); ++symbol_version (bar3, bar, HxxxyqB); ++symbol_version (bar4, bar, HxxxzaB); ++symbol_version (bar5, bar, Hxxxz_b); +diff --git a/elf/tst-hash-collision3-mod.map b/elf/tst-hash-collision3-mod.map +new file mode 100644 +index 0000000000000000..1b7d8498309c606b +--- /dev/null ++++ b/elf/tst-hash-collision3-mod.map +@@ -0,0 +1,43 @@ ++Base { ++ local: *; ++}; ++ ++Hxxxyoa { ++ global: foo; ++} Base; ++ ++HxxxypQ { ++ global: foo; ++} Base; ++ ++HxxxyqA { ++ global: foo; ++} Base; ++ ++HxxxzaA { ++ global: foo; ++} Base; ++ ++Hxxxz_a { ++ global: foo; ++} Base; ++ ++Hxxxyob { ++ global: bar; ++} Base; ++ ++HxxxypR { ++ global: bar; ++} Base; ++ ++HxxxyqB { ++ global: bar; ++} Base; ++ ++HxxxzaB { ++ global: bar; ++} Base; ++ ++Hxxxz_b { ++ global: bar; ++} Base; +diff --git a/elf/tst-hash-collision3.c b/elf/tst-hash-collision3.c +new file mode 100644 +index 0000000000000000..309869c3f86d3859 +--- /dev/null ++++ b/elf/tst-hash-collision3.c +@@ -0,0 +1,61 @@ ++/* Test ELF symbol version hash collisions. ++ 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 ++ . */ ++ ++#include ++#include ++ ++extern int ref_foo1 (void); ++extern int ref_foo2 (void); ++extern int ref_foo3 (void); ++extern int ref_foo4 (void); ++extern int ref_foo5 (void); ++extern int ref_bar1 (void); ++extern int ref_bar2 (void); ++extern int ref_bar3 (void); ++extern int ref_bar4 (void); ++extern int ref_bar5 (void); ++ ++symbol_version_reference (ref_foo1, foo, Hxxxyoa); ++symbol_version_reference (ref_foo2, foo, HxxxypQ); ++symbol_version_reference (ref_foo3, foo, HxxxyqA); ++symbol_version_reference (ref_foo4, foo, HxxxzaA); ++symbol_version_reference (ref_foo5, foo, Hxxxz_a); ++symbol_version_reference (ref_bar1, bar, Hxxxyob); ++symbol_version_reference (ref_bar2, bar, HxxxypR); ++symbol_version_reference (ref_bar3, bar, HxxxyqB); ++symbol_version_reference (ref_bar4, bar, HxxxzaB); ++symbol_version_reference (ref_bar5, bar, Hxxxz_b); ++ ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (ref_foo1 (), 1); ++ TEST_COMPARE (ref_foo2 (), 2); ++ TEST_COMPARE (ref_foo3 (), 3); ++ TEST_COMPARE (ref_foo4 (), 4); ++ TEST_COMPARE (ref_foo5 (), 5); ++ TEST_COMPARE (ref_bar1 (), 6); ++ TEST_COMPARE (ref_bar2 (), 7); ++ TEST_COMPARE (ref_bar3 (), 8); ++ TEST_COMPARE (ref_bar4 (), 9); ++ TEST_COMPARE (ref_bar5 (), 10); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-58987-1.patch b/SOURCES/glibc-RHEL-58987-1.patch new file mode 100644 index 0000000..e941392 --- /dev/null +++ b/SOURCES/glibc-RHEL-58987-1.patch @@ -0,0 +1,26 @@ +commit 062257c5d929e3c9a83a26624a09e57936ac6b5e +Author: Joseph Myers +Date: Thu Dec 5 21:40:57 2024 +0000 + + Fix typo in elf/Makefile:postclean-generated + + The postclean-generated setting in elf/Makefile lists + $(objpfx)/dso-sort-tests-2.generated-makefile twice and + $(objpfx)/dso-sort-tests-1.generated-makefile not at all, which looks + like a typo; fix it to list each once. + + Tested for x86_64. + +diff --git a/elf/Makefile b/elf/Makefile +index 96d5c290c9447c74..dfdcfc8e3d1e1770 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1140,7 +1140,7 @@ $(objpfx)$(1).generated-makefile: $(1) + endef + endif + +-postclean-generated += $(objpfx)/dso-sort-tests-2.generated-makefile \ ++postclean-generated += $(objpfx)/dso-sort-tests-1.generated-makefile \ + $(objpfx)/dso-sort-tests-2.generated-makefile + + # Generate from each testcase description file diff --git a/SOURCES/glibc-RHEL-58987-2.patch b/SOURCES/glibc-RHEL-58987-2.patch new file mode 100644 index 0000000..fcbf4ba --- /dev/null +++ b/SOURCES/glibc-RHEL-58987-2.patch @@ -0,0 +1,333 @@ +commit d7f587398cfda79a48cde94a38c4eee660781d30 +Author: Joseph Myers +Date: Thu Dec 19 18:56:04 2024 +0000 + + Add further DSO dependency sorting tests + + The current DSO dependency sorting tests are for a limited number of + specific cases, including some from particular bug reports. + + Add tests that systematically cover all possible DAGs for an + executable and the shared libraries it depends on, directly or + indirectly, up to four objects (an executable and three shared + libraries). (For this kind of DAG - ones with a single source vertex + from which all others are reachable, and an ordering on the edges from + each vertex - there are 57 DAGs on four vertices, 3399 on five + vertices and 1026944 on six vertices; see + https://arxiv.org/pdf/2303.14710 for more details on this enumeration. + I've tested that the 3399 cases with five vertices do all pass if + enabled.) + + These tests are replicating the sorting logic from the dynamic linker + (thereby, for example, asserting that it doesn't accidentally change); + I'm not claiming that the logic in the dynamic linker is in some + abstract sense optimal. Note that these tests do illustrate how in + some cases the two sorting algorithms produce different results for a + DAG (I think all the existing tests for such differences are ones + involving cycles, and the motivation for the new algorithm was also to + improve the handling of cycles): + + tst-dso-ordering-all4-44: a->[bc];{}->[cba] + output(glibc.rtld.dynamic_sort=1): c>b>a>{}c>a>{}[abc] + output: c>b>a>{}[cb];{}->[cba] + output: c>b>a>{} $@ ++ ++$(objpfx)dso-sort-tests-all3.def: dso-sort-tests-all.py ++ $(PYTHON) $< 3 > $@ ++ ++$(objpfx)dso-sort-tests-all4.def: dso-sort-tests-all.py ++ $(PYTHON) $< 4 > $@ ++ ++$(eval $(call include_dsosort_tests_objpfx,dso-sort-tests-all2.def)) ++$(eval $(call include_dsosort_tests_objpfx,dso-sort-tests-all3.def)) ++$(eval $(call include_dsosort_tests_objpfx,dso-sort-tests-all4.def)) ++endif # $(have-tunables) + + check-abi: $(objpfx)check-abi-ld.out + tests-special += $(objpfx)check-abi-ld.out +diff --git a/elf/dso-sort-tests-all.py b/elf/dso-sort-tests-all.py +new file mode 100755 +index 0000000000000000..703e7d2eddae3482 +--- /dev/null ++++ b/elf/dso-sort-tests-all.py +@@ -0,0 +1,218 @@ ++#!/usr/bin/env python3 ++# Generate all DAGs for dependency ordering of a given number of objects. ++# 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 ++# . ++ ++import argparse ++import sys ++ ++ ++def print_dag(state, dag, postorder, postorder_new): ++ """Print a DAG in the form used by dso-ordering-test.py.""" ++ out = [] ++ for i in range(len(dag)): ++ if dag[i]: ++ if i == len(dag) - 1: ++ name = '{}' ++ else: ++ name = chr(ord('a') + len(dag) - 2 - i) ++ this_deps = [chr(ord('a') + len(dag) - 2 - j) for j in dag[i]] ++ this_out = ('[%s]' % (''.join(this_deps)) ++ if len(this_deps) > 1 ++ else this_deps[0]) ++ out.append('%s->%s' % (name, this_out)) ++ output_old = ( ++ '%s>{}<%s' % ++ ('>'.join(chr(ord('a') + i) for i in range(len(dag) - 2, -1, -1)), ++ '<'.join(chr(ord('a') + i) for i in range(0, len(dag) - 1)))) ++ if postorder == postorder_new: ++ print('tst-dso-ordering-all%d-%d: %s\n' ++ 'output: %s\n' ++ % (len(dag), state['num_dags'], ';'.join(out), output_old)) ++ else: ++ names_new = [chr(ord('a') + len(dag) - 2 - x) ++ for x in postorder_new[:-1]] ++ output_new = '%s>{}<%s' % ('>'.join(names_new), ++ '<'.join(reversed(names_new))) ++ print('tst-dso-ordering-all%d-%d: %s\n' ++ 'output(glibc.rtld.dynamic_sort=1): %s\n' ++ 'output(glibc.rtld.dynamic_sort=2): %s\n' ++ % (len(dag), state['num_dags'], ';'.join(out), output_old, ++ output_new)) ++ state['num_dags'] += 1 ++ ++ ++def gen_postorder_old(dag, postorder): ++ """Generate a postorder traversal of the vertices of the given ++ DAG, in the particular choice of ordering that corresponds to how ++ the dynamic linker sorts constructor executions (old algorithm).""" ++ # First list all the vertices, breadth-first. ++ postorder.append(len(dag) - 1) ++ for i in range(len(dag)): ++ for v in dag[postorder[i]]: ++ if v not in postorder: ++ postorder.append(v) ++ # Now move any vertex with an edge from a later one to just after ++ # the last vertex with an edge to it (emulating the older dynamic ++ # linker algorithm). ++ changed = True ++ while changed: ++ changed = False ++ i = 0 ++ while i < len(dag): ++ move_past = None ++ for k in range(len(dag) - 1, i, -1): ++ if postorder[i] in dag[postorder[k]]: ++ move_past = k ++ break ++ if move_past is None: ++ i += 1 ++ else: ++ changed = True ++ postorder[i:k+1] = postorder[i+1:k+1] + [postorder[i]] ++ # Finally, reverse the list. ++ postorder.reverse() ++ ++ ++def gen_postorder_dfs(dag, postorder, v): ++ """Traverse the dependencies of a vertex as part of generating a ++ postorder traversal of the given DAG (new algorithm).""" ++ if v in postorder: ++ return ++ for d in dag[v]: ++ gen_postorder_dfs(dag, postorder, d) ++ postorder.append(v) ++ ++ ++def gen_postorder_new(dag, postorder): ++ """Generate a postorder traversal of the vertices of the given ++ DAG, in the particular choice of ordering that corresponds to how ++ the dynamic linker sorts constructor executions (new algorithm).""" ++ # First list all the vertices, breadth-first. ++ tmp = [] ++ tmp.append(len(dag) - 1) ++ for i in range(len(dag)): ++ for v in dag[tmp[i]]: ++ if v not in tmp: ++ tmp.append(v) ++ # Starting at the end of the breadth-first list, do depth-first ++ # traversal of dependencies to add to the final ordering. ++ for v in reversed(tmp): ++ gen_postorder_dfs(dag, postorder, v) ++ ++ ++def gen_orderings_rec_sub(state, dag, num_done, num_swaps_done): ++ """Generate possible orderings for the edges out from each vertex ++ of a DAG and test whether a postorder traversal yields the ++ vertices in order, where orderings have already been generated for ++ some number of vertices and some number of initial edges have been ++ chosen in the ordering for the next vertex.""" ++ if num_swaps_done >= len(dag[num_done]) - 1: ++ gen_orderings_rec(state, dag, num_done + 1) ++ else: ++ for i in range(num_swaps_done, len(dag[num_done])): ++ ndag = dag ++ if i != num_swaps_done: ++ ndag = ndag.copy() ++ ndag[num_done] = ndag[num_done].copy() ++ first = ndag[num_done][num_swaps_done] ++ second = ndag[num_done][i] ++ ndag[num_done][i] = first ++ ndag[num_done][num_swaps_done] = second ++ gen_orderings_rec_sub(state, ndag, num_done, num_swaps_done + 1) ++ ++def gen_orderings_rec(state, dag, num_done): ++ """Generate possible orderings for the edges out from each vertex ++ of a DAG and test whether a postorder traversal yields the ++ vertices in order, where orderings have already been generated for ++ some number of vertices.""" ++ if num_done == len(dag): ++ postorder = [] ++ gen_postorder_old(dag, postorder) ++ if postorder == sorted(postorder): ++ postorder_new = [] ++ gen_postorder_new(dag, postorder_new) ++ print_dag(state, dag, postorder, postorder_new) ++ else: ++ gen_orderings_rec_sub(state, dag, num_done, 0) ++ ++ ++def gen_orderings(state, dag): ++ """Generate possible orderings for the edges out from each vertex ++ of a DAG and test whether a postorder traversal yields the ++ vertices in order.""" ++ gen_orderings_rec(state, dag, 0) ++ ++ ++def gen_dags_rec_sub(state, partial_dag, num_vertices, num_done_last): ++ """Generate DAGs, where a partial DAG for an initial subsequence ++ of the vertices, and partial information about edges from the last ++ vertex, are passed in.""" ++ if num_done_last == len(partial_dag) - 1: ++ gen_dags_rec(state, partial_dag, num_vertices) ++ else: ++ # Recurse with an edge to vertex num_done_last. ++ new_dag = partial_dag.copy() ++ new_dag[-1] = new_dag[-1].copy() ++ new_dag[-1].append(num_done_last) ++ gen_dags_rec_sub(state, new_dag, num_vertices, num_done_last + 1) ++ # Recurse without an edge to vertex num_done_last, unless this is ++ # the last vertex and num_done_last is not otherwise reachable. ++ can_recurse_without = len(partial_dag) < num_vertices ++ if not can_recurse_without: ++ for i in range(num_done_last + 1, len(partial_dag) - 1): ++ if num_done_last in partial_dag[i]: ++ can_recurse_without = True ++ break ++ if can_recurse_without: ++ gen_dags_rec_sub(state, partial_dag, num_vertices, ++ num_done_last + 1) ++ ++ ++def gen_dags_rec(state, partial_dag, num_vertices): ++ """Generate DAGs, where a partial DAG for an initial subsequence ++ of the vertices is passed in.""" ++ if len(partial_dag) == num_vertices: ++ gen_orderings(state, partial_dag) ++ else: ++ partial_dag = partial_dag.copy() ++ partial_dag.append([]) ++ gen_dags_rec_sub(state, partial_dag, num_vertices, 0) ++ ++ ++def gen_dags(state, num_vertices): ++ """Generate DAGs with the given number of vertices, last vertex a ++ distinguished root vertex from which all the others can be ++ reached, order of edges from each vertex considered significant, ++ such that a postorder traversal (corresponding to the order in ++ which DSO dependency constructors are executed) yields the ++ vertices in order.""" ++ gen_dags_rec(state, [[]], num_vertices) ++ ++ ++def main(argv): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description='Generate DAGs to test DSO dependency ordering.') ++ parser.add_argument('num_objects', help='number of objects in DAG') ++ print('tunable_option: glibc.rtld.dynamic_sort=1\n' ++ 'tunable_option: glibc.rtld.dynamic_sort=2\n') ++ gen_dags({'num_dags': 0}, int(parser.parse_args(argv).num_objects)) ++ ++ ++if __name__ == '__main__': ++ main(sys.argv[1:]) diff --git a/SOURCES/glibc-RHEL-58989-1.patch b/SOURCES/glibc-RHEL-58989-1.patch new file mode 100644 index 0000000..dd7bd38 --- /dev/null +++ b/SOURCES/glibc-RHEL-58989-1.patch @@ -0,0 +1,228 @@ +commit 3d53d18fc71c5d9ef4773b8bce04d54b80181926 +Author: Adhemerval Zanella +Date: Tue Mar 12 13:21:20 2024 -0300 + + elf: Enable TLS descriptor tests on aarch64 + + The aarch64 uses 'trad' for traditional tls and 'desc' for tls + descriptors, but unlike other targets it defaults to 'desc'. The + gnutls2 configure check does not set aarch64 as an ABI that uses + TLS descriptors, which then disable somes stests. + + Also rename the internal machinery fron gnu2 to tls descriptors. + + Checked on aarch64-linux-gnu. + Reviewed-by: H.J. Lu + + +Conflicts: + configure (regenerated) + configure.ac (fixed context) + elf/Makefile (fixed context) + sysdeps/arm/Makefile (fixed context) + +diff --git a/configure b/configure +index afa094324cdcf96d..605309159db1e2a0 100755 +--- a/configure ++++ b/configure +@@ -619,7 +619,7 @@ LIBGD + libc_cv_cc_loop_to_function + libc_cv_cc_submachine + libc_cv_cc_nofma +-libc_cv_mtls_dialect_gnu2 ++libc_cv_mtls_descriptor + fno_unit_at_a_time + libc_cv_has_glob_dat + libc_cv_hashstyle +@@ -3896,6 +3896,9 @@ libc_config_ok=no + # whether to use such directories. + with_fp_cond=1 + ++# A preconfigure script may define another name to TLS descriptor variant ++mtls_descriptor=gnu2 ++ + if frags=`ls -d $srcdir/sysdeps/*/preconfigure 2> /dev/null` + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysdeps preconfigure fragments" >&5 +@@ -6162,9 +6165,9 @@ else + fi + + +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -mtls-dialect=gnu2" >&5 +-$as_echo_n "checking for -mtls-dialect=gnu2... " >&6; } +-if ${libc_cv_mtls_dialect_gnu2+:} false; then : ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tls descriptor support" >&5 ++$as_echo_n "checking for tls descriptor support... " >&6; } ++if ${libc_cv_mtls_descriptor+:} false; then : + $as_echo_n "(cached) " >&6 + else + cat > conftest.c <&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then +- libc_cv_mtls_dialect_gnu2=yes ++ libc_cv_mtls_descriptor=$mtls_descriptor + else +- libc_cv_mtls_dialect_gnu2=no ++ libc_cv_mtls_descriptor=no + fi + rm -f conftest* + fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mtls_dialect_gnu2" >&5 +-$as_echo "$libc_cv_mtls_dialect_gnu2" >&6; } ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mtls_descriptor" >&5 ++$as_echo "$libc_cv_mtls_descriptor" >&6; } + + config_vars="$config_vars +-have-mtls-dialect-gnu2 = $libc_cv_mtls_dialect_gnu2" ++have-mtls-descriptor = $libc_cv_mtls_descriptor" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc puts quotes around section names" >&5 + $as_echo_n "checking whether cc puts quotes around section names... " >&6; } +diff --git a/configure.ac b/configure.ac +index 85ea64f9f5f4fd35..d18d8bdff9a7849d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -533,6 +533,9 @@ libc_config_ok=no + # whether to use such directories. + with_fp_cond=1 + ++# A preconfigure script may define another name to TLS descriptor variant ++mtls_descriptor=gnu2 ++ + dnl Let sysdeps/*/preconfigure act here. + LIBC_PRECONFIGURE([$srcdir], [for sysdeps]) + +@@ -1429,7 +1432,7 @@ else + fi + AC_SUBST(fno_unit_at_a_time) + +-AC_CACHE_CHECK([for -mtls-dialect=gnu2], libc_cv_mtls_dialect_gnu2, ++AC_CACHE_CHECK([for tls descriptor support], libc_cv_mtls_descriptor, + [dnl + cat > conftest.c <&AS_MESSAGE_LOG_FD]) ++if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -fPIC -mtls-dialect=$mtls_descriptor -nostdlib -nostartfiles ++ -shared conftest.c -o conftest 1>&AS_MESSAGE_LOG_FD]) + then +- libc_cv_mtls_dialect_gnu2=yes ++ libc_cv_mtls_descriptor=$mtls_descriptor + else +- libc_cv_mtls_dialect_gnu2=no ++ libc_cv_mtls_descriptor=no + fi + rm -f conftest*]) +-AC_SUBST(libc_cv_mtls_dialect_gnu2) +-LIBC_CONFIG_VAR([have-mtls-dialect-gnu2], [$libc_cv_mtls_dialect_gnu2]) ++AC_SUBST(libc_cv_mtls_descriptor) ++LIBC_CONFIG_VAR([have-mtls-descriptor], [$libc_cv_mtls_descriptor]) + + AC_CACHE_CHECK(whether cc puts quotes around section names, + libc_cv_have_section_quotes, +diff --git a/elf/Makefile b/elf/Makefile +index 7d686ca7d190c921..65eb3b9b28183821 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -944,13 +944,13 @@ modules-names-tests = $(filter-out ifuncmod% tst-tlsmod% \ + tst-hash-collision3-mod,\ + $(modules-names)) + +-ifeq (yes,$(have-mtls-dialect-gnu2)) ++ifneq (no,$(have-mtls-descriptor)) + tests += tst-gnu2-tls1 + modules-names += tst-gnu2-tls1mod + $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so + tst-gnu2-tls1mod.so-no-z-defs = yes +-CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2 +-endif # $(have-mtls-dialect-gnu2) ++CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=$(have-mtls-descriptor) ++endif # $(have-mtls-descriptor) + + ifeq (yes,$(have-protected-data)) + modules-names += tst-protected1moda tst-protected1modb +@@ -2719,11 +2719,11 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \ + $(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ + $(objpfx)tst-audit-tlsdesc-mod2.so \ + $(shared-thread-library) +-ifeq (yes,$(have-mtls-dialect-gnu2)) ++ifneq (no,$(have-mtls-descriptor)) + # The test is valid for all TLS types, but we want to exercise GNU2 + # TLS if possible. +-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 +-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 ++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=$(have-mtls-descriptor) + endif + $(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) + $(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ +@@ -2763,10 +2763,14 @@ $(objpfx)tst-tlsgap.out: \ + $(objpfx)tst-tlsgap-mod0.so \ + $(objpfx)tst-tlsgap-mod1.so \ + $(objpfx)tst-tlsgap-mod2.so +-ifeq (yes,$(have-mtls-dialect-gnu2)) +-CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2 +-CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2 +-CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2 ++ ++ifneq (no,$(have-mtls-descriptor)) ++CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-gnu2-tls2mod0.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-gnu2-tls2mod1.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-gnu2-tls2mod2.c += -mtls-dialect=$(have-mtls-descriptor) + endif + + $(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so +diff --git a/sysdeps/aarch64/preconfigure b/sysdeps/aarch64/preconfigure +index d9bd1f8558a079cb..19657b627bc84c4e 100644 +--- a/sysdeps/aarch64/preconfigure ++++ b/sysdeps/aarch64/preconfigure +@@ -2,5 +2,6 @@ case "$machine" in + aarch64*) + base_machine=aarch64 + machine=aarch64 ++ mtls_descriptor=desc + ;; + esac +diff --git a/sysdeps/arm/Makefile b/sysdeps/arm/Makefile +index fb4164f0d9cf71fa..efe08b15e16ccda4 100644 +--- a/sysdeps/arm/Makefile ++++ b/sysdeps/arm/Makefile +@@ -18,15 +18,15 @@ $(objpfx)libgcc-stubs.a: $(objpfx)aeabi_unwind_cpp_pr1.os + lib-noranlib: $(objpfx)libgcc-stubs.a + + ifeq ($(build-shared),yes) +-ifeq ($(have-arm-tls-desc),yes) ++ifneq (no,$(have-mtls-descriptor)) + tests += tst-armtlsdescloc tst-armtlsdescextnow tst-armtlsdescextlazy + modules-names += tst-armtlsdesclocmod + modules-names += tst-armtlsdescextlazymod tst-armtlsdescextnowmod + CPPFLAGS-tst-armtlsdescextnowmod.c += -Dstatic= + CPPFLAGS-tst-armtlsdescextlazymod.c += -Dstatic= +-CFLAGS-tst-armtlsdesclocmod.c += -mtls-dialect=gnu2 +-CFLAGS-tst-armtlsdescextnowmod.c += -mtls-dialect=gnu2 +-CFLAGS-tst-armtlsdescextlazymod.c += -mtls-dialect=gnu2 ++CFLAGS-tst-armtlsdesclocmod.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-armtlsdescextnowmod.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-armtlsdescextlazymod.c += -mtls-dialect=$(have-mtls-descriptor) + LDFLAGS-tst-armtlsdescextnowmod.so += -Wl,-z,now + tst-armtlsdescloc-ENV = LD_BIND_NOW=1 + tst-armtlsdescextnow-ENV = LD_BIND_NOW=1 diff --git a/SOURCES/glibc-RHEL-58989-2.patch b/SOURCES/glibc-RHEL-58989-2.patch new file mode 100644 index 0000000..bbf813a --- /dev/null +++ b/SOURCES/glibc-RHEL-58989-2.patch @@ -0,0 +1,495 @@ +commit 9b5f2eb9fc5d3cf4b984f6002e69aac43296e922 +Author: Joseph Myers +Date: Thu Dec 5 09:53:47 2024 +0000 + + Add further test of TLS + + Add an additional test of TLS variables, with different alignment, + accessed from different modules. The idea of the alignment test is + similar to tst-tlsalign and the same code is shared for setting up + test variables, but unlike the tst-tlsalign code, there are multiple + threads and variables are accessed from multiple objects to verify + that they get a consistent notion of the address of an object within a + thread. Threads are repeatedly created and shut down to verify proper + initialization in each new thread. The test is also repeated with TLS + descriptors when supported. (However, only initial-exec TLS is + covered in this test.) + + Tested for x86_64. + +Conflicts: + elf/Makefile (fixup context) + +diff --git a/elf/Makefile b/elf/Makefile +index 4a9c983686126adf..9d48e408de0a67a4 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -454,6 +454,8 @@ tests += \ + tst-tls19 \ + tst-tls20 \ + tst-tls21 \ ++ tst-tls22 \ ++ tst-tls22-gnu2 \ + tst-tls4 \ + tst-tls5 \ + tst-tlsalign \ +@@ -592,9 +594,15 @@ tst-tls-many-dynamic-modules-dep-bad = \ + extra-test-objs += \ + $(tlsmod17a-modules:=.os) \ + $(tlsmod18a-modules:=.os) \ ++ tst-tls22-mod1-vars.os \ ++ tst-tls22-mod2-vars.os \ ++ tst-tls22-vars.o \ + tst-tlsalign-vars.o \ + # extra-test-objs + test-extras += \ ++ tst-tls22-mod1-vars \ ++ tst-tls22-mod2-vars \ ++ tst-tls22-vars \ + tst-tlsalign-vars \ + tst-tlsmod17a \ + tst-tlsmod18a \ +@@ -840,6 +848,10 @@ modules-names = \ + tst-tls19mod3 \ + tst-tls20mod-bad \ + tst-tls21mod \ ++ tst-tls22-mod1 \ ++ tst-tls22-mod1-gnu2 \ ++ tst-tls22-mod2 \ ++ tst-tls22-mod2-gnu2 \ + tst-tlsalign-lib \ + tst-tlsgap-mod0 \ + tst-tlsgap-mod1 \ +@@ -2822,3 +2834,27 @@ $(objpfx)tst-hash-collision2-sysv: $(objpfx)tst-hash-collision2-mod1-sysv.so \ + LDFLAGS-tst-hash-collision3-mod.so = \ + -Wl,--version-script=tst-hash-collision3-mod.map + $(objpfx)tst-hash-collision3: $(objpfx)tst-hash-collision3-mod.so ++ ++$(objpfx)tst-tls22: $(objpfx)tst-tls22-vars.o $(objpfx)tst-tls22-mod1.so \ ++ $(objpfx)tst-tls22-mod2.so $(shared-thread-library) ++$(objpfx)tst-tls22-mod1.so: $(objpfx)tst-tls22-mod1.os \ ++ $(objpfx)tst-tls22-mod1-vars.os $(objpfx)tst-tls22-mod2.so ++$(objpfx)tst-tls22-mod2.so: $(objpfx)tst-tls22-mod2.os \ ++ $(objpfx)tst-tls22-mod2-vars.os ++$(objpfx)tst-tls22-gnu2: $(objpfx)tst-tls22-vars.o \ ++ $(objpfx)tst-tls22-mod1-gnu2.so $(objpfx)tst-tls22-mod2-gnu2.so \ ++ $(shared-thread-library) ++$(objpfx)tst-tls22-mod1-gnu2.so: $(objpfx)tst-tls22-mod1-gnu2.os \ ++ $(objpfx)tst-tls22-mod1-vars.os $(objpfx)tst-tls22-mod2-gnu2.so ++$(objpfx)tst-tls22-mod2-gnu2.so: $(objpfx)tst-tls22-mod2-gnu2.os \ ++ $(objpfx)tst-tls22-mod2-vars.os ++ifneq (no,$(have-mtls-descriptor)) ++CFLAGS-tst-tls22-gnu2.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-tls22-mod1-gnu2.c += -mtls-dialect=$(have-mtls-descriptor) ++CFLAGS-tst-tls22-mod2-gnu2.c += -mtls-dialect=$(have-mtls-descriptor) ++endif ++# These reference symbols from the main executable. ++tst-tls22-mod1.so-no-z-defs = yes ++tst-tls22-mod1-gnu2.so-no-z-defs = yes ++tst-tls22-mod2.so-no-z-defs = yes ++tst-tls22-mod2-gnu2.so-no-z-defs = yes +diff --git a/elf/tst-tls22-gnu2.c b/elf/tst-tls22-gnu2.c +new file mode 100644 +index 0000000000000000..d9ce6df0b2bcc201 +--- /dev/null ++++ b/elf/tst-tls22-gnu2.c +@@ -0,0 +1 @@ ++#include +diff --git a/elf/tst-tls22-mod1-gnu2.c b/elf/tst-tls22-mod1-gnu2.c +new file mode 100644 +index 0000000000000000..0b085fe175b74962 +--- /dev/null ++++ b/elf/tst-tls22-mod1-gnu2.c +@@ -0,0 +1 @@ ++#include +diff --git a/elf/tst-tls22-mod1-vars.c b/elf/tst-tls22-mod1-vars.c +new file mode 100644 +index 0000000000000000..bdb7358287a325ee +--- /dev/null ++++ b/elf/tst-tls22-mod1-vars.c +@@ -0,0 +1,9 @@ ++#include ++ ++#define tdata1 mod1_tdata1 ++#define tdata2 mod1_tdata2 ++#define tdata3 mod1_tdata3 ++#define tbss1 mod1_tbss1 ++#define tbss2 mod1_tbss2 ++#define tbss3 mod1_tbss3 ++#include +diff --git a/elf/tst-tls22-mod1.c b/elf/tst-tls22-mod1.c +new file mode 100644 +index 0000000000000000..3a47d7bbc6cd16c2 +--- /dev/null ++++ b/elf/tst-tls22-mod1.c +@@ -0,0 +1,27 @@ ++/* Test TLS with varied alignment and multiple modules and threads. ++ 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 ++ . */ ++ ++#include ++ ++void ++test_mod1 (struct one_thread_data *data, int base_val) ++{ ++ STORE_ADDRS (&data->mod1_self, mod1); ++ STORE_ADDRS (&data->exe_from_mod1, exe); ++ STORE_ADDRS (&data->mod2_from_mod1, mod2); ++} +diff --git a/elf/tst-tls22-mod2-gnu2.c b/elf/tst-tls22-mod2-gnu2.c +new file mode 100644 +index 0000000000000000..a5260e0616d8b595 +--- /dev/null ++++ b/elf/tst-tls22-mod2-gnu2.c +@@ -0,0 +1 @@ ++#include +diff --git a/elf/tst-tls22-mod2-vars.c b/elf/tst-tls22-mod2-vars.c +new file mode 100644 +index 0000000000000000..9ef3452bba56e829 +--- /dev/null ++++ b/elf/tst-tls22-mod2-vars.c +@@ -0,0 +1,9 @@ ++#include ++ ++#define tdata1 mod2_tdata1 ++#define tdata2 mod2_tdata2 ++#define tdata3 mod2_tdata3 ++#define tbss1 mod2_tbss1 ++#define tbss2 mod2_tbss2 ++#define tbss3 mod2_tbss3 ++#include +diff --git a/elf/tst-tls22-mod2.c b/elf/tst-tls22-mod2.c +new file mode 100644 +index 0000000000000000..5d26d592b0262b1e +--- /dev/null ++++ b/elf/tst-tls22-mod2.c +@@ -0,0 +1,26 @@ ++/* Test TLS with varied alignment and multiple modules and threads. ++ 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 ++ . */ ++ ++#include ++ ++void ++test_mod2 (struct one_thread_data *data, int base_val) ++{ ++ STORE_ADDRS (&data->mod2_self, mod2); ++ STORE_ADDRS (&data->exe_from_mod2, exe); ++} +diff --git a/elf/tst-tls22-vars.c b/elf/tst-tls22-vars.c +new file mode 100644 +index 0000000000000000..2ad3ee7a3b6ac980 +--- /dev/null ++++ b/elf/tst-tls22-vars.c +@@ -0,0 +1,9 @@ ++#include ++ ++#define tdata1 exe_tdata1 ++#define tdata2 exe_tdata2 ++#define tdata3 exe_tdata3 ++#define tbss1 exe_tbss1 ++#define tbss2 exe_tbss2 ++#define tbss3 exe_tbss3 ++#include +diff --git a/elf/tst-tls22.c b/elf/tst-tls22.c +new file mode 100644 +index 0000000000000000..35a8cd82b22462ff +--- /dev/null ++++ b/elf/tst-tls22.c +@@ -0,0 +1,147 @@ ++/* Test TLS with varied alignment and multiple modules and threads. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static void ++check_addrs_align (const struct obj_addrs *addrs) ++{ ++ TEST_COMPARE (addrs->addr_tdata1 & (__alignof__ (int) - 1), 0); ++ TEST_COMPARE (addrs->addr_tdata2 & 0xf, 0); ++ TEST_COMPARE (addrs->addr_tdata3 & 0xfff, 0); ++ TEST_COMPARE (addrs->addr_tbss1 & (__alignof__ (int) - 1), 0); ++ TEST_COMPARE (addrs->addr_tbss2 & 0xf, 0); ++ TEST_COMPARE (addrs->addr_tbss3 & 0xfff, 0); ++} ++ ++static void ++check_addrs_same (const struct obj_addrs *addrs1, ++ const struct obj_addrs *addrs2) ++{ ++ TEST_COMPARE (addrs1->addr_tdata1, addrs2->addr_tdata1); ++ TEST_COMPARE (addrs1->addr_tdata2, addrs2->addr_tdata2); ++ TEST_COMPARE (addrs1->addr_tdata3, addrs2->addr_tdata3); ++ TEST_COMPARE (addrs1->addr_tbss1, addrs2->addr_tbss1); ++ TEST_COMPARE (addrs1->addr_tbss2, addrs2->addr_tbss2); ++ TEST_COMPARE (addrs1->addr_tbss3, addrs2->addr_tbss3); ++} ++ ++static void ++check_vals_before (const struct obj_values *vals) ++{ ++ TEST_COMPARE (vals->val_tdata1, 1); ++ TEST_COMPARE (vals->val_tdata2, 2); ++ TEST_COMPARE (vals->val_tdata3, 4); ++ TEST_COMPARE (vals->val_tbss1, 0); ++ TEST_COMPARE (vals->val_tbss2, 0); ++ TEST_COMPARE (vals->val_tbss3, 0); ++} ++ ++static void ++check_vals_after (const struct obj_values *vals, int base_val) ++{ ++ TEST_COMPARE (vals->val_tdata1, base_val); ++ TEST_COMPARE (vals->val_tdata2, base_val + 1); ++ TEST_COMPARE (vals->val_tdata3, base_val + 2); ++ TEST_COMPARE (vals->val_tbss1, base_val + 3); ++ TEST_COMPARE (vals->val_tbss2, base_val + 4); ++ TEST_COMPARE (vals->val_tbss3, base_val + 5); ++} ++ ++static void ++check_one_thread (const struct one_thread_data *data, int base_val) ++{ ++ check_vals_before (&data->exe_before); ++ check_vals_before (&data->mod1_before); ++ check_vals_before (&data->mod2_before); ++ check_vals_after (&data->exe_after, base_val); ++ check_vals_after (&data->mod1_after, base_val); ++ check_vals_after (&data->mod2_after, base_val); ++ check_addrs_align (&data->exe_self); ++ check_addrs_same (&data->exe_self, &data->exe_from_mod1); ++ check_addrs_same (&data->exe_self, &data->exe_from_mod2); ++ check_addrs_align (&data->mod1_self); ++ check_addrs_same (&data->mod1_self, &data->mod1_from_exe); ++ check_addrs_align (&data->mod2_self); ++ check_addrs_same (&data->mod2_self, &data->mod2_from_exe); ++ check_addrs_same (&data->mod2_self, &data->mod2_from_mod1); ++} ++ ++static void * ++thread_func (void *arg) ++{ ++ int base_val = (int) (intptr_t) arg + 10; ++ struct one_thread_data data; ++ /* Record the addresses of variables as seen from the main ++ executable (which should be the same as seen from the other ++ modules), and their initial values. */ ++ STORE_ADDRS (&data.exe_self, exe); ++ STORE_ADDRS (&data.mod1_from_exe, mod1); ++ STORE_ADDRS (&data.mod2_from_exe, mod2); ++ STORE_VALUES (&data.exe_before, exe); ++ STORE_VALUES (&data.mod1_before, mod1); ++ STORE_VALUES (&data.mod2_before, mod2); ++ /* Overwrite the value of variables. */ ++ OVERWRITE_VALUES (exe, base_val); ++ OVERWRITE_VALUES (mod1, base_val); ++ OVERWRITE_VALUES (mod2, base_val); ++ /* Record the addresses of variables as seen from other modules. */ ++ test_mod1 (&data, base_val); ++ test_mod2 (&data, base_val); ++ /* Record the overwritten values (thus making sure that no other ++ thread running in parallel has changed this thread's values). */ ++ STORE_VALUES (&data.exe_after, exe); ++ STORE_VALUES (&data.mod1_after, mod1); ++ STORE_VALUES (&data.mod2_after, mod2); ++ /* Check all the addresses and values recorded. */ ++ check_one_thread (&data, base_val); ++ return NULL; ++} ++ ++#define NUM_ITERS 50 ++#define NUM_THREADS 16 ++ ++/* For NUM_ITERS iterations, repeatedly create NUM_THREADS threads. ++ In each thread, we determine the addresses of TLS objects (both ++ from the module defining those objects and from other modules), and ++ their initial values, and store in values that are then read back; ++ we check that each object's address is the same regardless of the ++ module in which it is determined, that alignment of objects is as ++ required, and that the values of objects are as expected. */ ++ ++static int ++do_test (void) ++{ ++ for (size_t i = 0; i < NUM_ITERS; i++) ++ { ++ pthread_t threads[NUM_THREADS]; ++ for (size_t j = 0; j < NUM_THREADS; j++) ++ threads[j] = xpthread_create (NULL, thread_func, (void *) j); ++ /* Also run checks in the main thread, but only once because ++ those values don't get reinitialized. */ ++ if (i == 0) ++ thread_func ((void *) NUM_THREADS); ++ for (size_t j = 0; j < NUM_THREADS; j++) ++ xpthread_join (threads[j]); ++ } ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-tls22.h b/elf/tst-tls22.h +new file mode 100644 +index 0000000000000000..24b2e0a0b6af4d45 +--- /dev/null ++++ b/elf/tst-tls22.h +@@ -0,0 +1,115 @@ ++/* Test TLS with varied alignment and multiple modules and threads: header. ++ 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 ++ . */ ++ ++#ifndef TST_TLS22_H ++#define TST_TLS22_H ++ ++#include ++ ++extern __thread int exe_tdata1 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int exe_tdata2 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int exe_tdata3 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int exe_tbss1 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int exe_tbss2 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int exe_tbss3 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod1_tdata1 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod1_tdata2 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod1_tdata3 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod1_tbss1 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod1_tbss2 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod1_tbss3 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod2_tdata1 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod2_tdata2 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod2_tdata3 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod2_tbss1 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod2_tbss2 __attribute__ ((tls_model ("initial-exec"))); ++extern __thread int mod2_tbss3 __attribute__ ((tls_model ("initial-exec"))); ++ ++/* Structure to store the addresses of one set of TLS objects in one ++ thread, as seen by one module in the program. */ ++struct obj_addrs ++{ ++ uintptr_t addr_tdata1, addr_tdata2, addr_tdata3; ++ uintptr_t addr_tbss1, addr_tbss2, addr_tbss3; ++}; ++ ++/* Structure to store the values of one set of TLS objects in one ++ thread. */ ++struct obj_values ++{ ++ uintptr_t val_tdata1, val_tdata2, val_tdata3; ++ uintptr_t val_tbss1, val_tbss2, val_tbss3; ++}; ++ ++/* Structure to store all the data about TLS objects in one ++ thread. */ ++struct one_thread_data ++{ ++ struct obj_addrs exe_self, exe_from_mod1, exe_from_mod2; ++ struct obj_addrs mod1_self, mod1_from_exe; ++ struct obj_addrs mod2_self, mod2_from_exe, mod2_from_mod1; ++ struct obj_values exe_before, mod1_before, mod2_before; ++ struct obj_values exe_after, mod1_after, mod2_after; ++}; ++ ++/* Store the addresses of variables prefixed by PFX in the structure ++ pointed to by DST. */ ++#define STORE_ADDRS(DST, PFX) \ ++ do \ ++ { \ ++ (DST)->addr_tdata1 = (uintptr_t) &PFX ## _tdata1; \ ++ (DST)->addr_tdata2 = (uintptr_t) &PFX ## _tdata2; \ ++ (DST)->addr_tdata3 = (uintptr_t) &PFX ## _tdata3; \ ++ (DST)->addr_tbss1 = (uintptr_t) &PFX ## _tbss1; \ ++ (DST)->addr_tbss2 = (uintptr_t) &PFX ## _tbss2; \ ++ (DST)->addr_tbss3 = (uintptr_t) &PFX ## _tbss3; \ ++ } \ ++ while (0) ++ ++/* Store the values of variables prefixed by PFX in the structure ++ pointed to by DST. */ ++#define STORE_VALUES(DST, PFX) \ ++ do \ ++ { \ ++ (DST)->val_tdata1 = PFX ## _tdata1; \ ++ (DST)->val_tdata2 = PFX ## _tdata2; \ ++ (DST)->val_tdata3 = PFX ## _tdata3; \ ++ (DST)->val_tbss1 = PFX ## _tbss1; \ ++ (DST)->val_tbss2 = PFX ## _tbss2; \ ++ (DST)->val_tbss3 = PFX ## _tbss3; \ ++ } \ ++ while (0) ++ ++/* Overwrite the values of variables prefixed by PFX with values ++ starting with VAL. */ ++#define OVERWRITE_VALUES(PFX, VAL) \ ++ do \ ++ { \ ++ PFX ## _tdata1 = (VAL); \ ++ PFX ## _tdata2 = (VAL) + 1; \ ++ PFX ## _tdata3 = (VAL) + 2; \ ++ PFX ## _tbss1 = (VAL) + 3; \ ++ PFX ## _tbss2 = (VAL) + 4; \ ++ PFX ## _tbss3 = (VAL) + 5; \ ++ } \ ++ while (0) ++ ++void test_mod1 (struct one_thread_data *data, int base_val); ++void test_mod2 (struct one_thread_data *data, int base_val); ++ ++#endif /* TST_TLS22_H */ diff --git a/SOURCES/glibc-RHEL-59494-1.patch b/SOURCES/glibc-RHEL-59494-1.patch new file mode 100644 index 0000000..5551aae --- /dev/null +++ b/SOURCES/glibc-RHEL-59494-1.patch @@ -0,0 +1,65 @@ +commit 3bea50ccbc925d4fc5f85ec402b6154cbe770b71 +Author: Yu Chien Peter Lin +Date: Fri Sep 30 20:19:50 2022 +0800 + + support: Add xpthread_cond_signal wrapper + + Signed-off-by: Yu Chien Peter Lin + Reviewed-by: Adhemerval Zanella + +diff --git a/support/Makefile b/support/Makefile +index 154e3a4ff03cebda..bfd8d59285524f4d 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -160,6 +160,7 @@ libsupport-routines = \ + xpthread_cancel \ + xpthread_check_return \ + xpthread_cond_wait \ ++ xpthread_cond_signal \ + xpthread_create \ + xpthread_detach \ + xpthread_join \ +diff --git a/support/xpthread_cond_signal.c b/support/xpthread_cond_signal.c +new file mode 100644 +index 0000000000000000..ed0be1a8abf8559b +--- /dev/null ++++ b/support/xpthread_cond_signal.c +@@ -0,0 +1,26 @@ ++/* pthread_cond_signal 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 ++ . */ ++ ++#include ++ ++void ++xpthread_cond_signal (pthread_cond_t *cond) ++{ ++ xpthread_check_return ++ ("pthread_cond_signal", pthread_cond_signal (cond)); ++} +diff --git a/support/xthread.h b/support/xthread.h +index a4a4ec5b1ef16fd3..1a39b1c0ddda9725 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -58,6 +58,7 @@ void xpthread_mutex_consistent (pthread_mutex_t *); + void xpthread_spin_lock (pthread_spinlock_t *lock); + void xpthread_spin_unlock (pthread_spinlock_t *lock); + void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); ++void xpthread_cond_signal (pthread_cond_t *cond); + pthread_t xpthread_create (pthread_attr_t *attr, + void *(*thread_func) (void *), void *closure); + void xpthread_detach (pthread_t thr); diff --git a/SOURCES/glibc-RHEL-59494-2.patch b/SOURCES/glibc-RHEL-59494-2.patch new file mode 100644 index 0000000..35e60c7 --- /dev/null +++ b/SOURCES/glibc-RHEL-59494-2.patch @@ -0,0 +1,107 @@ +commit 365b3af67ecaf176b2e2678afe903bebce598fd7 +Author: Yu Chien Peter Lin +Date: Fri Sep 30 20:19:51 2022 +0800 + + nptl: Convert tst-setuid2 to test-driver + + Use and replace pthread calls to its xpthread + equivalents. + + Signed-off-by: Yu Chien Peter Lin + Reviewed-by: Adhemerval Zanella + +diff --git a/nptl/tst-setuid2.c b/nptl/tst-setuid2.c +index a9e3a6c4c0a48352..2abe6e20d108ccf9 100644 +--- a/nptl/tst-setuid2.c ++++ b/nptl/tst-setuid2.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -36,30 +37,21 @@ static pthread_cond_t cond_recv; + static void * + thread_func (void *ctx __attribute__ ((unused))) + { +- int ret = pthread_mutex_lock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_lock (thread): %d", ret); +- ++ xpthread_mutex_lock (&mutex); + while (true) + { + if (func_sent != NULL) + { + void (*func) (void) = func_sent; +- ret = pthread_mutex_unlock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_unlock (thread): %d", ret); ++ xpthread_mutex_unlock (&mutex); ++ + func (); +- ret = pthread_mutex_lock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_lock (thread): %d", ret); ++ ++ xpthread_mutex_lock (&mutex); + func_sent = NULL; +- ret = pthread_cond_signal (&cond_recv); +- if (ret != 0) +- FAIL ("pthread_cond_signal (recv): %d", ret); ++ xpthread_cond_signal (&cond_recv); + } +- ret = pthread_cond_wait (&cond_send, &mutex); +- if (ret != 0) +- FAIL ("pthread_cond_wait (send): %d", ret); ++ xpthread_cond_wait (&cond_send, &mutex); + } + return NULL; + } +@@ -67,31 +59,18 @@ thread_func (void *ctx __attribute__ ((unused))) + static void + run_on_thread (void (*func) (void)) + { +- int ret = pthread_mutex_lock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_lock (%s): %d", __func__, ret); ++ xpthread_mutex_lock (&mutex); + func_sent = func; +- ret = pthread_mutex_unlock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret); ++ xpthread_mutex_unlock (&mutex); + +- ret = pthread_cond_signal (&cond_send); +- if (ret != 0) +- FAIL ("pthread_mutex_lock (%s): %d", __func__, ret); +- +- ret = pthread_mutex_lock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_lock (%s): %d", __func__, ret); ++ xpthread_cond_signal (&cond_send); + ++ xpthread_mutex_lock (&mutex); + while (func_sent != NULL) + { +- ret = pthread_cond_wait (&cond_recv, &mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_wait (%s): %d", __func__, ret); ++ xpthread_cond_wait (&cond_recv, &mutex); + } +- ret = pthread_mutex_unlock (&mutex); +- if (ret != 0) +- FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret); ++ xpthread_mutex_unlock (&mutex); + } + + static void +@@ -141,5 +120,4 @@ do_test (void) + return 0; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include diff --git a/SOURCES/glibc-RHEL-59494-3.patch b/SOURCES/glibc-RHEL-59494-3.patch new file mode 100644 index 0000000..d0fa23c --- /dev/null +++ b/SOURCES/glibc-RHEL-59494-3.patch @@ -0,0 +1,79 @@ +commit d5a3ca4061f7adc59196fa58e34eacebbebcbcfe +Author: Florian Weimer +Date: Thu Sep 19 15:40:05 2024 +0200 + + Implement run-built-tests=no for make xcheck, always build xtests + + Previously, the second occurrence of the xtests target + expected all xtests to run (as the result of specifying + $(xtests)), but these tests have not been run due to + the the first xtests target is set up for run-built-tests=no: + it only runs tests in $(xtests-special). Consequently, + xtests are reported as UNSUPPORTED with “make xcheck + run-built-tests=no”. The xtests were not built, either. + + After this change always, xtests are built regardless + of the $(run-built-tests) variable (except for xtests listed + in $(tests-unsupported)). To fix the UNSUPPORTED issue, + introduce xtests-expected and use that manage test + expectations in the second xtests target. + + Reviewed-by: Carlos O'Donell + +Conflicts: + Rules + (Missing malloc hugetlb support downstream) + +diff --git a/Rules b/Rules +index b1137afe71fbfe59..0516f4762c69bbe0 100644 +--- a/Rules ++++ b/Rules +@@ -146,37 +146,42 @@ endif + others: $(py-const) + + ifeq ($(run-built-tests),no) ++# The $(xtests) dependency ensures that xtests are always built. + tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \ +- $(tests) $(tests-internal) \ ++ $(tests) $(tests-internal) $(xtests) \ + $(tests-container)) \ + $(test-srcs)) $(tests-special) \ + $(tests-printers-programs) + xtests: tests $(xtests-special) +-else ++else # $(run-built-tests) != no ++# The $(xtests) dependency ensures that xtests are always built. + tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ ++ $(addprefix $(objpfx),$(filter-out $(tests-unsupported), $(xtests))) \ + $(tests-container:%=$(objpfx)%.out) \ + $(tests-mcheck:%=$(objpfx)%-mcheck.out) \ + $(tests-malloc-check:%=$(objpfx)%-malloc-check.out) \ + $(tests-special) $(tests-printers-out) + xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) +-endif ++endif # $(run-built-tests) != no + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) + xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special)) + ifeq ($(run-built-tests),no) + tests-expected = +-else ++xtests-expected = ++else # $(run-built-tests) != no + tests-expected = $(tests) $(tests-internal) $(tests-printers) \ + $(tests-container) $(tests-malloc-check:%=%-malloc-check) \ + $(tests-mcheck:%=%-mcheck) +-endif ++xtests-expected = $(xtests) ++endif # $(run-built-tests) != no + tests: + $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \ + $(sort $(tests-expected) $(tests-special-notdir:.out=)) \ + > $(objpfx)subdir-tests.sum + xtests: + $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \ +- $(sort $(xtests) $(xtests-special-notdir:.out=)) \ ++ $(sort $(xtests-expected) $(xtests-special-notdir:.out=)) \ + > $(objpfx)subdir-xtests.sum + + ifeq ($(build-programs),yes) diff --git a/SOURCES/glibc-RHEL-60466-1.patch b/SOURCES/glibc-RHEL-60466-1.patch new file mode 100644 index 0000000..c812640 --- /dev/null +++ b/SOURCES/glibc-RHEL-60466-1.patch @@ -0,0 +1,327 @@ +commit 2f47198b04a02097f438ecb765306fa39568a006 +Author: Rajalakshmi Srinivasaraghavan +Date: Fri Dec 2 14:26:41 2022 -0600 + + powerpc64: Remove old strncmp optimization + + This patch cleans up the power4 strncmp optimization for powerpc64 which + is unlikely to be used anywhere. + + Tested on ppc64le with and without --disable-multi-arch flag. + + Reviewed-by: Paul E. Murphy + Reviewed-by: Adhemerval Zanella + +Conflicts: + sysdeps/powerpc/powerpc64/multiarch/strncmp-power4.S + sysdeps/powerpc/powerpc64/power4/strncmp.S + (copyright year changes upstream) + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 626845a43c4e8ded..5b20dab108de14ab 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -12,8 +12,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strnlen-power8 strnlen-power7 strnlen-ppc64 \ + strcasecmp-power7 strcasecmp_l-power7 \ + strncase-power7 strncase_l-power7 \ +- strncmp-power8 strncmp-power7 \ +- strncmp-power4 strncmp-ppc64 \ ++ strncmp-power8 strncmp-power7 strncmp-ppc64 \ + strchr-power8 strchr-power7 strchr-ppc64 \ + strchrnul-power8 strchrnul-power7 strchrnul-ppc64 \ + strcpy-power8 strcpy-power7 strcpy-ppc64 stpcpy-power8 \ +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 7b83aa7b8ff28bb7..914e7d5e28a98b5d 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -177,8 +177,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + __strncmp_power8) + IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_ARCH_2_06, + __strncmp_power7) +- IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_POWER4, +- __strncmp_power4) + IFUNC_IMPL_ADD (array, i, strncmp, 1, + __strncmp_ppc)) + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power4.S b/sysdeps/powerpc/powerpc64/multiarch/strncmp-power4.S +deleted file mode 100644 +index 6ead3b6374749e6a..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power4.S ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* Copyright (C) 2013-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 +- . */ +- +-#define STRNCMP __strncmp_power4 +- +-#undef libc_hidden_builtin_def +-#define libc_hidden_builtin_def(name) +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +index 2d2112285445a450..275a558e4afa7d61 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +@@ -26,7 +26,6 @@ + # include "init-arch.h" + + extern __typeof (strncmp) __strncmp_ppc attribute_hidden; +-extern __typeof (strncmp) __strncmp_power4 attribute_hidden; + extern __typeof (strncmp) __strncmp_power7 attribute_hidden; + extern __typeof (strncmp) __strncmp_power8 attribute_hidden; + # ifdef __LITTLE_ENDIAN__ +@@ -46,7 +45,5 @@ libc_ifunc_redirected (__redirect_strncmp, strncmp, + ? __strncmp_power8 + : (hwcap & PPC_FEATURE_ARCH_2_06) + ? __strncmp_power7 +- : (hwcap & PPC_FEATURE_POWER4) +- ? __strncmp_power4 +- : __strncmp_ppc); ++ : __strncmp_ppc); + #endif +diff --git a/sysdeps/powerpc/powerpc64/power4/strncmp.S b/sysdeps/powerpc/powerpc64/power4/strncmp.S +deleted file mode 100644 +index cf5f4e5fb8fb2522..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/power4/strncmp.S ++++ /dev/null +@@ -1,225 +0,0 @@ +-/* Optimized strcmp implementation for PowerPC64. +- Copyright (C) 2003-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 +- . */ +- +-#include +- +-#ifndef STRNCMP +-# define STRNCMP strncmp +-#endif +- +-/* See strlen.s for comments on how the end-of-string testing works. */ +- +-/* int [r3] strncmp (const char *s1 [r3], const char *s2 [r4], size_t size [r5]) */ +- +-ENTRY_TOCLESS (STRNCMP, 4) +- CALL_MCOUNT 3 +- +-#define rTMP2 r0 +-#define rRTN r3 +-#define rSTR1 r3 /* first string arg */ +-#define rSTR2 r4 /* second string arg */ +-#define rN r5 /* max string length */ +-#define rWORD1 r6 /* current word in s1 */ +-#define rWORD2 r7 /* current word in s2 */ +-#define rWORD3 r10 +-#define rWORD4 r11 +-#define rFEFE r8 /* constant 0xfefefefefefefeff (-0x0101010101010101) */ +-#define r7F7F r9 /* constant 0x7f7f7f7f7f7f7f7f */ +-#define rNEG r10 /* ~(word in s1 | 0x7f7f7f7f7f7f7f7f) */ +-#define rBITDIF r11 /* bits that differ in s1 & s2 words */ +-#define rTMP r12 +- +- dcbt 0,rSTR1 +- or rTMP, rSTR2, rSTR1 +- lis r7F7F, 0x7f7f +- dcbt 0,rSTR2 +- clrldi. rTMP, rTMP, 61 +- cmpldi cr1, rN, 0 +- lis rFEFE, -0x101 +- bne L(unaligned) +-/* We are doubleword aligned so set up for two loops. first a double word +- loop, then fall into the byte loop if any residual. */ +- srdi. rTMP, rN, 3 +- clrldi rN, rN, 61 +- addi rFEFE, rFEFE, -0x101 +- addi r7F7F, r7F7F, 0x7f7f +- cmpldi cr1, rN, 0 +- beq L(unaligned) +- +- mtctr rTMP /* Power4 wants mtctr 1st in dispatch group. */ +- ld rWORD1, 0(rSTR1) +- ld rWORD2, 0(rSTR2) +- sldi rTMP, rFEFE, 32 +- insrdi r7F7F, r7F7F, 32, 0 +- add rFEFE, rFEFE, rTMP +- b L(g1) +- +-L(g0): +- ldu rWORD1, 8(rSTR1) +- bne- cr1, L(different) +- ldu rWORD2, 8(rSTR2) +-L(g1): add rTMP, rFEFE, rWORD1 +- nor rNEG, r7F7F, rWORD1 +- bdz L(tail) +- and. rTMP, rTMP, rNEG +- cmpd cr1, rWORD1, rWORD2 +- beq+ L(g0) +- +-/* OK. We've hit the end of the string. We need to be careful that +- we don't compare two strings as different because of gunk beyond +- the end of the strings... */ +- +-#ifdef __LITTLE_ENDIAN__ +-L(endstring): +- addi rTMP2, rTMP, -1 +- beq cr1, L(equal) +- andc rTMP2, rTMP2, rTMP +- rldimi rTMP2, rTMP2, 1, 0 +- and rWORD2, rWORD2, rTMP2 /* Mask off gunk. */ +- and rWORD1, rWORD1, rTMP2 +- cmpd cr1, rWORD1, rWORD2 +- beq cr1, L(equal) +- xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */ +- neg rNEG, rBITDIF +- and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */ +- cntlzd rNEG, rNEG /* bitcount of the bit. */ +- andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */ +- sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */ +- sld rWORD2, rWORD2, rNEG +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt- L(highbit) +- sradi rRTN, rRTN, 63 /* must return an int. */ +- ori rRTN, rRTN, 1 +- blr +-L(equal): +- li rRTN, 0 +- blr +- +-L(different): +- ld rWORD1, -8(rSTR1) +- xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */ +- neg rNEG, rBITDIF +- and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */ +- cntlzd rNEG, rNEG /* bitcount of the bit. */ +- andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */ +- sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */ +- sld rWORD2, rWORD2, rNEG +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt- L(highbit) +- sradi rRTN, rRTN, 63 +- ori rRTN, rRTN, 1 +- blr +-L(highbit): +- sradi rRTN, rWORD2, 63 +- ori rRTN, rRTN, 1 +- blr +- +-#else +-L(endstring): +- and rTMP, r7F7F, rWORD1 +- beq cr1, L(equal) +- add rTMP, rTMP, r7F7F +- xor. rBITDIF, rWORD1, rWORD2 +- andc rNEG, rNEG, rTMP +- blt- L(highbit) +- cntlzd rBITDIF, rBITDIF +- cntlzd rNEG, rNEG +- addi rNEG, rNEG, 7 +- cmpd cr1, rNEG, rBITDIF +- sub rRTN, rWORD1, rWORD2 +- blt- cr1, L(equal) +- sradi rRTN, rRTN, 63 /* must return an int. */ +- ori rRTN, rRTN, 1 +- blr +-L(equal): +- li rRTN, 0 +- blr +- +-L(different): +- ld rWORD1, -8(rSTR1) +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt- L(highbit) +- sradi rRTN, rRTN, 63 +- ori rRTN, rRTN, 1 +- blr +-L(highbit): +- sradi rRTN, rWORD2, 63 +- ori rRTN, rRTN, 1 +- blr +-#endif +- +-/* Oh well. In this case, we just do a byte-by-byte comparison. */ +- .align 4 +-L(tail): +- and. rTMP, rTMP, rNEG +- cmpd cr1, rWORD1, rWORD2 +- bne- L(endstring) +- addi rSTR1, rSTR1, 8 +- bne- cr1, L(different) +- addi rSTR2, rSTR2, 8 +- cmpldi cr1, rN, 0 +-L(unaligned): +- mtctr rN /* Power4 wants mtctr 1st in dispatch group */ +- ble cr1, L(ux) +-L(uz): +- lbz rWORD1, 0(rSTR1) +- lbz rWORD2, 0(rSTR2) +- .align 4 +-L(u1): +- cmpdi cr1, rWORD1, 0 +- bdz L(u4) +- cmpd rWORD1, rWORD2 +- beq- cr1, L(u4) +- bne- L(u4) +- lbzu rWORD3, 1(rSTR1) +- lbzu rWORD4, 1(rSTR2) +- cmpdi cr1, rWORD3, 0 +- bdz L(u3) +- cmpd rWORD3, rWORD4 +- beq- cr1, L(u3) +- bne- L(u3) +- lbzu rWORD1, 1(rSTR1) +- lbzu rWORD2, 1(rSTR2) +- cmpdi cr1, rWORD1, 0 +- bdz L(u4) +- cmpd rWORD1, rWORD2 +- beq- cr1, L(u4) +- bne- L(u4) +- lbzu rWORD3, 1(rSTR1) +- lbzu rWORD4, 1(rSTR2) +- cmpdi cr1, rWORD3, 0 +- bdz L(u3) +- cmpd rWORD3, rWORD4 +- beq- cr1, L(u3) +- bne- L(u3) +- lbzu rWORD1, 1(rSTR1) +- lbzu rWORD2, 1(rSTR2) +- b L(u1) +- +-L(u3): sub rRTN, rWORD3, rWORD4 +- blr +-L(u4): sub rRTN, rWORD1, rWORD2 +- blr +-L(ux): +- li rRTN, 0 +- blr +-END (STRNCMP) +-libc_hidden_builtin_def (strncmp) diff --git a/SOURCES/glibc-RHEL-60466-2.patch b/SOURCES/glibc-RHEL-60466-2.patch new file mode 100644 index 0000000..bc22daa --- /dev/null +++ b/SOURCES/glibc-RHEL-60466-2.patch @@ -0,0 +1,595 @@ +commit 92fdb11ae7aa1ab6b18622670ea702205cd6fdc5 +Author: Adhemerval Zanella Netto +Date: Tue Feb 28 14:23:59 2023 -0300 + + powerpc: Remove powerpc64 strncmp variants + + The default, and power7 implementation just adds word aligned + access when inputs have the same aligment. The unaligned case + is still done by byte operations. + + This is already covered by the generic implementation, which also add + the unaligned input optimization. + + Checked on powerpc64-linux-gnu built without multi-arch for powerpc64, + power7, power8, and power9 (build for le). + Reviewed-by: Rajalakshmi Srinivasaraghavan + +Conflicts: + sysdeps/powerpc/powerpc64/multiarch/strncmp-power7.S + sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.S + sysdeps/powerpc/powerpc64/power7/strncmp.S + sysdeps/powerpc/powerpc64/strncmp.S + (copyright year changes upstream) + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile +index 5b20dab108de14ab..0ee7ce39d6470d80 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile ++++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile +@@ -12,7 +12,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \ + strnlen-power8 strnlen-power7 strnlen-ppc64 \ + strcasecmp-power7 strcasecmp_l-power7 \ + strncase-power7 strncase_l-power7 \ +- strncmp-power8 strncmp-power7 strncmp-ppc64 \ ++ strncmp-power8 strncmp-ppc64 \ + strchr-power8 strchr-power7 strchr-ppc64 \ + strchrnul-power8 strchrnul-power7 strchrnul-ppc64 \ + strcpy-power8 strcpy-power7 strcpy-ppc64 stpcpy-power8 \ +diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +index 914e7d5e28a98b5d..2c84d287ee76a7ea 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +@@ -175,8 +175,6 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + #endif + IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_2_07, + __strncmp_power8) +- IFUNC_IMPL_ADD (array, i, strncmp, hwcap & PPC_FEATURE_ARCH_2_06, +- __strncmp_power7) + IFUNC_IMPL_ADD (array, i, strncmp, 1, + __strncmp_ppc)) + +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power7.S b/sysdeps/powerpc/powerpc64/multiarch/strncmp-power7.S +deleted file mode 100644 +index 8282ff076c9e00ce..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power7.S ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* Copyright (C) 2013-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 +- . */ +- +-#define STRNCMP __strncmp_power7 +- +-#undef libc_hidden_builtin_def +-#define libc_hidden_builtin_def(name) +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.S b/sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.S +deleted file mode 100644 +index c6f325650c9ace3b..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.S ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* Copyright (C) 2013-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 +- . */ +- +-#if defined SHARED && IS_IN (libc) +-# define STRNCMP __strncmp_ppc +- +-# undef libc_hidden_builtin_def +-# define libc_hidden_builtin_def(name) \ +- .globl __GI_strncmp; __GI_strncmp = __strncmp_ppc +-#endif +- +-#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.c +new file mode 100644 +index 0000000000000000..09cc009a913ed169 +--- /dev/null ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp-ppc64.c +@@ -0,0 +1,7 @@ ++#if defined SHARED && IS_IN (libc) ++# define STRNCMP __strncmp_ppc ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(name) \ ++ __hidden_ver1 (__strncmp_ppc, __GI_strncmp, __strncmp_ppc); ++#endif ++#include +diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +index 275a558e4afa7d61..df2c0707a919ad79 100644 +--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c ++++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c +@@ -26,7 +26,6 @@ + # include "init-arch.h" + + extern __typeof (strncmp) __strncmp_ppc attribute_hidden; +-extern __typeof (strncmp) __strncmp_power7 attribute_hidden; + extern __typeof (strncmp) __strncmp_power8 attribute_hidden; + # ifdef __LITTLE_ENDIAN__ + extern __typeof (strncmp) __strncmp_power9 attribute_hidden; +@@ -43,7 +42,5 @@ libc_ifunc_redirected (__redirect_strncmp, strncmp, + # endif + (hwcap2 & PPC_FEATURE2_ARCH_2_07) + ? __strncmp_power8 +- : (hwcap & PPC_FEATURE_ARCH_2_06) +- ? __strncmp_power7 +- : __strncmp_ppc); ++ : __strncmp_ppc); + #endif +diff --git a/sysdeps/powerpc/powerpc64/power7/strncmp.S b/sysdeps/powerpc/powerpc64/power7/strncmp.S +deleted file mode 100644 +index d91aeb6077a558f2..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/power7/strncmp.S ++++ /dev/null +@@ -1,228 +0,0 @@ +-/* Optimized strcmp implementation for POWER7/PowerPC64. +- Copyright (C) 2010-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 +- . */ +- +-#include +- +-#ifndef STRNCMP +-# define STRNCMP strncmp +-#endif +- +-/* See strlen.s for comments on how the end-of-string testing works. */ +- +-/* int [r3] strncmp (const char *s1 [r3], +- const char *s2 [r4], +- size_t size [r5]) */ +- +- .machine power7 +-ENTRY_TOCLESS (STRNCMP, 5) +- CALL_MCOUNT 3 +- +-#define rTMP2 r0 +-#define rRTN r3 +-#define rSTR1 r3 /* first string arg */ +-#define rSTR2 r4 /* second string arg */ +-#define rN r5 /* max string length */ +-#define rWORD1 r6 /* current word in s1 */ +-#define rWORD2 r7 /* current word in s2 */ +-#define rWORD3 r10 +-#define rWORD4 r11 +-#define rFEFE r8 /* constant 0xfefefefefefefeff (-0x0101010101010101) */ +-#define r7F7F r9 /* constant 0x7f7f7f7f7f7f7f7f */ +-#define rNEG r10 /* ~(word in s1 | 0x7f7f7f7f7f7f7f7f) */ +-#define rBITDIF r11 /* bits that differ in s1 & s2 words */ +-#define rTMP r12 +- +- dcbt 0,rSTR1 +- nop +- or rTMP,rSTR2,rSTR1 +- lis r7F7F,0x7f7f +- dcbt 0,rSTR2 +- nop +- clrldi. rTMP,rTMP,61 +- cmpldi cr1,rN,0 +- lis rFEFE,-0x101 +- bne L(unaligned) +-/* We are doubleword aligned so set up for two loops. first a double word +- loop, then fall into the byte loop if any residual. */ +- srdi. rTMP,rN,3 +- clrldi rN,rN,61 +- addi rFEFE,rFEFE,-0x101 +- addi r7F7F,r7F7F,0x7f7f +- cmpldi cr1,rN,0 +- beq L(unaligned) +- +- mtctr rTMP +- ld rWORD1,0(rSTR1) +- ld rWORD2,0(rSTR2) +- sldi rTMP,rFEFE,32 +- insrdi r7F7F,r7F7F,32,0 +- add rFEFE,rFEFE,rTMP +- b L(g1) +- +-L(g0): +- ldu rWORD1,8(rSTR1) +- bne cr1,L(different) +- ldu rWORD2,8(rSTR2) +-L(g1): add rTMP,rFEFE,rWORD1 +- nor rNEG,r7F7F,rWORD1 +- bdz L(tail) +- and. rTMP,rTMP,rNEG +- cmpd cr1,rWORD1,rWORD2 +- beq L(g0) +- +-/* OK. We've hit the end of the string. We need to be careful that +- we don't compare two strings as different because of gunk beyond +- the end of the strings... */ +- +-#ifdef __LITTLE_ENDIAN__ +-L(endstring): +- addi rTMP2, rTMP, -1 +- beq cr1, L(equal) +- andc rTMP2, rTMP2, rTMP +- rldimi rTMP2, rTMP2, 1, 0 +- and rWORD2, rWORD2, rTMP2 /* Mask off gunk. */ +- and rWORD1, rWORD1, rTMP2 +- cmpd cr1, rWORD1, rWORD2 +- beq cr1, L(equal) +- cmpb rBITDIF, rWORD1, rWORD2 /* 0xff on equal bytes. */ +- addi rNEG, rBITDIF, 1 +- orc rNEG, rNEG, rBITDIF /* 0's below LS differing byte. */ +- sldi rNEG, rNEG, 8 /* 1's above LS differing byte. */ +- andc rWORD1, rWORD1, rNEG /* mask off MS bytes. */ +- andc rWORD2, rWORD2, rNEG +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt L(highbit) +- sradi rRTN, rRTN, 63 /* must return an int. */ +- ori rRTN, rRTN, 1 +- blr +-L(equal): +- li rRTN, 0 +- blr +- +-L(different): +- ld rWORD1, -8(rSTR1) +- cmpb rBITDIF, rWORD1, rWORD2 /* 0xff on equal bytes. */ +- addi rNEG, rBITDIF, 1 +- orc rNEG, rNEG, rBITDIF /* 0's below LS differing byte. */ +- sldi rNEG, rNEG, 8 /* 1's above LS differing byte. */ +- andc rWORD1, rWORD1, rNEG /* mask off MS bytes. */ +- andc rWORD2, rWORD2, rNEG +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt L(highbit) +- sradi rRTN, rRTN, 63 +- ori rRTN, rRTN, 1 +- blr +-L(highbit): +- sradi rRTN, rWORD2, 63 +- ori rRTN, rRTN, 1 +- blr +- +-#else +-L(endstring): +- and rTMP,r7F7F,rWORD1 +- beq cr1,L(equal) +- add rTMP,rTMP,r7F7F +- xor. rBITDIF,rWORD1,rWORD2 +- andc rNEG,rNEG,rTMP +- blt L(highbit) +- cntlzd rBITDIF,rBITDIF +- cntlzd rNEG,rNEG +- addi rNEG,rNEG,7 +- cmpd cr1,rNEG,rBITDIF +- sub rRTN,rWORD1,rWORD2 +- blt cr1,L(equal) +- sradi rRTN,rRTN,63 /* must return an int. */ +- ori rRTN,rRTN,1 +- blr +-L(equal): +- li rRTN,0 +- blr +- +-L(different): +- ld rWORD1,-8(rSTR1) +- xor. rBITDIF,rWORD1,rWORD2 +- sub rRTN,rWORD1,rWORD2 +- blt L(highbit) +- sradi rRTN,rRTN,63 +- ori rRTN,rRTN,1 +- blr +-L(highbit): +- sradi rRTN,rWORD2,63 +- ori rRTN,rRTN,1 +- blr +-#endif +- +-/* Oh well. In this case, we just do a byte-by-byte comparison. */ +- .align 4 +-L(tail): +- and. rTMP,rTMP,rNEG +- cmpd cr1,rWORD1,rWORD2 +- bne L(endstring) +- addi rSTR1,rSTR1,8 +- bne cr1,L(different) +- addi rSTR2,rSTR2,8 +- cmpldi cr1,rN,0 +-L(unaligned): +- mtctr rN +- ble cr1,L(ux) +-L(uz): +- lbz rWORD1,0(rSTR1) +- lbz rWORD2,0(rSTR2) +- .align 4 +-L(u1): +- cmpdi cr1,rWORD1,0 +- bdz L(u4) +- cmpd rWORD1,rWORD2 +- beq cr1,L(u4) +- bne L(u4) +- lbzu rWORD3,1(rSTR1) +- lbzu rWORD4,1(rSTR2) +- cmpdi cr1,rWORD3,0 +- bdz L(u3) +- cmpd rWORD3,rWORD4 +- beq cr1,L(u3) +- bne L(u3) +- lbzu rWORD1,1(rSTR1) +- lbzu rWORD2,1(rSTR2) +- cmpdi cr1,rWORD1,0 +- bdz L(u4) +- cmpd rWORD1,rWORD2 +- beq cr1,L(u4) +- bne L(u4) +- lbzu rWORD3,1(rSTR1) +- lbzu rWORD4,1(rSTR2) +- cmpdi cr1,rWORD3,0 +- bdz L(u3) +- cmpd rWORD3,rWORD4 +- beq cr1,L(u3) +- bne L(u3) +- lbzu rWORD1,1(rSTR1) +- lbzu rWORD2,1(rSTR2) +- b L(u1) +- +-L(u3): sub rRTN,rWORD3,rWORD4 +- blr +-L(u4): sub rRTN,rWORD1,rWORD2 +- blr +-L(ux): +- li rRTN,0 +- blr +-END (STRNCMP) +-libc_hidden_builtin_def (strncmp) +diff --git a/sysdeps/powerpc/powerpc64/strncmp.S b/sysdeps/powerpc/powerpc64/strncmp.S +deleted file mode 100644 +index 40a230242cbdf733..0000000000000000 +--- a/sysdeps/powerpc/powerpc64/strncmp.S ++++ /dev/null +@@ -1,210 +0,0 @@ +-/* Optimized strcmp implementation for PowerPC64. +- Copyright (C) 2003-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 +- . */ +- +-#include +- +-/* See strlen.s for comments on how the end-of-string testing works. */ +- +-/* int [r3] strncmp (const char *s1 [r3], const char *s2 [r4], size_t size [r5]) */ +- +-#ifndef STRNCMP +-# define STRNCMP strncmp +-#endif +- +-ENTRY_TOCLESS (STRNCMP, 4) +- CALL_MCOUNT 3 +- +-#define rTMP2 r0 +-#define rRTN r3 +-#define rSTR1 r3 /* first string arg */ +-#define rSTR2 r4 /* second string arg */ +-#define rN r5 /* max string length */ +-#define rWORD1 r6 /* current word in s1 */ +-#define rWORD2 r7 /* current word in s2 */ +-#define rFEFE r8 /* constant 0xfefefefefefefeff (-0x0101010101010101) */ +-#define r7F7F r9 /* constant 0x7f7f7f7f7f7f7f7f */ +-#define rNEG r10 /* ~(word in s1 | 0x7f7f7f7f7f7f7f7f) */ +-#define rBITDIF r11 /* bits that differ in s1 & s2 words */ +-#define rTMP r12 +- +- dcbt 0,rSTR1 +- or rTMP, rSTR2, rSTR1 +- lis r7F7F, 0x7f7f +- dcbt 0,rSTR2 +- clrldi. rTMP, rTMP, 61 +- cmpldi cr1, rN, 0 +- lis rFEFE, -0x101 +- bne L(unaligned) +-/* We are doubleword aligned so set up for two loops. first a double word +- loop, then fall into the byte loop if any residual. */ +- srdi. rTMP, rN, 3 +- clrldi rN, rN, 61 +- addi rFEFE, rFEFE, -0x101 +- addi r7F7F, r7F7F, 0x7f7f +- cmpldi cr1, rN, 0 +- beq L(unaligned) +- +- mtctr rTMP /* Power4 wants mtctr 1st in dispatch group. */ +- ld rWORD1, 0(rSTR1) +- ld rWORD2, 0(rSTR2) +- sldi rTMP, rFEFE, 32 +- insrdi r7F7F, r7F7F, 32, 0 +- add rFEFE, rFEFE, rTMP +- b L(g1) +- +-L(g0): +- ldu rWORD1, 8(rSTR1) +- bne- cr1, L(different) +- ldu rWORD2, 8(rSTR2) +-L(g1): add rTMP, rFEFE, rWORD1 +- nor rNEG, r7F7F, rWORD1 +- bdz L(tail) +- and. rTMP, rTMP, rNEG +- cmpd cr1, rWORD1, rWORD2 +- beq+ L(g0) +- +-/* OK. We've hit the end of the string. We need to be careful that +- we don't compare two strings as different because of gunk beyond +- the end of the strings... */ +- +-#ifdef __LITTLE_ENDIAN__ +-L(endstring): +- addi rTMP2, rTMP, -1 +- beq cr1, L(equal) +- andc rTMP2, rTMP2, rTMP +- rldimi rTMP2, rTMP2, 1, 0 +- and rWORD2, rWORD2, rTMP2 /* Mask off gunk. */ +- and rWORD1, rWORD1, rTMP2 +- cmpd cr1, rWORD1, rWORD2 +- beq cr1, L(equal) +- xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */ +- neg rNEG, rBITDIF +- and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */ +- cntlzd rNEG, rNEG /* bitcount of the bit. */ +- andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */ +- sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */ +- sld rWORD2, rWORD2, rNEG +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt- L(highbit) +- sradi rRTN, rRTN, 63 /* must return an int. */ +- ori rRTN, rRTN, 1 +- blr +-L(equal): +- li rRTN, 0 +- blr +- +-L(different): +- ld rWORD1, -8(rSTR1) +- xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */ +- neg rNEG, rBITDIF +- and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */ +- cntlzd rNEG, rNEG /* bitcount of the bit. */ +- andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */ +- sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */ +- sld rWORD2, rWORD2, rNEG +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt- L(highbit) +- sradi rRTN, rRTN, 63 +- ori rRTN, rRTN, 1 +- blr +-L(highbit): +- sradi rRTN, rWORD2, 63 +- ori rRTN, rRTN, 1 +- blr +- +-#else +-L(endstring): +- and rTMP, r7F7F, rWORD1 +- beq cr1, L(equal) +- add rTMP, rTMP, r7F7F +- xor. rBITDIF, rWORD1, rWORD2 +- andc rNEG, rNEG, rTMP +- blt- L(highbit) +- cntlzd rBITDIF, rBITDIF +- cntlzd rNEG, rNEG +- addi rNEG, rNEG, 7 +- cmpd cr1, rNEG, rBITDIF +- sub rRTN, rWORD1, rWORD2 +- blt- cr1, L(equal) +- sradi rRTN, rRTN, 63 /* must return an int. */ +- ori rRTN, rRTN, 1 +- blr +-L(equal): +- li rRTN, 0 +- blr +- +-L(different): +- ld rWORD1, -8(rSTR1) +- xor. rBITDIF, rWORD1, rWORD2 +- sub rRTN, rWORD1, rWORD2 +- blt- L(highbit) +- sradi rRTN, rRTN, 63 +- ori rRTN, rRTN, 1 +- blr +-L(highbit): +- sradi rRTN, rWORD2, 63 +- ori rRTN, rRTN, 1 +- blr +-#endif +- +-/* Oh well. In this case, we just do a byte-by-byte comparison. */ +- .align 4 +-L(tail): +- and. rTMP, rTMP, rNEG +- cmpd cr1, rWORD1, rWORD2 +- bne- L(endstring) +- addi rSTR1, rSTR1, 8 +- bne- cr1, L(different) +- addi rSTR2, rSTR2, 8 +- cmpldi cr1, rN, 0 +-L(unaligned): +- mtctr rN /* Power4 wants mtctr 1st in dispatch group */ +- bgt cr1, L(uz) +-L(ux): +- li rRTN, 0 +- blr +- .align 4 +-L(uz): +- lbz rWORD1, 0(rSTR1) +- lbz rWORD2, 0(rSTR2) +- nop +- b L(u1) +-L(u0): +- lbzu rWORD2, 1(rSTR2) +-L(u1): +- bdz L(u3) +- cmpdi cr1, rWORD1, 0 +- cmpd rWORD1, rWORD2 +- beq- cr1, L(u3) +- lbzu rWORD1, 1(rSTR1) +- bne- L(u2) +- lbzu rWORD2, 1(rSTR2) +- bdz L(u3) +- cmpdi cr1, rWORD1, 0 +- cmpd rWORD1, rWORD2 +- bne- L(u3) +- lbzu rWORD1, 1(rSTR1) +- bne+ cr1, L(u0) +- +-L(u2): lbzu rWORD1, -1(rSTR1) +-L(u3): sub rRTN, rWORD1, rWORD2 +- blr +-END (STRNCMP) +-libc_hidden_builtin_def (strncmp) diff --git a/SOURCES/glibc-RHEL-61559-1.patch b/SOURCES/glibc-RHEL-61559-1.patch new file mode 100644 index 0000000..71eff05 --- /dev/null +++ b/SOURCES/glibc-RHEL-61559-1.patch @@ -0,0 +1,394 @@ +commit b600f47758332d78f04daa970b02a4044a37ebd9 +Author: Carlos O'Donell +Date: Wed May 17 08:27:59 2023 -0400 + + nptl: Reformat Makefile. + + Reflow all long lines adding comment terminators. + Rename files that cause inconsistent ordering. + Sort all reflowed text using scripts/sort-makefile-lines.py. + + No code generation changes observed in binary artifacts. + No regressions on x86_64 and i686. + +Conflicts: + nptl/Makefile + (different list of tests) + +diff --git a/nptl/Makefile b/nptl/Makefile +index f89bb07747cf5522..eec8563f95a42554 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -202,6 +202,7 @@ routines = \ + tpp \ + unwind \ + vars \ ++ # routines + + static-only-routines = pthread_atfork + libpthread-routines = libpthread-compat +@@ -265,70 +266,133 @@ LDLIBS-tst-thread-exit-clobber = -lstdc++ + CFLAGS-tst-minstack-throw.o = -std=gnu++11 + LDLIBS-tst-minstack-throw = -lstdc++ + +-tests = tst-attr2 tst-attr3 tst-default-attr \ +- tst-mutex5a tst-mutex7a \ +- tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \ +- tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ +- tst-mutexpi9 tst-mutexpi10 \ +- tst-cond22 tst-cond26 \ +- tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 tst-robustpi5 \ +- tst-robustpi6 tst-robustpi7 tst-robustpi9 \ +- tst-rwlock2 tst-rwlock2a tst-rwlock2b tst-rwlock3 \ +- tst-rwlock6 tst-rwlock7 tst-rwlock8 \ +- tst-rwlock9 tst-rwlock10 tst-rwlock11 \ +- tst-rwlock15 tst-rwlock17 tst-rwlock18 \ +- tst-once5 \ +- tst-sem17 \ +- tst-tsd3 tst-tsd4 \ +- tst-cancel4_1 tst-cancel4_2 \ +- tst-cancel7 tst-cancel17 tst-cancel24 \ +- tst-signal3 \ +- tst-exec4 tst-exec5 \ +- tst-stack2 tst-stack3 tst-stack4 \ +- tst-pthread-attr-affinity \ +- tst-pthread-attr-affinity-fail \ +- tst-dlsym1 \ +- tst-context1 \ +- tst-sched1 \ +- tst-initializers1 $(addprefix tst-initializers1-,\ +- c89 gnu89 c99 gnu99 c11 gnu11) \ +- tst-thread_local1 \ +- tst-robust-fork \ +- tst-thread-exit-clobber tst-minstack-cancel tst-minstack-exit \ +- tst-minstack-throw \ +- tst-rwlock-pwn \ +- tst-thread-affinity-pthread \ +- tst-thread-affinity-pthread2 \ +- tst-thread-affinity-sched \ +- tst-pthread-defaultattr-free \ +- tst-pthread-attr-sigmask \ +- tst-pthread-timedlock-lockloop \ +- tst-pthread-gdb-attach tst-pthread-gdb-attach-static \ +- tst-pthread_exit-nothreads \ +- tst-pthread_exit-nothreads-static \ +- tst-thread-setspecific \ ++tests = \ ++ tst-attr2 \ ++ tst-attr3 \ ++ tst-cancel4_1 \ ++ tst-cancel4_2 \ ++ tst-cancel7 \ ++ tst-cancel17 \ ++ tst-cancel24 \ ++ tst-cond22 \ ++ tst-cond26 \ ++ tst-context1 \ ++ tst-default-attr \ ++ tst-dlsym1 \ ++ tst-exec4 \ ++ tst-exec5 \ ++ tst-initializers1 \ ++ tst-initializers1-c11 \ ++ tst-initializers1-c89 \ ++ tst-initializers1-c99 \ ++ tst-initializers1-gnu11 \ ++ tst-initializers1-gnu89 \ ++ tst-initializers1-gnu99 \ ++ tst-minstack-cancel \ ++ tst-minstack-exit \ ++ tst-minstack-throw \ ++ tst-mutex5a \ ++ tst-mutex7a \ ++ tst-mutexpi1 \ ++ tst-mutexpi2 \ ++ tst-mutexpi3 \ ++ tst-mutexpi4 \ ++ tst-mutexpi5 \ ++ tst-mutexpi6 \ ++ tst-mutexpi7 \ ++ tst-mutexpi9 \ ++ tst-mutexpi10 \ ++ tst-mutexpi11 \ ++ tst-mutexpi12 \ ++ tst-once5 \ ++ tst-pthread-attr-affinity \ ++ tst-pthread-attr-affinity-fail \ ++ tst-pthread-attr-sigmask \ ++ tst-pthread-defaultattr-free \ ++ tst-pthread-gdb-attach \ ++ tst-pthread-gdb-attach-static \ + tst-pthread-getcpuclockid-invalid \ ++ tst-pthread-timedlock-lockloop \ ++ tst-pthread_exit-nothreads \ ++ tst-pthread_exit-nothreads-static \ ++ tst-robust-fork \ ++ tst-robustpi1 \ ++ tst-robustpi2 \ ++ tst-robustpi3 \ ++ tst-robustpi4 \ ++ tst-robustpi5 \ ++ tst-robustpi6 \ ++ tst-robustpi7 \ ++ tst-robustpi9 \ ++ tst-rwlock-pwn \ ++ tst-rwlock2 \ ++ tst-rwlock3 \ ++ tst-rwlock6 \ ++ tst-rwlock7 \ ++ tst-rwlock8 \ ++ tst-rwlock9 \ ++ tst-rwlock10 \ ++ tst-rwlock11 \ ++ tst-rwlock15 \ ++ tst-rwlock17 \ ++ tst-rwlock18 \ ++ tst-rwlock21 \ ++ tst-rwlock22 \ ++ tst-sched1 \ ++ tst-sem17 \ ++ tst-signal3 \ ++ tst-stack2 \ ++ tst-stack3 \ ++ tst-stack4 \ ++ tst-thread-affinity-pthread \ ++ tst-thread-affinity-pthread2 \ ++ tst-thread-affinity-sched \ ++ tst-thread-exit-clobber \ ++ tst-thread-setspecific \ ++ tst-thread_local1 \ ++ tst-tsd3 \ ++ tst-tsd4 \ ++ # tests + + tests-nolibpthread = \ + tst-pthread_exit-nothreads \ + tst-pthread_exit-nothreads-static \ ++ # tests-nolibpthread + + tests-container = tst-pthread-getattr + +-tests-internal := tst-robustpi8 tst-rwlock19 tst-rwlock20 \ +- tst-sem11 tst-sem12 tst-sem13 \ +- tst-barrier5 tst-signal7 tst-mutex8 tst-mutex8-static \ +- tst-mutexpi8 tst-mutexpi8-static \ +- tst-setgetname \ +- tst-nptl-padding \ +- # tests-internal +- +-xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ +- tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 tst-setgroups \ +- tst-mutexpp5 tst-mutexpp9 ++tests-internal := \ ++ tst-barrier5 \ ++ tst-mutex8 \ ++ tst-mutex8-static \ ++ tst-mutexpi8 \ ++ tst-mutexpi8-static \ ++ tst-nptl-padding \ ++ tst-robustpi8 \ ++ tst-rwlock19 \ ++ tst-rwlock20 \ ++ tst-sem11 \ ++ tst-sem12 \ ++ tst-sem13 \ ++ tst-setgetname \ ++ tst-signal7 \ ++ # tests-internal ++ ++xtests = \ ++ tst-mutexpp1 \ ++ tst-mutexpp5 \ ++ tst-mutexpp6 \ ++ tst-mutexpp9 \ ++ tst-mutexpp10 \ ++ tst-setgroups \ ++ tst-setuid1 \ ++ tst-setuid1-static \ ++ tst-setuid2 \ ++ # xtests + + tests-time64 := \ + tst-cancel4_2-time64 ++ # tests-time64 + + # This test can run into task limits because of a linux kernel bug + # and then cause the make process to fail too, see bug 24537. +@@ -341,9 +405,14 @@ gen-as-const-headers = unwindbuf.sym \ + + gen-py-const-headers := nptl_lock_constants.pysym + pretty-printers := nptl-printers.py +-tests-printers := test-mutexattr-printers test-mutex-printers \ +- test-condattr-printers test-cond-printers \ +- test-rwlockattr-printers test-rwlock-printers ++tests-printers := \ ++ test-cond-printers \ ++ test-condattr-printers \ ++ test-mutex-printers \ ++ test-mutexattr-printers \ ++ test-rwlock-printers \ ++ test-rwlockattr-printers \ ++ # tests-printers + + # We must specify both CFLAGS and CPPFLAGS to override any + # compiler options the user might have provided that conflict +@@ -378,25 +447,51 @@ CPPFLAGS-tst-pthread-gdb-attach-static.c := \ + # were launched with an explicit ld.so invocation. + tst-pthread-gdb-attach-no-pie = yes + +-tests += tst-cancelx7 tst-cancelx17 ++tests += \ ++ tst-cancelx7 \ ++ tst-cancelx17 \ ++ # tests + + ifeq ($(build-shared),yes) +-tests += tst-compat-forwarder tst-audit-threads +-tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1 ++tests += \ ++ tst-audit-threads \ ++ tst-compat-forwarder \ ++ # tests ++tests-internal += \ ++ tst-stackguard1 \ ++ tst-tls3 \ ++ tst-tls3-malloc \ ++ tst-tls5 \ ++ # tests-internal + ifeq ($(have-z-execstack),yes) + tests += tst-execstack + endif + endif + +-modules-names = tst-tls3mod \ +- tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ +- tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \ +- tst-execstack-mod \ +- tst-compat-forwarder-mod tst-audit-threads-mod1 \ +- tst-audit-threads-mod2 +-extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \ +- tst-cleanup4aux.o tst-cleanupx4aux.o +-test-extras += tst-cleanup4aux tst-cleanupx4aux ++modules-names = \ ++ tst-audit-threads-mod1 \ ++ tst-audit-threads-mod2 \ ++ tst-compat-forwarder-mod \ ++ tst-execstack-mod \ ++ tst-stack4mod \ ++ tst-tls3mod \ ++ tst-tls5mod \ ++ tst-tls5moda \ ++ tst-tls5modb \ ++ tst-tls5modc \ ++ tst-tls5modd \ ++ tst-tls5mode \ ++ tst-tls5modf \ ++ # modules-names ++extra-test-objs += \ ++ $(addsuffix .os,$(strip $(modules-names))) \ ++ tst-cleanup4aux.o \ ++ tst-cleanupx4aux.o \ ++ # extra-test-objs ++test-extras += \ ++ tst-cleanup4aux \ ++ tst-cleanupx4aux \ ++ # test-extras + + # This test exercises compat symbols removed in glibc 2.34. + ifdef have-GLIBC_2.33 +@@ -434,20 +529,31 @@ CFLAGS-funlockfile.c += $(libio-mtsafe) + link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \ + $(common-objpfx)libc.a + +-tests-static += tst-stackguard1-static \ +- tst-cancel24-static \ +- tst-mutex8-static tst-mutexpi8-static tst-sem11-static \ +- tst-sem12-static tst-cond11-static \ +- tst-pthread-gdb-attach-static \ +- tst-pthread_exit-nothreads-static ++tests-static += \ ++ tst-cancel24-static \ ++ tst-mutex8-static \ ++ tst-mutexpi8-static \ ++ tst-pthread-gdb-attach-static \ ++ tst-pthread_exit-nothreads-static \ ++ tst-sem11-static \ ++ tst-sem12-static tst-cond11-static \ ++ tst-stackguard1-static \ ++ # tests-static + + tests += tst-cancel24-static + +-tests-internal += tst-sem11-static tst-sem12-static tst-stackguard1-static ++tests-internal += \ ++ tst-sem11-static \ ++ tst-sem12-static \ ++ tst-stackguard1-static \ ++ # tests-internal + xtests-static += tst-setuid1-static + + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-stack3-mem.out $(objpfx)tst-oddstacklimit.out ++tests-special += \ ++ $(objpfx)tst-oddstacklimit.out \ ++ $(objpfx)tst-stack3-mem.out \ ++ # tests-special + ifeq ($(build-shared),yes) + tests-special += $(objpfx)tst-tls6.out + endif +@@ -455,8 +561,13 @@ endif + + ifeq (,$(CXX)) + # These tests require a C++ compiler and runtime. +-tests-unsupported += tst-cancel24 tst-cancel24-static tst-once5 \ +- tst-thread-exit-clobber tst-minstack-throw ++tests-unsupported += \ ++ tst-cancel24 \ ++ tst-cancel24-static \ ++ tst-minstack-throw \ ++ tst-once5 \ ++ tst-thread-exit-clobber \ ++ # tests-unsupported + endif + # These tests require a C++ compiler and runtime with thread_local support. + ifneq ($(have-cxx-thread_local),yes) +@@ -502,7 +613,10 @@ tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace \ + $(objpfx)tst-stack3-mem.out: $(objpfx)tst-stack3.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@; \ + $(evaluate-test) +-generated += tst-stack3-mem.out tst-stack3.mtrace ++generated += \ ++ tst-stack3-mem.out \ ++ tst-stack3.mtrace \ ++ # generated + + tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \ + 11 12 13 14 15 16 17 18 19; do \ +@@ -544,7 +658,10 @@ LDLIBS-tst-cancel24-static = $(LDLIBS-tst-cancel24) + + ifeq ($(build-shared),yes) + +-generated += multidir.mk tst-tls6.out ++generated += \ ++ multidir.mk \ ++ tst-tls6.out \ ++ # generated + endif + + tst-exec4-ARGS = $(host-test-program-cmd) +diff --git a/nptl/tst-mutexpi5a.c b/nptl/tst-mutexpi11.c +similarity index 100% +rename from nptl/tst-mutexpi5a.c +rename to nptl/tst-mutexpi11.c +diff --git a/nptl/tst-mutexpi7a.c b/nptl/tst-mutexpi12.c +similarity index 100% +rename from nptl/tst-mutexpi7a.c +rename to nptl/tst-mutexpi12.c +diff --git a/nptl/tst-rwlock2a.c b/nptl/tst-rwlock21.c +similarity index 100% +rename from nptl/tst-rwlock2a.c +rename to nptl/tst-rwlock21.c +diff --git a/nptl/tst-rwlock2b.c b/nptl/tst-rwlock22.c +similarity index 100% +rename from nptl/tst-rwlock2b.c +rename to nptl/tst-rwlock22.c diff --git a/SOURCES/glibc-RHEL-61559-2.patch b/SOURCES/glibc-RHEL-61559-2.patch new file mode 100644 index 0000000..619d976 --- /dev/null +++ b/SOURCES/glibc-RHEL-61559-2.patch @@ -0,0 +1,353 @@ +commit e41aabcc93edd6c9a6acb15212b2783d8a7ec5a3 +Author: Siddhesh Poyarekar +Date: Mon Dec 16 08:14:09 2024 -0500 + + tests: Verify inheritance of cpu affinity + + Add a couple of tests to verify that CPU affinity set using + sched_setaffinity and pthread_setaffinity_np are inherited by a child + process and child thread. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +Conflicts: + sysdeps/unix/sysv/linux/Makefile + (test list has not been reformatted downstream) + +diff --git a/nptl/Makefile b/nptl/Makefile +index eec8563f95a42554..455703bbd763d516 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -305,6 +305,7 @@ tests = \ + tst-mutexpi11 \ + tst-mutexpi12 \ + tst-once5 \ ++ tst-pthread-affinity-inheritance \ + tst-pthread-attr-affinity \ + tst-pthread-attr-affinity-fail \ + tst-pthread-attr-sigmask \ +diff --git a/nptl/tst-pthread-affinity-inheritance.c b/nptl/tst-pthread-affinity-inheritance.c +new file mode 100644 +index 0000000000000000..c020530dd916dea1 +--- /dev/null ++++ b/nptl/tst-pthread-affinity-inheritance.c +@@ -0,0 +1,71 @@ ++/* CPU Affinity inheritance test - pthread_{gs}etaffinity_np. ++ 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 ++ . */ ++ ++/* See top level comment in nptl/tst-skeleton-affinity-inheritance.c for a ++ description of this test. */ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++set_my_affinity (size_t size, const cpu_set_t *set) ++{ ++ int ret = pthread_setaffinity_np (pthread_self (), size, set); ++ ++ if (ret != 0) ++ FAIL ("pthread_setaffinity_np returned %d (%s)", ret, strerror (ret)); ++} ++ ++static void ++verify_my_affinity (int nproc, size_t size, const cpu_set_t *expected_set) ++{ ++ cpu_set_t *set = CPU_ALLOC (nproc); ++ cpu_set_t *xor_set = CPU_ALLOC (nproc); ++ ++ if (set == NULL || xor_set== NULL) ++ FAIL_EXIT1 ("verify_my_affinity: Failed to allocate cpuset: %m\n"); ++ ++ int ret = pthread_getaffinity_np (pthread_self (), size, set); ++ if (ret != 0) ++ FAIL ("pthread_getaffinity_np returned %d (%s)", ret, strerror (ret)); ++ ++ CPU_XOR_S (size, xor_set, expected_set, set); ++ ++ int cpucount = CPU_COUNT_S (size, xor_set); ++ ++ if (cpucount > 0) ++ { ++ FAIL ("Affinity mask not inherited, " ++ "following %d CPUs mismatched in the expected and actual sets: ", ++ cpucount); ++ for (int cur = 0; cur < nproc && cpucount >= 0; cur++) ++ if (CPU_ISSET_S (size, cur, xor_set)) ++ { ++ printf ("%d ", cur); ++ cpucount--; ++ } ++ printf ("\n"); ++ } ++ ++ CPU_FREE (set); ++ CPU_FREE (xor_set); ++} ++ ++#include "tst-skeleton-affinity-inheritance.c" +diff --git a/nptl/tst-skeleton-affinity-inheritance.c b/nptl/tst-skeleton-affinity-inheritance.c +new file mode 100644 +index 0000000000000000..6de6d9c9428a0c9d +--- /dev/null ++++ b/nptl/tst-skeleton-affinity-inheritance.c +@@ -0,0 +1,152 @@ ++/* CPU Affinity inheritance test - common infrastructure. ++ 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 ++ . */ ++ ++/* The general idea of this test is to verify that the set of CPUs assigned to ++ a task gets inherited by a child (thread or process) of that task. This is ++ a framework that is included by specific APIs for the test, e.g. ++ sched_getaffinity/sched_setaffinity and ++ pthread_setaffinity_np/pthread_getaffinity_np. This is a framework, actual ++ tests entry points are in nptl/tst-pthread-affinity-inheritance.c and ++ sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c. ++ ++ There are two levels to the test with two different CPU masks. The first ++ level verifies that the affinity set on the main process is inherited by its ++ children subprocess or thread. The second level verifies that a subprocess ++ or subthread passes on its affinity to their respective subprocess or ++ subthread. We set a slightly different mask in both levels to ensure that ++ they're both inherited. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct test_param ++{ ++ int nproc; ++ cpu_set_t *set; ++ size_t size; ++ bool entry; ++}; ++ ++void __attribute__((noinline)) ++set_cpu_mask (struct test_param *param, bool entry) ++{ ++ int cpus = param->nproc; ++ ++ /* Less CPUS for the first level, if that's possible. */ ++ if (entry && cpus > 1) ++ cpus--; ++ ++ CPU_ZERO_S (param->size, param->set); ++ while (cpus > 0) ++ CPU_SET_S (--cpus, param->size, param->set); ++ ++ if (CPU_COUNT_S (param->size, param->set) == 0) ++ FAIL_EXIT1 ("Failed to add any CPUs to the affinity set\n"); ++} ++ ++static void * ++child_test (void *arg) ++{ ++ struct test_param *param = arg; ++ ++ printf ("%d:%d child\n", getpid (), gettid ()); ++ verify_my_affinity (param->nproc, param->size, param->set); ++ return NULL; ++} ++ ++void * ++do_one_test (void *arg) ++{ ++ void *(*child) (void *) = NULL; ++ struct test_param *param = arg; ++ bool entry = param->entry; ++ ++ if (entry) ++ { ++ printf ("%d:%d Start test run\n", getpid (), gettid ()); ++ /* First level: Reenter as a subprocess and then as a subthread. */ ++ child = do_one_test; ++ set_cpu_mask (param, true); ++ set_my_affinity (param->size, param->set); ++ param->entry = false; ++ } ++ else ++ { ++ /* Verification for the first level. */ ++ verify_my_affinity (param->nproc, param->size, param->set); ++ ++ /* Launch the second level test, launching CHILD_TEST as a subprocess and ++ then as a subthread. Use a different mask to see if it gets ++ inherited. */ ++ child = child_test; ++ set_cpu_mask (param, false); ++ set_my_affinity (param->size, param->set); ++ } ++ ++ /* Verify that a child of a thread/process inherits the affinity mask. */ ++ printf ("%d:%d%sdo_one_test: fork\n", getpid (), gettid (), ++ entry ? " " : " "); ++ int pid = xfork (); ++ ++ if (pid == 0) ++ { ++ child (param); ++ return NULL; ++ } ++ ++ xwaitpid (pid, NULL, 0); ++ ++ /* Verify that a subthread of a thread/process inherits the affinity ++ mask. */ ++ printf ("%d:%d%sdo_one_test: thread\n", getpid (), gettid (), ++ entry ? " " : " "); ++ pthread_t t = xpthread_create (NULL, child, param); ++ xpthread_join (t); ++ ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ int num_cpus = get_nprocs (); ++ ++ struct test_param param = ++ { ++ .nproc = num_cpus, ++ .set = CPU_ALLOC (num_cpus), ++ .size = CPU_ALLOC_SIZE (num_cpus), ++ .entry = true, ++ }; ++ ++ if (param.set == NULL) ++ FAIL_EXIT1 ("error: CPU_ALLOC (%d) failed\n", num_cpus); ++ ++ do_one_test (¶m); ++ ++ CPU_FREE (param.set); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 8632bfe6eac31ff2..08b4e7765c07f6a3 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -127,6 +127,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ + tst-getauxval \ + tst-fdopendir-o_path \ + tst-linux-mremap1 \ ++ tst-sched-affinity-inheritance \ + # tests + + # Test for the symbol version of fcntl that was replaced in glibc 2.28. +diff --git a/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c b/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c +new file mode 100644 +index 0000000000000000..fe0297f743d55e2f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c +@@ -0,0 +1,71 @@ ++/* CPU Affinity inheritance test - sched_{gs}etaffinity. ++ 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 ++ . */ ++ ++/* See top level comment in nptl/tst-skeleton-affinity-inheritance.c for a ++ description of this test. */ ++ ++#include ++#include ++#include ++#include ++ ++static void ++set_my_affinity (size_t size, const cpu_set_t *set) ++{ ++ int ret = sched_setaffinity (0, size, set); ++ ++ if (ret != 0) ++ FAIL ("sched_setaffinity returned %d (%s)", ret, strerror (ret)); ++} ++ ++static void ++verify_my_affinity (int nproc, size_t size, const cpu_set_t *expected_set) ++{ ++ cpu_set_t *set = CPU_ALLOC (nproc); ++ cpu_set_t *xor_set = CPU_ALLOC (nproc); ++ ++ if (set == NULL || xor_set== NULL) ++ FAIL_EXIT1 ("verify_my_affinity: Failed to allocate cpuset: %m\n"); ++ ++ int ret = sched_getaffinity (0, size, set); ++ if (ret != 0) ++ FAIL ("sched_getaffinity returned %d (%s)", ret, strerror (ret)); ++ ++ CPU_XOR_S (size, xor_set, expected_set, set); ++ ++ int cpucount = CPU_COUNT_S (size, xor_set); ++ ++ if (cpucount > 0) ++ { ++ FAIL ("Affinity mask not inherited, " ++ "following %d CPUs mismatched in the expected and actual sets:\n", ++ cpucount); ++ for (int cur = 0; cur < nproc && cpucount >= 0; cur++) ++ if (CPU_ISSET_S (size, cur, xor_set)) ++ { ++ printf ("%d ", cur); ++ cpucount--; ++ } ++ printf ("\n"); ++ } ++ ++ CPU_FREE (set); ++ CPU_FREE (xor_set); ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-61559-3.patch b/SOURCES/glibc-RHEL-61559-3.patch new file mode 100644 index 0000000..be715f9 --- /dev/null +++ b/SOURCES/glibc-RHEL-61559-3.patch @@ -0,0 +1,103 @@ +commit 09ea1afec75ed0d41cb0da27a9df1b8c3dd56ddc +Author: Stefan Liebler +Date: Fri Jan 10 12:55:50 2025 -0500 + + affinity-inheritance: Overallocate CPU sets + + Some kernels on S390 appear to return a CPU affinity mask based on + configured processors rather than the ones online. Overallocate the CPU + set to match that, but operate only on the ones online. + + Signed-off-by: Siddhesh Poyarekar + Co-authored-by: Siddhesh Poyarekar + +diff --git a/nptl/tst-pthread-affinity-inheritance.c b/nptl/tst-pthread-affinity-inheritance.c +index c020530dd916dea1..153fc904dfe14c9d 100644 +--- a/nptl/tst-pthread-affinity-inheritance.c ++++ b/nptl/tst-pthread-affinity-inheritance.c +@@ -34,10 +34,11 @@ set_my_affinity (size_t size, const cpu_set_t *set) + } + + static void +-verify_my_affinity (int nproc, size_t size, const cpu_set_t *expected_set) ++verify_my_affinity (int nproc, int nproc_configured, size_t size, ++ const cpu_set_t *expected_set) + { +- cpu_set_t *set = CPU_ALLOC (nproc); +- cpu_set_t *xor_set = CPU_ALLOC (nproc); ++ cpu_set_t *set = CPU_ALLOC (nproc_configured); ++ cpu_set_t *xor_set = CPU_ALLOC (nproc_configured); + + if (set == NULL || xor_set== NULL) + FAIL_EXIT1 ("verify_my_affinity: Failed to allocate cpuset: %m\n"); +diff --git a/nptl/tst-skeleton-affinity-inheritance.c b/nptl/tst-skeleton-affinity-inheritance.c +index 6de6d9c9428a0c9d..926f49622990e9e4 100644 +--- a/nptl/tst-skeleton-affinity-inheritance.c ++++ b/nptl/tst-skeleton-affinity-inheritance.c +@@ -42,6 +42,7 @@ + struct test_param + { + int nproc; ++ int nproc_configured; + cpu_set_t *set; + size_t size; + bool entry; +@@ -70,7 +71,8 @@ child_test (void *arg) + struct test_param *param = arg; + + printf ("%d:%d child\n", getpid (), gettid ()); +- verify_my_affinity (param->nproc, param->size, param->set); ++ verify_my_affinity (param->nproc, param->nproc_configured, param->size, ++ param->set); + return NULL; + } + +@@ -93,7 +95,8 @@ do_one_test (void *arg) + else + { + /* Verification for the first level. */ +- verify_my_affinity (param->nproc, param->size, param->set); ++ verify_my_affinity (param->nproc, param->nproc_configured, param->size, ++ param->set); + + /* Launch the second level test, launching CHILD_TEST as a subprocess and + then as a subthread. Use a different mask to see if it gets +@@ -129,13 +132,17 @@ do_one_test (void *arg) + static int + do_test (void) + { ++ /* Large enough in case the kernel decides to return the larger mask. This ++ seems to happen on some kernels for S390x. */ ++ int num_configured_cpus = get_nprocs_conf (); + int num_cpus = get_nprocs (); + + struct test_param param = + { + .nproc = num_cpus, +- .set = CPU_ALLOC (num_cpus), +- .size = CPU_ALLOC_SIZE (num_cpus), ++ .nproc_configured = num_configured_cpus, ++ .set = CPU_ALLOC (num_configured_cpus), ++ .size = CPU_ALLOC_SIZE (num_configured_cpus), + .entry = true, + }; + +diff --git a/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c b/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c +index fe0297f743d55e2f..8a42d275fce35e84 100644 +--- a/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c ++++ b/sysdeps/unix/sysv/linux/tst-sched-affinity-inheritance.c +@@ -34,10 +34,11 @@ set_my_affinity (size_t size, const cpu_set_t *set) + } + + static void +-verify_my_affinity (int nproc, size_t size, const cpu_set_t *expected_set) ++verify_my_affinity (int nproc, int nproc_configured, size_t size, ++ const cpu_set_t *expected_set) + { +- cpu_set_t *set = CPU_ALLOC (nproc); +- cpu_set_t *xor_set = CPU_ALLOC (nproc); ++ cpu_set_t *set = CPU_ALLOC (nproc_configured); ++ cpu_set_t *xor_set = CPU_ALLOC (nproc_configured); + + if (set == NULL || xor_set== NULL) + FAIL_EXIT1 ("verify_my_affinity: Failed to allocate cpuset: %m\n"); diff --git a/SOURCES/glibc-RHEL-61559-4.patch b/SOURCES/glibc-RHEL-61559-4.patch new file mode 100644 index 0000000..d97c4c0 --- /dev/null +++ b/SOURCES/glibc-RHEL-61559-4.patch @@ -0,0 +1,20 @@ +commit 71b49e299dbe22853095119da5064303e1d6b9ff +Author: Florian Weimer +Date: Tue Jan 21 10:36:58 2025 +0100 + + nptl: Include in tst-skeleton-affinity-inheritance.c + + The file uses the identifiers bool, false, true. + +diff --git a/nptl/tst-skeleton-affinity-inheritance.c b/nptl/tst-skeleton-affinity-inheritance.c +index 926f49622990e9e4..e1f328ae265b2bfb 100644 +--- a/nptl/tst-skeleton-affinity-inheritance.c ++++ b/nptl/tst-skeleton-affinity-inheritance.c +@@ -32,6 +32,7 @@ + they're both inherited. */ + + #include ++#include + #include + #include + #include diff --git a/SOURCES/glibc-RHEL-61568.patch b/SOURCES/glibc-RHEL-61568.patch new file mode 100644 index 0000000..b28221c --- /dev/null +++ b/SOURCES/glibc-RHEL-61568.patch @@ -0,0 +1,114 @@ +commit bde47662b74b883149c3001e2c052dea5d3cd92f +Author: Sergey Kolosov +Date: Wed Nov 6 15:24:06 2024 +0100 + + nptl: Add new test for pthread_spin_trylock + + Add a threaded test for pthread_spin_trylock attempting to lock already + acquired spin lock and checking for correct return code. + + Reviewed-by: Florian Weimer + +Conflicts: + sysdeps/pthread/Makefile (add new test) + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index d99c161c827ef4b8..6355e94171fbcdc3 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -127,6 +127,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-pthread_kill-exited \ + tst-pthread_kill-exiting \ + tst-cancel30 \ ++ tst-spin5 \ + # tests + + tests-time64 := \ +diff --git a/sysdeps/pthread/tst-spin5.c b/sysdeps/pthread/tst-spin5.c +new file mode 100644 +index 0000000000000000..5c23bd48ef27b3ce +--- /dev/null ++++ b/sysdeps/pthread/tst-spin5.c +@@ -0,0 +1,82 @@ ++/* Threaded test the pthread_spin_trylock 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++pthread_spinlock_t lock; ++ ++void * ++thread (void *arg) ++{ ++ int ret; ++ int thr_id = *(int *) arg; ++ ++ ret = pthread_spin_trylock (&lock); ++ if (thr_id == 1) ++ /* thread with already acquired lock. */ ++ { ++ if (ret != EBUSY) ++ { ++ FAIL_EXIT1 ("pthread_spin_trylock should fail with EBUSY"); ++ } ++ } ++ else if (thr_id == 2) ++ /* thread with released spin lock. */ ++ { ++ if (ret != 0) ++ { ++ FAIL_EXIT1 ("pthread_spin_trylock should be able to acquire lock"); ++ } ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr1, thr2; ++ int ret; ++ int thr1_id = 1, thr2_id = 2; ++ ++ pthread_spin_init (&lock, PTHREAD_PROCESS_PRIVATE); ++ /* lock spin in main thread. */ ++ ret = pthread_spin_trylock (&lock); ++ if (ret != 0) ++ { ++ FAIL_EXIT1 ("Main thread should be able to acquire spin lock"); ++ } ++ ++ /* create first thread to try locking already acquired spin lock. */ ++ thr1 = xpthread_create (NULL, thread, &thr1_id); ++ xpthread_join (thr1); ++ ++ /* release spin lock and create thread to acquire released spin lock. */ ++ pthread_spin_unlock (&lock); ++ thr2 = xpthread_create (NULL, thread, &thr2_id); ++ xpthread_join (thr2); ++ ++ pthread_spin_destroy (&lock); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-62716-1.patch b/SOURCES/glibc-RHEL-62716-1.patch new file mode 100644 index 0000000..e7d0757 --- /dev/null +++ b/SOURCES/glibc-RHEL-62716-1.patch @@ -0,0 +1,214 @@ +commit 8022fc7d5119a22e9e0ac72798f649385b0e167a +Author: Frédéric Bérat +Date: Wed Jun 14 10:52:07 2023 +0200 + + tests: replace system by xsystem + + With fortification enabled, system calls return result needs to be checked, + has it gets the __wur macro enabled. + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + nptl/tst-cancel7.c (change not relevant for this version) + +diff --git a/elf/tst-stackguard1.c b/elf/tst-stackguard1.c +index 6584740d6aa26f5f..9c4a5ccde0c659a9 100644 +--- a/elf/tst-stackguard1.c ++++ b/elf/tst-stackguard1.c +@@ -27,6 +27,8 @@ + #include + #include + ++#include ++ + static const char *command; + static bool child; + static uintptr_t stack_chk_guard_copy; +@@ -109,7 +111,8 @@ do_test (void) + dup2 (fds[1], 2); + close (fds[1]); + +- system (command); ++ xsystem (command); ++ + exit (0); + } + +diff --git a/libio/bug-mmap-fflush.c b/libio/bug-mmap-fflush.c +index d8aa58985aa0790c..3f99222eefa7d4c3 100644 +--- a/libio/bug-mmap-fflush.c ++++ b/libio/bug-mmap-fflush.c +@@ -4,6 +4,7 @@ + #include + #include + ++#include + + static char *fname; + +@@ -35,14 +36,16 @@ do_test (void) + char buffer[1024]; + + snprintf (buffer, sizeof (buffer), "echo 'From foo@bar.com' > %s", fname); +- system (buffer); ++ xsystem (buffer); ++ + f = fopen (fname, "r"); + fseek (f, 0, SEEK_END); + o = ftello (f); + fseek (f, 0, SEEK_SET); + fflush (f); + snprintf (buffer, sizeof (buffer), "echo 'From bar@baz.edu' >> %s", fname); +- system (buffer); ++ xsystem (buffer); ++ + fseek (f, o, SEEK_SET); + if (fgets (buffer, 1024, f) == NULL) + exit (1); +diff --git a/nptl/tst-cancel7.c b/nptl/tst-cancel7.c +index 7a1870ac74b23faa..338cecc8293638b0 100644 +--- a/nptl/tst-cancel7.c ++++ b/nptl/tst-cancel7.c +@@ -41,6 +41,7 @@ tf (void *arg) + + strcpy (stpcpy (stpcpy (cmd, command), args), pidfilename); + system (cmd); ++ + /* This call should never return. */ + return NULL; + } +diff --git a/nptl/tst-stackguard1.c b/nptl/tst-stackguard1.c +index cac492ec34808617..5b9d57a73327b3c8 100644 +--- a/nptl/tst-stackguard1.c ++++ b/nptl/tst-stackguard1.c +@@ -29,6 +29,7 @@ + #include + + #include ++#include + + static const char *command; + static bool child; +@@ -141,7 +142,8 @@ do_test (void) + dup2 (fds[1], 2); + close (fds[1]); + +- system (command); ++ xsystem (command); ++ + exit (0); + } + +diff --git a/nss/tst-nss-db-endpwent.c b/nss/tst-nss-db-endpwent.c +index 5932a9800f33b717..d25033afabc01c30 100644 +--- a/nss/tst-nss-db-endpwent.c ++++ b/nss/tst-nss-db-endpwent.c +@@ -23,6 +23,7 @@ + + #include + #include ++#include + + /* It is entirely allowed to start with a getpwent call without + resetting the state of the service via a call to setpwent. +@@ -55,7 +56,7 @@ do_test (void) + + cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in", + support_bindir_prefix); +- system (cmd); ++ xsystem (cmd); + free (cmd); + + try_it (); +diff --git a/support/Makefile b/support/Makefile +index 3b8509c88db4662a..47d5db4629b029d3 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -221,6 +221,7 @@ libsupport-routines = \ + xstrndup \ + xsymlink \ + xsysconf \ ++ xsystem \ + xunlink \ + xuselocale \ + xwaitpid \ +diff --git a/support/xstdlib.h b/support/xstdlib.h +new file mode 100644 +index 0000000000000000..db5a5b9d4fd1fa71 +--- /dev/null ++++ b/support/xstdlib.h +@@ -0,0 +1,31 @@ ++/* Error-checking wrappers for stdlib functions. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_XSTDLIB_H ++#define SUPPORT_XSTDLIB_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++void xsystem (const char *cmd); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XSTDLIB_H */ +diff --git a/support/xsystem.c b/support/xsystem.c +new file mode 100644 +index 0000000000000000..1f558953bca8f5b2 +--- /dev/null ++++ b/support/xsystem.c +@@ -0,0 +1,37 @@ ++/* Error-checking replacement for "system". ++ 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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++void ++xsystem (const char *cmd) ++{ ++ int ret = system (cmd); ++ ++ if (ret == 0 && cmd == NULL) ++ FAIL_EXIT1 ("Unable to spawn a shell for NULL command"); ++ ++ if (ret == 127) ++ FAIL_EXIT1 ("Child terminated with status 127"); ++ ++ if (ret < 0) ++ FAIL_EXIT1 ("system (\"%s\")", cmd); ++} diff --git a/SOURCES/glibc-RHEL-62716-2.patch b/SOURCES/glibc-RHEL-62716-2.patch new file mode 100644 index 0000000..311f478 --- /dev/null +++ b/SOURCES/glibc-RHEL-62716-2.patch @@ -0,0 +1,291 @@ +commit ff0320bec2810192d453c579623482fab87bfa01 +Author: H.J. Lu +Date: Wed Jul 24 14:05:15 2024 -0700 + + Add mremap tests + + Add tests for MREMAP_MAYMOVE and MREMAP_FIXED. On Linux, also test + MREMAP_DONTUNMAP. + + Signed-off-by: H.J. Lu + Reviewed-by: Adhemerval Zanella + +Conflicts: + misc/Makefile (new test added) + sysdeps/unix/sysv/linux/Makefile (new test added) + +diff --git a/misc/Makefile b/misc/Makefile +index ae244a72689ffb0a..5d6fc0f6824a734f 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -89,7 +89,9 @@ tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \ + tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \ + tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \ + tst-mntent-autofs tst-syscalls tst-mntent-escape tst-select \ +- tst-ioctl ++ tst-ioctl \ ++ tst-mremap1 \ ++ tst-mremap2 \ + + tests-time64 := \ + tst-select-time64 \ +diff --git a/misc/tst-mremap1.c b/misc/tst-mremap1.c +new file mode 100644 +index 0000000000000000..0469991a6c1438b6 +--- /dev/null ++++ b/misc/tst-mremap1.c +@@ -0,0 +1,46 @@ ++/* Test mremap with MREMAP_MAYMOVE. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ size_t old_size = getpagesize (); ++ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1); ++ old_addr[0] = 1; ++ old_addr[old_size - 1] = 2; ++ ++ /* Test MREMAP_MAYMOVE. */ ++ size_t new_size = old_size + old_size; ++ char *new_addr = mremap (old_addr, old_size, new_size, MREMAP_MAYMOVE); ++ TEST_VERIFY_EXIT (new_addr != MAP_FAILED); ++ new_addr[0] = 1; ++ new_addr[new_size - 1] = 2; ++ xmunmap (new_addr, new_size); ++ ++ return 0; ++} ++ ++#include +diff --git a/misc/tst-mremap2.c b/misc/tst-mremap2.c +new file mode 100644 +index 0000000000000000..45be7f0369c2571e +--- /dev/null ++++ b/misc/tst-mremap2.c +@@ -0,0 +1,54 @@ ++/* Test mremap with MREMAP_FIXED. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ size_t old_size = getpagesize (); ++ size_t new_size = old_size + old_size; ++ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1); ++ old_addr[0] = 1; ++ old_addr[old_size - 1] = 2; ++ ++ char *fixed_addr = xmmap (NULL, new_size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1); ++ fixed_addr[0] = 1; ++ fixed_addr[new_size - 1] = 2; ++ ++ /* Test MREMAP_FIXED. */ ++ char *new_addr = mremap (old_addr, old_size, new_size, ++ MREMAP_FIXED | MREMAP_MAYMOVE, ++ fixed_addr); ++ if (new_addr == MAP_FAILED) ++ return mremap_failure_exit (errno); ++ new_addr[0] = 1; ++ new_addr[new_size - 1] = 2; ++ xmunmap (new_addr, new_size); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/generic/mremap-failure.h b/sysdeps/generic/mremap-failure.h +new file mode 100644 +index 0000000000000000..bc0d476368050c2c +--- /dev/null ++++ b/sysdeps/generic/mremap-failure.h +@@ -0,0 +1,25 @@ ++/* mremap failure handling. Generic version. ++ 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 ++ . */ ++ ++/* Return exit value on mremap failure with errno ERR. */ ++ ++static int ++mremap_failure_exit (int err) ++{ ++ return EXIT_FAILURE; ++} +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 74656e56038844aa..8632bfe6eac31ff2 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -126,6 +126,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ + tst-scm_rights \ + tst-getauxval \ + tst-fdopendir-o_path \ ++ tst-linux-mremap1 \ + # tests + + # Test for the symbol version of fcntl that was replaced in glibc 2.28. +diff --git a/sysdeps/unix/sysv/linux/mremap-failure.h b/sysdeps/unix/sysv/linux/mremap-failure.h +new file mode 100644 +index 0000000000000000..c99ab30ca9ea796f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/mremap-failure.h +@@ -0,0 +1,30 @@ ++/* mremap failure handling. Linux version. ++ 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 ++ . */ ++ ++#include ++ ++/* Return exit value on mremap failure with errno ERR. */ ++ ++static int ++mremap_failure_exit (int err) ++{ ++ if (err != EINVAL) ++ return EXIT_FAILURE; ++ ++ return EXIT_UNSUPPORTED; ++} +diff --git a/sysdeps/unix/sysv/linux/tst-linux-mremap1.c b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c +new file mode 100644 +index 0000000000000000..408e8af2abe59033 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c +@@ -0,0 +1,63 @@ ++/* Test mremap with MREMAP_DONTUNMAP. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ size_t old_size = getpagesize (); ++ size_t new_size = old_size; ++ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1); ++ old_addr[0] = 1; ++ old_addr[old_size - 1] = 2; ++ ++ /* Create an available 64-page mmap region. */ ++ size_t fixed_size = old_size * 64; ++ char *fixed_addr = xmmap (NULL, fixed_size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1); ++ xmunmap (fixed_addr, fixed_size); ++ ++ /* Add 3 * pagesize. */ ++ fixed_size += 3 * old_size; ++ ++ /* Test MREMAP_DONTUNMAP. It should return FIXED_ADDR created above. */ ++ char *new_addr = mremap (old_addr, old_size, new_size, ++ MREMAP_DONTUNMAP | MREMAP_MAYMOVE, ++ fixed_addr); ++ if (new_addr == MAP_FAILED) ++ return mremap_failure_exit (errno); ++ TEST_VERIFY_EXIT (fixed_addr == new_addr); ++ old_addr[0] = 3; ++ old_addr[old_size - 1] = 4; ++ new_addr[0] = 1; ++ new_addr[new_size - 1] = 2; ++ xmunmap (new_addr, new_size); ++ xmunmap (old_addr, old_size); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-65354.patch b/SOURCES/glibc-RHEL-65354.patch new file mode 100644 index 0000000..5f93e8a --- /dev/null +++ b/SOURCES/glibc-RHEL-65354.patch @@ -0,0 +1,109 @@ +commit 3c2b9dc41cd05da055fae6f793a355063156bdf3 +Author: Joseph Myers +Date: Fri Nov 29 20:25:04 2024 +0000 + + Add threaded test of sem_trywait + + All the existing glibc tests of sem_trywait are single-threaded. Add + one that calls sem_trywait and sem_post in separate threads. + + Tested for x86_64. + +Conflicts: + sysdeps/pthread/Makefile (add new test) + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 6355e94171fbcdc3..5a1b26fa3c0e6061 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -128,6 +128,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-pthread_kill-exiting \ + tst-cancel30 \ + tst-spin5 \ ++ tst-sem19 \ + # tests + + tests-time64 := \ +diff --git a/sysdeps/pthread/tst-sem19.c b/sysdeps/pthread/tst-sem19.c +new file mode 100644 +index 0000000000000000..9ef461e008ab9eab +--- /dev/null ++++ b/sysdeps/pthread/tst-sem19.c +@@ -0,0 +1,77 @@ ++/* Test sem_trywait with threads. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* The test uses two threads, the main thread and a newly created ++ thread to test the operation of sem_trywait in a threaded scenario. ++ The intent is to test sem_trywait when it would return EAGAIN, and ++ then again after the critical section in the new thread has posted ++ to the semaphore and the main thread succeeds in calling ++ sem_trywait. It is possible this test fails with a timeout if the ++ second thread takes longer than the test timeout to acquire the ++ lock, and post. */ ++ ++static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; ++static sem_t sem; ++ ++static void * ++tf (void *arg) ++{ ++ xpthread_mutex_lock (&lock); ++ sem_post (&sem); ++ xpthread_mutex_unlock (&lock); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ int ret; ++ ++ ret = sem_init (&sem, 0, 0); ++ TEST_VERIFY_EXIT (ret == 0); ++ xpthread_mutex_lock (&lock); ++ pthread_t th = xpthread_create (NULL, tf, NULL); ++ errno = 0; ++ /* The other thread is waiting on the lock before it calls sem_post, ++ so sem_trywait should fail. */ ++ ret = sem_trywait (&sem); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EAGAIN); ++ xpthread_mutex_unlock (&lock); ++ /* The other thread now takes the lock, calls sem_post and releases ++ the lock. */ ++ for (;;) ++ { ++ errno = 0; ++ ret = sem_trywait (&sem); ++ if (ret == 0) ++ break; ++ TEST_COMPARE (errno, EAGAIN); ++ } ++ xpthread_join (th); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-65356-1.patch b/SOURCES/glibc-RHEL-65356-1.patch new file mode 100644 index 0000000..8b40111 --- /dev/null +++ b/SOURCES/glibc-RHEL-65356-1.patch @@ -0,0 +1,93 @@ +commit 2f679937b35b7f9a8d448ab2ee03bc1fb3ace263 +Author: Florian Weimer +Date: Mon May 8 13:14:22 2023 +0200 + + manual: Remove unsupported line breaks in waiting-with-clock section + + The argument to @deftypefun must be on a single line. + Also add the missing @safety for sem_clockwait. + + Reported-by: Nilgün Belma Bugüner + +diff --git a/manual/threads.texi b/manual/threads.texi +index 48fd562923800b34..a721c7f464e3588e 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -754,8 +754,8 @@ freed. + + @comment semaphore.h + @comment POSIX-proposed +-@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid}, +- const struct timespec *@var{abstime}) ++@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) ++@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{sem_timedwait} except the time @var{abstime} is measured + against the clock specified by @var{clockid} rather than + @code{CLOCK_REALTIME}. Currently, @var{clockid} must be either +@@ -764,8 +764,7 @@ against the clock specified by @var{clockid} rather than + + @comment pthread.h + @comment POSIX-proposed +-@deftypefun int pthread_cond_clockwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, +- clockid_t @var{clockid}, const struct timespec *@var{abstime}) ++@deftypefun int pthread_cond_clockwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + @c If exactly the same function with arguments is called from a signal + @c handler that interrupts between the mutex unlock and sleep then it +@@ -784,10 +783,7 @@ specified or defaulted when @code{pthread_cond_init} was called. Currently, + + @comment pthread.h + @comment POSIX-proposed +-@deftypefun int pthread_rwlock_clockrdlock (pthread_rwlock_t *@var{rwlock}, +- clockid_t @var{clockid}, +- const struct timespec *@var{abstime}) +- ++@deftypefun int pthread_rwlock_clockrdlock (pthread_rwlock_t *@var{rwlock}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{pthread_rwlock_timedrdlock} except the time + @var{abstime} is measured against the clock specified by @var{clockid} +@@ -798,10 +794,7 @@ returned. + + @comment pthread.h + @comment POSIX-proposed +-@deftypefun int pthread_rwlock_clockwrlock (pthread_rwlock_t *@var{rwlock}, +- clockid_t @var{clockid}, +- const struct timespec *@var{abstime}) +- ++@deftypefun int pthread_rwlock_clockwrlock (pthread_rwlock_t *@var{rwlock}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{pthread_rwlock_timedwrlock} except the time + @var{abstime} is measured against the clock specified by @var{clockid} +@@ -812,8 +805,7 @@ returned. + + @comment pthread.h + @comment GNU extension +-@deftypefun int pthread_tryjoin_np (pthread_t *@var{thread}, +- void **@var{thread_return}) ++@deftypefun int pthread_tryjoin_np (pthread_t *@var{thread}, void **@var{thread_return}) + @standards{GNU, pthread.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{pthread_join} except that it will return @code{EBUSY} +@@ -822,9 +814,7 @@ immediately if the thread specified by @var{thread} has not yet terminated. + + @comment pthread.h + @comment GNU extension +-@deftypefun int pthread_timedjoin_np (pthread_t *@var{thread}, +- void **@var{thread_return}, +- const struct timespec *@var{abstime}) ++@deftypefun int pthread_timedjoin_np (pthread_t *@var{thread}, void **@var{thread_return}, const struct timespec *@var{abstime}) + @standards{GNU, pthread.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{pthread_tryjoin_np} except that it will block until the +@@ -836,10 +826,7 @@ will wait forever in the same way as @code{pthread_join}. + + @comment pthread.h + @comment GNU extension +-@deftypefun int pthread_clockjoin_np (pthread_t *@var{thread}, +- void **@var{thread_return}, +- clockid_t @var{clockid}, +- const struct timespec *@var{abstime}) ++@deftypefun int pthread_clockjoin_np (pthread_t *@var{thread}, void **@var{thread_return}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) + @standards{GNU, pthread.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{pthread_timedjoin_np} except that the absolute time in diff --git a/SOURCES/glibc-RHEL-65356-2.patch b/SOURCES/glibc-RHEL-65356-2.patch new file mode 100644 index 0000000..7a24269 --- /dev/null +++ b/SOURCES/glibc-RHEL-65356-2.patch @@ -0,0 +1,332 @@ +commit 83a1cc3bc3d28c97d1af6c0957b11fe39fd786d8 +Author: Carlos O'Donell +Date: Wed Oct 9 18:32:26 2024 -0400 + + manual: Fix and test @deftypef* function formatting + + The manual contained several instances of incorrect formatting + that were correct texinfo but produced incorrectly rendered manuals + or incorrect behaviour from the tooling. + + The most important was incorrect quoting of function returns + by failing to use {} to quote the return. The impact of this + mistake means that 'info libc func' does not jump to the function + in question but instead to the introductory page under the assumption + that func doesn't exist. The function returns are now correctly + quoted. + + The second issue was the use of a category specifier with + @deftypefun which doesn't accept a category specifier. If a category + specifier is required then @deftypefn needs to be used. This is + corrected by changing the command to @deftypefn for such functions + that used {Deprecated function} as a category. + + The last issue is a missing space between the function name and the + arguments which results in odd function names like "epoll_wait(int" + instead of "epoll_wait". This also impacts the use of 'info libc' + and is corrected. + + We additionally remove ';' from the end of function arguments and + add an 'int' return type for dprintf. + + Lastly we add a new test check-deftype.sh which verifies the expected + formatting of @deftypefun, @deftypefunx, @deftypefn, and + @deftypefnx. The new test is also run as the summary file is + generated to ensure we don't generate incorrect results. + + The existing check-safety.sh is also run directly as a test to increase + coverage since the existing tests only ran on manual install. + + The new tests now run as part of the standard "make check" that + pre-commit CI runs and developers should run. + + No regressions on x86_64. + + HTML and PDF rendering reviewed and looks correct for all changes. + + Reviewed-by: H.J. Lu + +Conflicts: + manual/time.texi (irrelevant changes) + +diff --git a/manual/Makefile b/manual/Makefile +index 6301e4a16f9daf58..66ea73384d9d85aa 100644 +--- a/manual/Makefile ++++ b/manual/Makefile +@@ -69,6 +69,11 @@ chapters.% top-menu.%: libc-texinfo.sh $(texis-path) Makefile + '$(chapters)' \ + '$(appendices) $(licenses)' + ++# Verify validity of texinfo sources against project rules. ++tests-special += \ ++ $(objpfx)check-deftype.out \ ++ $(objpfx)check-safety.out \ ++ # tests-special + + $(objpfx)libc.dvi $(objpfx)libc.pdf $(objpfx)libc.info: \ + $(addprefix $(objpfx),$(libc-texi-generated)) +@@ -83,10 +88,19 @@ $(objpfx)summary.texi: $(objpfx)stamp-summary ; + $(objpfx)stamp-summary: summary.pl $(filter-out $(objpfx)summary.texi, \ + $(texis-path)) + $(SHELL) ./check-safety.sh $(filter-out $(objpfx)%, $(texis-path)) ++ $(SHELL) ./check-deftype.sh $(filter-out $(objpfx)%, $(texis-path)) + LC_ALL=C $(PERL) $^ > $(objpfx)summary-tmp + $(move-if-change) $(objpfx)summary-tmp $(objpfx)summary.texi + touch $@ + ++$(objpfx)check-safety.out: check-safety.sh ++ $(SHELL) $< > $@ ; \ ++ $(evaluate-test) ++ ++$(objpfx)check-deftype.out: check-deftype.sh ++ $(SHELL) $< > $@ ; \ ++ $(evaluate-test) ++ + # Generate a file which can be added to the `dir' content to provide direct + # access to the documentation of the function, variables, and other + # definitions. +@@ -152,10 +166,19 @@ $(objpfx)%.pdf: %.texinfo + + + # Distribution. +-minimal-dist = summary.pl texis.awk tsort.awk libc-texinfo.sh libc.texinfo \ +- libm-err.texi stamp-libm-err check-safety.sh \ +- $(filter-out summary.texi, $(nonexamples)) \ +- $(patsubst %.c.texi,examples/%.c, $(examples)) ++minimal-dist = \ ++ $(filter-out summary.texi, $(nonexamples)) \ ++ $(patsubst %.c.texi,examples/%.c, $(examples)) \ ++ check-deftype.sh \ ++ check-safety.sh \ ++ libc-texinfo.sh \ ++ libc.texinfo \ ++ libm-err.texi \ ++ stamp-libm-err \ ++ summary.pl \ ++ texis.awk \ ++ tsort.awk \ ++ # minimal-dist + + indices = cp fn pg tp vr ky + generated-dirs += libc +diff --git a/manual/check-deftype.sh b/manual/check-deftype.sh +new file mode 100644 +index 0000000000000000..395c99af6afe1fdd +--- /dev/null ++++ b/manual/check-deftype.sh +@@ -0,0 +1,50 @@ ++#!/bin/sh ++ ++# Copyright 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 ++# . ++ ++# Check that the @deftypefun command is called with the expected ++# arguments and includes checking for common mistakes including ++# failure to include a space after the function name, or incorrect ++# quoting. ++ ++success=: ++ ++# If no arguments are given, take all *.texi files in the current directory. ++test $# != 0 || set *.texi ++ ++# We search for all @deftypefun and @deftypefunx command uses. ++# Then we remove all of those that match our expectations. ++# A @deftypefun or @deftypefunx command takes 3 arguments: ++# - return type ++# - name ++# - arguments ++# This is different from @deftypefn which includes an additional ++# category which is implicit here. ++grep -n -r '^@deftypefun' "$@" | ++grep -v '^.*@deftypefunx\?'\ ++' \({\?[a-zA-Z0-9_ *]*}\?\) \([a-zA-Z0-9_]*\) (.*)$' && ++success=false ++ ++# We search for all @deftypefn and @deftypefnx command uses. ++# We have 4 arguments in the command including the category. ++grep -n -r '^@deftypefn' "$@" | ++grep -v '^.*@deftypefnx\?'\ ++' {\?[a-zA-Z ]*}\? \({\?[a-zA-Z0-9@{}_ *]*}\?\) \([a-zA-Z0-9_]*\) (.*)$' && ++success=false ++ ++$success +diff --git a/manual/ipc.texi b/manual/ipc.texi +index 081b98fe29e0b3b5..73189960c46c908a 100644 +--- a/manual/ipc.texi ++++ b/manual/ipc.texi +@@ -20,7 +20,7 @@ by @theglibc{}. + @c Need descriptions for all of these functions. + + @subsection System V Semaphores +-@deftypefun int semctl (int @var{semid}, int @var{semnum}, int @var{cmd}); ++@deftypefun int semctl (int @var{semid}, int @var{semnum}, int @var{cmd}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{/linux}}} + @c syscall(ipc) ok + @c +@@ -30,35 +30,35 @@ by @theglibc{}. + @c semid_ds. + @end deftypefun + +-@deftypefun int semget (key_t @var{key}, int @var{nsems}, int @var{semflg}); ++@deftypefun int semget (key_t @var{key}, int @var{nsems}, int @var{semflg}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c syscall(ipc) ok + @end deftypefun + +-@deftypefun int semop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}); ++@deftypefun int semop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c syscall(ipc) ok + @end deftypefun + +-@deftypefun int semtimedop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}, const struct timespec *@var{timeout}); ++@deftypefun int semtimedop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}, const struct timespec *@var{timeout}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c syscall(ipc) ok + @end deftypefun + + @subsection POSIX Semaphores + +-@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}); ++@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} + @c Does not atomically update sem_t therefore AC-unsafe + @c because it can leave sem_t partially initialized. + @end deftypefun + +-@deftypefun int sem_destroy (sem_t *@var{sem}); ++@deftypefun int sem_destroy (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c Function does nothing and is therefore always safe. + @end deftypefun + +-@deftypefun sem_t *sem_open (const char *@var{name}, int @var{oflag}, ...); ++@deftypefun {sem_t *} sem_open (const char *@var{name}, int @var{oflag}, ...) + @safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acuinit{}}} + @c pthread_once asuinit + @c +@@ -67,7 +67,7 @@ by @theglibc{}. + @c shmfs on Linux. + @end deftypefun + +-@deftypefun int sem_close (sem_t *@var{sem}); ++@deftypefun int sem_close (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + @c lll_lock asulock aculock + @c twalk mtsrace{:root} +@@ -77,13 +77,13 @@ by @theglibc{}. + @c are not updated atomically. + @end deftypefun + +-@deftypefun int sem_unlink (const char *@var{name}); ++@deftypefun int sem_unlink (const char *@var{name}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acucorrupt{}}} + @c pthread_once asuinit acucorrupt aculock + @c mempcpy acucorrupt + @end deftypefun + +-@deftypefun int sem_wait (sem_t *@var{sem}); ++@deftypefun int sem_wait (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} + @c atomic_increment (nwaiters) acucorrupt + @c +@@ -95,22 +95,22 @@ by @theglibc{}. + @c waiters count. + @end deftypefun + +-@deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}); ++@deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} + @c Same safety issues as sem_wait. + @end deftypefun + +-@deftypefun int sem_trywait (sem_t *@var{sem}); ++@deftypefun int sem_trywait (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c All atomic operations are safe in all contexts. + @end deftypefun + +-@deftypefun int sem_post (sem_t *@var{sem}); ++@deftypefun int sem_post (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c Same safety as sem_trywait. + @end deftypefun + +-@deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}); ++@deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c Atomic write of a value is safe in all contexts. + @end deftypefun +diff --git a/manual/llio.texi b/manual/llio.texi +index 0f84a593ee92b31f..161ec3cb6de4b61e 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -4820,12 +4820,12 @@ of an IOCTL, see @ref{Out-of-Band Data}. + @manpagefunctionstub{poll,2} + @end deftypefun + +-@deftypefun int epoll_create(int @var{size}) ++@deftypefun int epoll_create (int @var{size}) + + @manpagefunctionstub{epoll_create,2} + @end deftypefun + +-@deftypefun int epoll_wait(int @var{epfd}, struct epoll_event *@var{events}, int @var{maxevents}, int @var{timeout}) ++@deftypefun int epoll_wait (int @var{epfd}, struct epoll_event *@var{events}, int @var{maxevents}, int @var{timeout}) + + @manpagefunctionstub{epoll_wait,2} + @end deftypefun +diff --git a/manual/memory.texi b/manual/memory.texi +index ee709b0cac57dded..4fb605b3faae1d36 100644 +--- a/manual/memory.texi ++++ b/manual/memory.texi +@@ -2929,7 +2929,7 @@ exceed the process' data storage limit. + @end deftypefun + + +-@deftypefun void *sbrk (ptrdiff_t @var{delta}) ++@deftypefun {void *} sbrk (ptrdiff_t @var{delta}) + @standards{BSD, unistd.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +diff --git a/manual/stdio.texi b/manual/stdio.texi +index a2d9292a787b9fa3..98da13de32f49c7c 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -2489,7 +2489,7 @@ store the result in which case @code{-1} is returned. This was + changed in order to comply with the @w{ISO C99} standard. + @end deftypefun + +-@deftypefun dprintf (int @var{fd}, @var{template}, ...) ++@deftypefun int dprintf (int @var{fd}, @var{template}, ...) + @standards{POSIX, stdio.h} + @safety{@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}} + This function formats its arguments according to @var{template} and +diff --git a/manual/threads.texi b/manual/threads.texi +index a721c7f464e3588e..3fd307e69a8029fa 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -592,7 +592,7 @@ destructor for the thread-specific data is not called during destruction, nor + is it called during thread exit. + @end deftypefun + +-@deftypefun void *pthread_getspecific (pthread_key_t @var{key}) ++@deftypefun {void *} pthread_getspecific (pthread_key_t @var{key}) + @standards{POSIX, pthread.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c pthread_getspecific ok diff --git a/SOURCES/glibc-RHEL-65358-1.patch b/SOURCES/glibc-RHEL-65358-1.patch new file mode 100644 index 0000000..d6d924c --- /dev/null +++ b/SOURCES/glibc-RHEL-65358-1.patch @@ -0,0 +1,106 @@ +commit 047703fbb88eb38fbe973f3abedb279382f181d0 +Author: Florian Weimer +Date: Tue Jun 6 11:37:30 2023 +0200 + + support: Add delayed__exit (with two underscores) + + It calls _exit instead of exit once the timeout expires. + +Conflicts: + support/delayed_exit.c (fixup context) + support/xthread.h (fixup context) + +diff --git a/support/delayed_exit.c b/support/delayed_exit.c +index 450860c5953257be..9242d4a1236e94ee 100644 +--- a/support/delayed_exit.c ++++ b/support/delayed_exit.c +@@ -23,33 +23,58 @@ + #include + #include + #include ++#include + #include ++#include ++ ++struct delayed_exit_request ++{ ++ void (*exitfunc) (int); ++ int seconds; ++}; + + static void * +-delayed_exit_thread (void *seconds_as_ptr) ++delayed_exit_thread (void *closure) + { +- int seconds = (uintptr_t) seconds_as_ptr; +- struct timespec delay = { seconds, 0 }; ++ struct delayed_exit_request *request = closure; ++ void (*exitfunc) (int) = request->exitfunc; ++ struct timespec delay = { request->seconds, 0 }; + struct timespec remaining = { 0 }; ++ free (request); ++ + if (nanosleep (&delay, &remaining) != 0) + FAIL_EXIT1 ("nanosleep: %m"); +- /* Exit the process sucessfully. */ +- exit (0); ++ /* Exit the process successfully. */ ++ exitfunc (0); + return NULL; + } + +-void +-delayed_exit (int seconds) ++static void ++delayed_exit_1 (int seconds, void (*exitfunc) (int)) + { + /* Create the new thread with all signals blocked. */ + sigset_t all_blocked; + sigfillset (&all_blocked); + sigset_t old_set; + xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); ++ struct delayed_exit_request *request = xmalloc (sizeof (*request)); ++ request->seconds = seconds; ++ request->exitfunc = exitfunc; + /* Create a detached thread. */ +- pthread_t thr = xpthread_create +- (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); ++ pthread_t thr = xpthread_create (NULL, delayed_exit_thread, request); + xpthread_detach (thr); + /* Restore the original signal mask. */ + xpthread_sigmask (SIG_SETMASK, &old_set, NULL); + } ++ ++void ++delayed_exit (int seconds) ++{ ++ delayed_exit_1 (seconds, exit); ++} ++ ++void ++delayed__exit (int seconds) ++{ ++ delayed_exit_1 (seconds, _exit); ++} +diff --git a/support/xthread.h b/support/xthread.h +index 1a39b1c0ddda9725..5c6b57e8829a4ee9 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -24,11 +24,14 @@ + + __BEGIN_DECLS + +-/* Terminate the process (with exit status 0) after SECONDS have +- elapsed, from a helper thread. The process is terminated with the +- exit function, so atexit handlers are executed. */ ++/* Terminate the process (with exit (0)) after SECONDS have elapsed, ++ from a helper thread. The process is terminated with the exit ++ function, so atexit handlers are executed. */ + void delayed_exit (int seconds); + ++/* Like delayed_exit, but use _exit (0). */ ++void delayed__exit (int seconds); ++ + /* Terminate the process (with exit status 1) if VALUE is not zero. + In that case, print a failure message to standard output mentioning + FUNCTION. The process is terminated with the exit function, so diff --git a/SOURCES/glibc-RHEL-65358-2.patch b/SOURCES/glibc-RHEL-65358-2.patch new file mode 100644 index 0000000..7884d35 --- /dev/null +++ b/SOURCES/glibc-RHEL-65358-2.patch @@ -0,0 +1,23 @@ +commit 7d421209287a07db5e926552ae5fbe9d8abb50dc +Author: Florian Weimer +Date: Tue Jun 6 11:39:06 2023 +0200 + + pthreads: Use _exit to terminate the tst-stdio1 test + + Previously, the exit function was used, but this causes the test to + block (until the timeout) once exit is changed to lock stdio streams + during flush. + +diff --git a/sysdeps/pthread/tst-stdio1.c b/sysdeps/pthread/tst-stdio1.c +index 80fb59c4e42ca550..a2cc71d67f0761f6 100644 +--- a/sysdeps/pthread/tst-stdio1.c ++++ b/sysdeps/pthread/tst-stdio1.c +@@ -47,7 +47,7 @@ do_test (void) + _exit (1); + } + +- delayed_exit (1); ++ delayed__exit (1); + xpthread_join (th); + + puts ("join returned"); diff --git a/SOURCES/glibc-RHEL-65358-3.patch b/SOURCES/glibc-RHEL-65358-3.patch new file mode 100644 index 0000000..3b0a167 --- /dev/null +++ b/SOURCES/glibc-RHEL-65358-3.patch @@ -0,0 +1,131 @@ +commit af130d27099651e0d27b2cf2cfb44dafd6fe8a26 +Author: Andreas Schwab +Date: Tue Jan 30 10:16:00 2018 +0100 + + Always do locking when accessing streams (bug 15142, bug 14697) + + Now that abort no longer calls fflush there is no reason to avoid locking + the stdio streams anywhere. This fixes a conformance issue and potential + heap corruption during exit. + +diff --git a/libio/genops.c b/libio/genops.c +index b964c50657d7fbe9..a82c1b96767e14e0 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -683,7 +683,7 @@ _IO_adjust_column (unsigned start, const char *line, int count) + libc_hidden_def (_IO_adjust_column) + + int +-_IO_flush_all_lockp (int do_lock) ++_IO_flush_all (void) + { + int result = 0; + FILE *fp; +@@ -696,8 +696,7 @@ _IO_flush_all_lockp (int do_lock) + for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain) + { + run_fp = fp; +- if (do_lock) +- _IO_flockfile (fp); ++ _IO_flockfile (fp); + + if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base) + || (_IO_vtable_offset (fp) == 0 +@@ -707,8 +706,7 @@ _IO_flush_all_lockp (int do_lock) + && _IO_OVERFLOW (fp, EOF) == EOF) + result = EOF; + +- if (do_lock) +- _IO_funlockfile (fp); ++ _IO_funlockfile (fp); + run_fp = NULL; + } + +@@ -719,14 +717,6 @@ _IO_flush_all_lockp (int do_lock) + + return result; + } +- +- +-int +-_IO_flush_all (void) +-{ +- /* We want locking. */ +- return _IO_flush_all_lockp (1); +-} + libc_hidden_def (_IO_flush_all) + + void +@@ -792,6 +782,9 @@ _IO_unbuffer_all (void) + { + int legacy = 0; + ++ run_fp = fp; ++ _IO_flockfile (fp); ++ + #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) + if (__glibc_unlikely (_IO_vtable_offset (fp) != 0)) + legacy = 1; +@@ -807,18 +800,6 @@ _IO_unbuffer_all (void) + /* Iff stream is un-orientated, it wasn't used. */ + && (legacy || fp->_mode != 0)) + { +-#ifdef _IO_MTSAFE_IO +- int cnt; +-#define MAXTRIES 2 +- for (cnt = 0; cnt < MAXTRIES; ++cnt) +- if (fp->_lock == NULL || _IO_lock_trylock (*fp->_lock) == 0) +- break; +- else +- /* Give the other thread time to finish up its use of the +- stream. */ +- __sched_yield (); +-#endif +- + if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) + { + fp->_flags |= _IO_USER_BUF; +@@ -832,17 +813,15 @@ _IO_unbuffer_all (void) + + if (! legacy && fp->_mode > 0) + _IO_wsetb (fp, NULL, NULL, 0); +- +-#ifdef _IO_MTSAFE_IO +- if (cnt < MAXTRIES && fp->_lock != NULL) +- _IO_lock_unlock (*fp->_lock); +-#endif + } + + /* Make sure that never again the wide char functions can be + used. */ + if (! legacy) + fp->_mode = -1; ++ ++ _IO_funlockfile (fp); ++ run_fp = NULL; + } + + #ifdef _IO_MTSAFE_IO +@@ -868,9 +847,7 @@ libc_freeres_fn (buffer_free) + int + _IO_cleanup (void) + { +- /* We do *not* want locking. Some threads might use streams but +- that is their problem, we flush them underneath them. */ +- int result = _IO_flush_all_lockp (0); ++ int result = _IO_flush_all (); + + /* We currently don't have a reliable mechanism for making sure that + C++ static destructors are executed in the correct order. +diff --git a/libio/libioP.h b/libio/libioP.h +index 811e9c919bbc2ce1..fbe58fc10fb694d0 100644 +--- a/libio/libioP.h ++++ b/libio/libioP.h +@@ -488,7 +488,6 @@ extern int _IO_new_do_write (FILE *, const char *, size_t); + extern int _IO_old_do_write (FILE *, const char *, size_t); + extern int _IO_wdo_write (FILE *, const wchar_t *, size_t); + libc_hidden_proto (_IO_wdo_write) +-extern int _IO_flush_all_lockp (int); + extern int _IO_flush_all (void); + libc_hidden_proto (_IO_flush_all) + extern int _IO_cleanup (void); diff --git a/SOURCES/glibc-RHEL-65358-4.patch b/SOURCES/glibc-RHEL-65358-4.patch new file mode 100644 index 0000000..bdd262c --- /dev/null +++ b/SOURCES/glibc-RHEL-65358-4.patch @@ -0,0 +1,230 @@ +commit f6ba993e0cda0ca5554fd47b00e6a87be5fdf05e +Author: Adhemerval Zanella +Date: Thu Jul 25 15:41:44 2024 -0300 + + stdlib: Allow concurrent exit (BZ 31997) + + Even if C/POSIX standard states that exit is not formally thread-unsafe, + calling it more than once is UB. The glibc already supports + it for the single-thread, and both elf/nodelete2.c and tst-rseq-disable.c + call exit from a DSO destructor (which is called by _dl_fini, registered + at program startup with __cxa_atexit). + + However, there are still race issues when it is called more than once + concurrently by multiple threads. A recent Rust PR triggered this + issue [1], which resulted in an Austin Group ask for clarification [2]. + Besides it, there is a discussion to make concurrent calling not UB [3], + wtih a defined semantic where any remaining callers block until the first + call to exit has finished (reentrant calls, leaving through longjmp, and + exceptions are still undefined). + + For glibc, at least reentrant calls are required to be supported to avoid + changing the current behaviour. This requires locking using a recursive + lock, where any exit called by atexit() handlers resumes at the point of + the current handler (thus avoiding calling the current handle multiple + times). + + Checked on x86_64-linux-gnu and aarch64-linux-gnu. + + [1] https://github.com/rust-lang/rust/issues/126600 + [2] https://austingroupbugs.net/view.php?id=1845 + [3] https://www.openwall.com/lists/libc-coord/2024/07/24/4 + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 603a330b1e8f1ba2..865d804ef2642cb5 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -93,6 +93,7 @@ tests := \ + tst-bsearch \ + tst-bz20544 \ + tst-canon-bz26341 \ ++ tst-concurrent-exit \ + tst-cxa_atexit \ + tst-environ \ + tst-getenv-signal \ +diff --git a/stdlib/exit.c b/stdlib/exit.c +index 546343f7d4b74773..7d536098623d47ff 100644 +--- a/stdlib/exit.c ++++ b/stdlib/exit.c +@@ -140,9 +140,17 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + } + + ++/* The lock handles concurrent exit(), even though the C/POSIX standard states ++ that calling exit() more than once is UB. The recursive lock allows ++ atexit() handlers or destructors to call exit() itself. In this case, the ++ handler list execution will resume at the point of the current handler. */ ++__libc_lock_define_initialized_recursive (static, __exit_lock) ++ + void + exit (int status) + { ++ /* The exit should never return, so there is no need to unlock it. */ ++ __libc_lock_lock_recursive (__exit_lock); + __run_exit_handlers (status, &__exit_funcs, true, true); + } + libc_hidden_def (exit) +diff --git a/stdlib/tst-concurrent-exit.c b/stdlib/tst-concurrent-exit.c +new file mode 100644 +index 0000000000000000..1141130f87fde20f +--- /dev/null ++++ b/stdlib/tst-concurrent-exit.c +@@ -0,0 +1,157 @@ ++/* Check if exit can be called concurrently by multiple threads. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_atexit 32 ++ ++static pthread_barrier_t barrier; ++ ++static void * ++tf (void *closure) ++{ ++ xpthread_barrier_wait (&barrier); ++ exit (0); ++ ++ return NULL; ++} ++ ++static const char expected[] = "00000000000000000000000003021121130211"; ++static char crumbs[sizeof (expected)]; ++static int next_slot = 0; ++ ++static void ++exit_with_flush (int code) ++{ ++ fflush (stdout); ++ /* glibc allows recursive exit, the atexit handlers execution will be ++ resumed from the where the previous exit was interrupted. */ ++ exit (code); ++} ++ ++/* Take some time, so another thread potentially issue exit. */ ++#define SETUP_NANOSLEEP \ ++ if (nanosleep (&(struct timespec) { .tv_sec = 0, .tv_nsec = 1000L }, \ ++ NULL) != 0) \ ++ FAIL_EXIT1 ("nanosleep: %m") ++ ++static void ++fn0 (void) ++{ ++ crumbs[next_slot++] = '0'; ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn1 (void) ++{ ++ crumbs[next_slot++] = '1'; ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn2 (void) ++{ ++ crumbs[next_slot++] = '2'; ++ atexit (fn1); ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn3 (void) ++{ ++ crumbs[next_slot++] = '3'; ++ atexit (fn2); ++ atexit (fn0); ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn_final (void) ++{ ++ TEST_COMPARE_STRING (crumbs, expected); ++ exit_with_flush (0); ++} ++ ++_Noreturn static void ++child (void) ++{ ++ enum { nthreads = 8 }; ++ ++ xpthread_barrier_init (&barrier, NULL, nthreads + 1); ++ ++ pthread_t thr[nthreads]; ++ for (int i = 0; i < nthreads; i++) ++ thr[i] = xpthread_create (NULL, tf, NULL); ++ ++ xpthread_barrier_wait (&barrier); ++ ++ for (int i = 0; i < nthreads; i++) ++ { ++ pthread_join (thr[i], NULL); ++ /* It should not be reached, it means that thread did not exit for ++ some reason. */ ++ support_record_failure (); ++ } ++ ++ exit (2); ++} ++ ++static int ++do_test (void) ++{ ++ /* Register a large number of handler that will trigger a heap allocation ++ for the handle state. On exit, each block will be freed after the ++ handle is processed. */ ++ int slots_remaining = MAX_atexit; ++ ++ /* Register this first so it can verify expected order of the rest. */ ++ atexit (fn_final); --slots_remaining; ++ ++ TEST_VERIFY_EXIT (atexit (fn1) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (atexit (fn3) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (atexit (fn1) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (atexit (fn2) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (atexit (fn1) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (atexit (fn3) == 0); --slots_remaining; ++ ++ while (slots_remaining > 0) ++ { ++ TEST_VERIFY_EXIT (atexit (fn0) == 0); --slots_remaining; ++ } ++ ++ pid_t pid = xfork (); ++ if (pid != 0) ++ { ++ int status; ++ xwaitpid (pid, &status, 0); ++ TEST_VERIFY (WIFEXITED (status)); ++ } ++ else ++ child (); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-65358-5.patch b/SOURCES/glibc-RHEL-65358-5.patch new file mode 100644 index 0000000..fdab7a4 --- /dev/null +++ b/SOURCES/glibc-RHEL-65358-5.patch @@ -0,0 +1,427 @@ +commit c6af8a9a3ce137a9704825d173be22a2b2d9cb49 +Author: Adhemerval Zanella +Date: Mon Aug 5 11:27:35 2024 -0300 + + stdlib: Allow concurrent quick_exit (BZ 31997) + + As for exit, also allows concurrent quick_exit to avoid race + conditions when it is called concurrently. Since it uses the same + internal function as exit, the __exit_lock lock is moved to + __run_exit_handlers. It also solved a potential concurrent when + calling exit and quick_exit concurrently. + + The test case 'expected' is expanded to a value larger than the + minimum required by C/POSIX (32 entries) so at_quick_exit() will + require libc to allocate a new block. This makes the test mre likely to + trigger concurrent issues (through free() at __run_exit_handlers) + if quick_exit() interacts with the at_quick_exit list concurrently. + + This is also the latest interpretation of the Austin Ticket [1]. + + Checked on x86_64-linux-gnu. + + [1] https://austingroupbugs.net/view.php?id=1845 + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 865d804ef2642cb5..4cbf47d215353681 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -94,6 +94,7 @@ tests := \ + tst-bz20544 \ + tst-canon-bz26341 \ + tst-concurrent-exit \ ++ tst-concurrent-quick_exit \ + tst-cxa_atexit \ + tst-environ \ + tst-getenv-signal \ +diff --git a/stdlib/exit.c b/stdlib/exit.c +index 7d536098623d47ff..1719f88c7aca5397 100644 +--- a/stdlib/exit.c ++++ b/stdlib/exit.c +@@ -30,6 +30,13 @@ DEFINE_HOOK (__libc_atexit, (void)) + __exit_funcs_lock is declared. */ + bool __exit_funcs_done = false; + ++/* The lock handles concurrent exit() and quick_exit(), even though the ++ C/POSIX standard states that calling exit() more than once is UB. The ++ recursive lock allows atexit() handlers or destructors to call exit() ++ itself. In this case, the handler list execution will resume at the ++ point of the current handler. */ ++__libc_lock_define_initialized_recursive (static, __exit_lock) ++ + /* Call all functions registered with `atexit' and `on_exit', + in the reverse of the order in which they were registered + perform stdio cleanup, and terminate program execution with STATUS. */ +@@ -38,6 +45,9 @@ attribute_hidden + __run_exit_handlers (int status, struct exit_function_list **listp, + bool run_list_atexit, bool run_dtors) + { ++ /* The exit should never return, so there is no need to unlock it. */ ++ __libc_lock_lock_recursive (__exit_lock); ++ + /* First, call the TLS destructors. */ + #ifndef SHARED + if (&__call_tls_dtors != NULL) +@@ -140,17 +150,9 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + } + + +-/* The lock handles concurrent exit(), even though the C/POSIX standard states +- that calling exit() more than once is UB. The recursive lock allows +- atexit() handlers or destructors to call exit() itself. In this case, the +- handler list execution will resume at the point of the current handler. */ +-__libc_lock_define_initialized_recursive (static, __exit_lock) +- + void + exit (int status) + { +- /* The exit should never return, so there is no need to unlock it. */ +- __libc_lock_lock_recursive (__exit_lock); + __run_exit_handlers (status, &__exit_funcs, true, true); + } + libc_hidden_def (exit) +diff --git a/stdlib/tst-concurrent-exit-skeleton.c b/stdlib/tst-concurrent-exit-skeleton.c +new file mode 100644 +index 0000000000000000..cfd5140466e1a730 +--- /dev/null ++++ b/stdlib/tst-concurrent-exit-skeleton.c +@@ -0,0 +1,160 @@ ++/* Check if exit/quick_exit can be called concurrently by multiple threads. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* A value larger than the minimum required by C/POSIX (32), to trigger a ++ new block memory allocation. */ ++#define MAX_atexit 64 ++ ++static pthread_barrier_t barrier; ++ ++static void * ++tf (void *closure) ++{ ++ xpthread_barrier_wait (&barrier); ++ EXIT (0); ++ ++ return NULL; ++} ++ ++static const char expected[] = "00000000000000000000000000000000000" ++ "00000000000000000000003021121130211"; ++static char crumbs[sizeof (expected)]; ++static int next_slot = 0; ++ ++static void ++exit_with_flush (int code) ++{ ++ fflush (stdout); ++ /* glibc allows recursive EXIT, the ATEXIT handlers execution will be ++ resumed from the where the previous EXIT was interrupted. */ ++ EXIT (code); ++} ++ ++/* Take some time, so another thread potentially issue EXIT. */ ++#define SETUP_NANOSLEEP \ ++ if (nanosleep (&(struct timespec) { .tv_sec = 0, .tv_nsec = 1000L }, \ ++ NULL) != 0) \ ++ FAIL_EXIT1 ("nanosleep: %m") ++ ++static void ++fn0 (void) ++{ ++ crumbs[next_slot++] = '0'; ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn1 (void) ++{ ++ crumbs[next_slot++] = '1'; ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn2 (void) ++{ ++ crumbs[next_slot++] = '2'; ++ ATEXIT (fn1); ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn3 (void) ++{ ++ crumbs[next_slot++] = '3'; ++ ATEXIT (fn2); ++ ATEXIT (fn0); ++ SETUP_NANOSLEEP; ++} ++ ++static void ++fn_final (void) ++{ ++ TEST_COMPARE_STRING (crumbs, expected); ++ exit_with_flush (0); ++} ++ ++_Noreturn static void ++child (void) ++{ ++ enum { nthreads = 8 }; ++ ++ xpthread_barrier_init (&barrier, NULL, nthreads + 1); ++ ++ pthread_t thr[nthreads]; ++ for (int i = 0; i < nthreads; i++) ++ thr[i] = xpthread_create (NULL, tf, NULL); ++ ++ xpthread_barrier_wait (&barrier); ++ ++ for (int i = 0; i < nthreads; i++) ++ { ++ pthread_join (thr[i], NULL); ++ /* It should not be reached, it means that thread did not exit for ++ some reason. */ ++ support_record_failure (); ++ } ++ ++ EXIT (2); ++} ++ ++static int ++do_test (void) ++{ ++ /* Register a large number of handler that will trigger a heap allocation ++ for the handle state. On EXIT, each block will be freed after the ++ handle is processed. */ ++ int slots_remaining = MAX_atexit; ++ ++ /* Register this first so it can verify expected order of the rest. */ ++ ATEXIT (fn_final); --slots_remaining; ++ ++ TEST_VERIFY_EXIT (ATEXIT (fn1) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (ATEXIT (fn3) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (ATEXIT (fn1) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (ATEXIT (fn2) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (ATEXIT (fn1) == 0); --slots_remaining; ++ TEST_VERIFY_EXIT (ATEXIT (fn3) == 0); --slots_remaining; ++ ++ while (slots_remaining > 0) ++ { ++ TEST_VERIFY_EXIT (ATEXIT (fn0) == 0); --slots_remaining; ++ } ++ ++ pid_t pid = xfork (); ++ if (pid != 0) ++ { ++ int status; ++ xwaitpid (pid, &status, 0); ++ TEST_VERIFY (WIFEXITED (status)); ++ } ++ else ++ child (); ++ ++ return 0; ++} ++ ++#include +diff --git a/stdlib/tst-concurrent-exit.c b/stdlib/tst-concurrent-exit.c +index 1141130f87fde20f..421c39d63126246d 100644 +--- a/stdlib/tst-concurrent-exit.c ++++ b/stdlib/tst-concurrent-exit.c +@@ -16,142 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#define EXIT(__r) exit (__r) ++#define ATEXIT(__f) atexit (__f) + +-#define MAX_atexit 32 +- +-static pthread_barrier_t barrier; +- +-static void * +-tf (void *closure) +-{ +- xpthread_barrier_wait (&barrier); +- exit (0); +- +- return NULL; +-} +- +-static const char expected[] = "00000000000000000000000003021121130211"; +-static char crumbs[sizeof (expected)]; +-static int next_slot = 0; +- +-static void +-exit_with_flush (int code) +-{ +- fflush (stdout); +- /* glibc allows recursive exit, the atexit handlers execution will be +- resumed from the where the previous exit was interrupted. */ +- exit (code); +-} +- +-/* Take some time, so another thread potentially issue exit. */ +-#define SETUP_NANOSLEEP \ +- if (nanosleep (&(struct timespec) { .tv_sec = 0, .tv_nsec = 1000L }, \ +- NULL) != 0) \ +- FAIL_EXIT1 ("nanosleep: %m") +- +-static void +-fn0 (void) +-{ +- crumbs[next_slot++] = '0'; +- SETUP_NANOSLEEP; +-} +- +-static void +-fn1 (void) +-{ +- crumbs[next_slot++] = '1'; +- SETUP_NANOSLEEP; +-} +- +-static void +-fn2 (void) +-{ +- crumbs[next_slot++] = '2'; +- atexit (fn1); +- SETUP_NANOSLEEP; +-} +- +-static void +-fn3 (void) +-{ +- crumbs[next_slot++] = '3'; +- atexit (fn2); +- atexit (fn0); +- SETUP_NANOSLEEP; +-} +- +-static void +-fn_final (void) +-{ +- TEST_COMPARE_STRING (crumbs, expected); +- exit_with_flush (0); +-} +- +-_Noreturn static void +-child (void) +-{ +- enum { nthreads = 8 }; +- +- xpthread_barrier_init (&barrier, NULL, nthreads + 1); +- +- pthread_t thr[nthreads]; +- for (int i = 0; i < nthreads; i++) +- thr[i] = xpthread_create (NULL, tf, NULL); +- +- xpthread_barrier_wait (&barrier); +- +- for (int i = 0; i < nthreads; i++) +- { +- pthread_join (thr[i], NULL); +- /* It should not be reached, it means that thread did not exit for +- some reason. */ +- support_record_failure (); +- } +- +- exit (2); +-} +- +-static int +-do_test (void) +-{ +- /* Register a large number of handler that will trigger a heap allocation +- for the handle state. On exit, each block will be freed after the +- handle is processed. */ +- int slots_remaining = MAX_atexit; +- +- /* Register this first so it can verify expected order of the rest. */ +- atexit (fn_final); --slots_remaining; +- +- TEST_VERIFY_EXIT (atexit (fn1) == 0); --slots_remaining; +- TEST_VERIFY_EXIT (atexit (fn3) == 0); --slots_remaining; +- TEST_VERIFY_EXIT (atexit (fn1) == 0); --slots_remaining; +- TEST_VERIFY_EXIT (atexit (fn2) == 0); --slots_remaining; +- TEST_VERIFY_EXIT (atexit (fn1) == 0); --slots_remaining; +- TEST_VERIFY_EXIT (atexit (fn3) == 0); --slots_remaining; +- +- while (slots_remaining > 0) +- { +- TEST_VERIFY_EXIT (atexit (fn0) == 0); --slots_remaining; +- } +- +- pid_t pid = xfork (); +- if (pid != 0) +- { +- int status; +- xwaitpid (pid, &status, 0); +- TEST_VERIFY (WIFEXITED (status)); +- } +- else +- child (); +- +- return 0; +-} +- +-#include ++#include "tst-concurrent-exit-skeleton.c" +diff --git a/stdlib/tst-concurrent-quick_exit.c b/stdlib/tst-concurrent-quick_exit.c +new file mode 100644 +index 0000000000000000..3f321668d6b8d536 +--- /dev/null ++++ b/stdlib/tst-concurrent-quick_exit.c +@@ -0,0 +1,22 @@ ++/* Check if quick_exit can be called concurrently by multiple threads. ++ 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 ++ . */ ++ ++#define EXIT(__r) quick_exit (__r) ++#define ATEXIT(__f) at_quick_exit (__f) ++ ++#include "tst-concurrent-exit-skeleton.c" diff --git a/SOURCES/glibc-RHEL-65359-1.patch b/SOURCES/glibc-RHEL-65359-1.patch new file mode 100644 index 0000000..0a02cd5 --- /dev/null +++ b/SOURCES/glibc-RHEL-65359-1.patch @@ -0,0 +1,54 @@ +commit ebd928224a138d4560dc0be3ef162162d62a9e43 +Author: Carlos O'Donell +Date: Thu May 18 12:56:45 2023 -0400 + + assert: Reformat Makefile. + + Reflow all long lines adding comment terminators. + Sort all reflowed text using scripts/sort-makefile-lines.py. + + No code generation changes observed in binary artifacts. + No regressions on x86_64 and i686. + +diff --git a/assert/Makefile b/assert/Makefile +index 2bc9e2214e3e9a8b..24a9bdb96306ca08 100644 +--- a/assert/Makefile ++++ b/assert/Makefile +@@ -22,7 +22,9 @@ subdir := assert + + include ../Makeconfig + +-headers := assert.h ++headers := \ ++ assert.h ++ # headers + + routines := \ + __assert \ +@@ -30,7 +32,13 @@ routines := \ + assert \ + assert-perr \ + # routines +-tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++ ++ ++tests := \ ++ test-assert \ ++ test-assert-perr \ ++ tst-assert-c++ \ ++ tst-assert-g++ \ ++ # tests + + ifeq ($(have-cxx-thread_local),yes) + CFLAGS-tst-assert-c++.o = -std=c++11 +@@ -38,7 +46,10 @@ LDLIBS-tst-assert-c++ = -lstdc++ + CFLAGS-tst-assert-g++.o = -std=gnu++11 + LDLIBS-tst-assert-g++ = -lstdc++ + else +-tests-unsupported += tst-assert-c++ tst-assert-g++ ++tests-unsupported += \ ++ tst-assert-c++ \ ++ tst-assert-g++ \ ++ # tests-unsupported + endif + + include ../Rules diff --git a/SOURCES/glibc-RHEL-65359-2.patch b/SOURCES/glibc-RHEL-65359-2.patch new file mode 100644 index 0000000..9a962ec --- /dev/null +++ b/SOURCES/glibc-RHEL-65359-2.patch @@ -0,0 +1,255 @@ +commit e79e5c4899e82eff1032b1f8e530234c8fcbd8b9 +Author: DJ Delorie +Date: Thu Nov 14 15:12:57 2024 -0500 + + assert: ensure posix compliance, add tests for such + + Fix assert.c so that even the fallback + case conforms to POSIX, although not exactly the same as + the default case so a test can tell the difference. + + Add a test that verifies that abort is called, and that the + message printed to stderr has all the info that POSIX requires. + Verify this even when malloc isn't usable. + + Reviewed-by: Paul Eggert + +Conflicts: + assert/assert.c + (no downstream) + +diff --git a/assert/Makefile b/assert/Makefile +index 24a9bdb96306ca08..85358fad51367b49 100644 +--- a/assert/Makefile ++++ b/assert/Makefile +@@ -38,6 +38,7 @@ tests := \ + test-assert-perr \ + tst-assert-c++ \ + tst-assert-g++ \ ++ test-assert-2 \ + # tests + + ifeq ($(have-cxx-thread_local),yes) +diff --git a/assert/assert.c b/assert/assert.c +index 989126c7e5b6b265..6002cc953cdb2d39 100644 +--- a/assert/assert.c ++++ b/assert/assert.c +@@ -24,6 +24,8 @@ + #include + #include + #include ++#include ++#include + + + extern const char *__progname; +@@ -85,8 +87,35 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file, + else + { + /* At least print a minimal message. */ +- static const char errstr[] = "Unexpected error.\n"; +- __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); ++ char linebuf[INT_STRLEN_BOUND (int) + sizeof ":: "]; ++ struct iovec v[9]; ++ int i = 0; ++ ++#define WS(s) (v[i].iov_len = strlen (v[i].iov_base = (void *) (s)), i++) ++ ++ if (__progname) ++ { ++ WS (__progname); ++ WS (": "); ++ } ++ ++ WS (file); ++ v[i++] = (struct iovec) {.iov_base = linebuf, ++ .iov_len = sprintf (linebuf, ":%d: ", line)}; ++ ++ if (function) ++ { ++ WS (function); ++ WS (": "); ++ } ++ ++ WS ("Assertion `"); ++ WS (assertion); ++ /* We omit the '.' here so that the assert tests can tell when ++ this code path is taken. */ ++ WS ("' failed\n"); ++ ++ (void) writev (STDERR_FILENO, v, i); + } + + abort (); +diff --git a/assert/test-assert-2.c b/assert/test-assert-2.c +new file mode 100644 +index 0000000000000000..99f8f683e87a0c64 +--- /dev/null ++++ b/assert/test-assert-2.c +@@ -0,0 +1,166 @@ ++/* Test assert's compliance with POSIX requirements. ++ 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 ++ . */ ++ ++/* This test verifies that a failed assertion acts in accordance with ++ the POSIX requirements, despite any internal failures. We do so by ++ calling test routines via fork() and monitoring their exit codes ++ and stderr, while possibly forcing internal functions (malloc) to ++ fail. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#undef NDEBUG ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* We need to be able to make malloc() "fail" so that __asprintf ++ fails. */ ++ ++void * (*next_malloc)(size_t sz) = 0; ++static volatile bool fail_malloc = 0; ++ ++void * ++malloc (size_t sz) ++{ ++ if (fail_malloc) ++ return NULL; ++ if (next_malloc == 0) ++ next_malloc = dlsym (RTLD_NEXT, "malloc"); ++ if (next_malloc == 0) ++ return NULL; ++ return next_malloc (sz); ++} ++ ++/* We can tell if abort() is called by looking for the custom return ++ value. */ ++ ++void ++abort_handler(int s) ++{ ++ _exit(5); ++} ++ ++static int do_lineno; ++static const char *do_funcname; ++ ++/* Hack to get the line of the assert. */ ++#define GET_INFO_1(l) \ ++ if (closure != NULL) \ ++ { \ ++ do_lineno = l; \ ++ do_funcname = __func__; \ ++ return; \ ++ } ++#define GET_INFO() GET_INFO_1(__LINE__+1) ++ ++/* These are the two test cases. */ ++ ++static void ++test_assert_normal (void *closure) ++{ ++ if (closure == NULL) ++ signal (SIGABRT, abort_handler); ++ ++ GET_INFO (); ++ assert (1 == 2); ++} ++ ++ ++static void ++test_assert_nomalloc (void *closure) ++{ ++ if (closure == NULL) ++ { ++ signal (SIGABRT, abort_handler); ++ fail_malloc = 1; ++ } ++ ++ GET_INFO (); ++ assert (1 == 2); ++} ++ ++static void ++check_posix (const char *buf, int rv, int line, ++ const char *funcname, const char *testarg) ++{ ++ /* POSIX requires that a failed assertion write a diagnostic to ++ stderr and call abort. The diagnostic must include the filename, ++ line number, and function where the assertion failed, along with ++ the text of the assert() argument. ++ */ ++ char linestr[100]; ++ ++ sprintf (linestr, "%d", line); ++ ++ /* If abort is called, our handler will return 5. */ ++ TEST_VERIFY (rv == 5); ++ ++ TEST_VERIFY (strstr (buf, __FILE__) != NULL); ++ TEST_VERIFY (strstr (buf, linestr) != NULL); ++ TEST_VERIFY (strstr (buf, funcname) != NULL); ++ TEST_VERIFY (strstr (buf, testarg) != NULL); ++ ++} ++ ++static void ++one_test (void (*func)(void *), int which_path) ++{ ++ struct support_capture_subprocess sp; ++ int rv; ++ ++ func (&do_lineno); ++ printf("running test for %s, line %d\n", do_funcname, do_lineno); ++ ++ sp = support_capture_subprocess (func, NULL); ++ rv = WEXITSTATUS (sp.status); ++ ++ check_posix (sp.err.buffer, rv, do_lineno, do_funcname, "1 == 2"); ++ ++ /* Look for intentional subtle differences in messages to verify ++ that the intended code path was taken. */ ++ switch (which_path) ++ { ++ case 0: ++ TEST_VERIFY (strstr (sp.err.buffer, "failed.\n") != NULL); ++ break; ++ case 1: ++ TEST_VERIFY (strstr (sp.err.buffer, "failed\n") != NULL); ++ break; ++ } ++ ++ support_capture_subprocess_free (&sp); ++} ++ ++static int ++do_test(void) ++{ ++ one_test (test_assert_normal, 0); ++ one_test (test_assert_nomalloc, 1); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-65359-3.patch b/SOURCES/glibc-RHEL-65359-3.patch new file mode 100644 index 0000000..757b8e1 --- /dev/null +++ b/SOURCES/glibc-RHEL-65359-3.patch @@ -0,0 +1,23 @@ +commit 3fb895ac88e99201573352b1abc18db4340ecede +Author: DJ Delorie +Date: Sat Dec 21 23:12:41 2024 -0500 + + assert: Use __writev in assert.c [BZ #32492] + + Replace writev with __writev in assert/assert.c. This fixes [BZ #32492]. + + Reviewed-by: H.J. Lu + +diff --git a/assert/assert.c b/assert/assert.c +index 6002cc953cdb2d39..1e9683cf0707b0d3 100644 +--- a/assert/assert.c ++++ b/assert/assert.c +@@ -115,7 +115,7 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file, + this code path is taken. */ + WS ("' failed\n"); + +- (void) writev (STDERR_FILENO, v, i); ++ (void) __writev (STDERR_FILENO, v, i); + } + + abort (); diff --git a/SOURCES/glibc-RHEL-65359-4.patch b/SOURCES/glibc-RHEL-65359-4.patch new file mode 100644 index 0000000..c1c5f9b --- /dev/null +++ b/SOURCES/glibc-RHEL-65359-4.patch @@ -0,0 +1,20 @@ +commit fd30525eadff6a4b2ac9478bdd6490d0c9c116d9 +Author: Samuel Thibault +Date: Sun Dec 22 23:33:27 2024 +0100 + + assert/test-assert-2.c: Include + + For _exit declaration. + +diff --git a/assert/test-assert-2.c b/assert/test-assert-2.c +index 99f8f683e87a0c64..3288609ab28701ed 100644 +--- a/assert/test-assert-2.c ++++ b/assert/test-assert-2.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #undef NDEBUG + #include diff --git a/SOURCES/glibc-RHEL-65910.patch b/SOURCES/glibc-RHEL-65910.patch new file mode 100644 index 0000000..faf0780 --- /dev/null +++ b/SOURCES/glibc-RHEL-65910.patch @@ -0,0 +1,417 @@ +commit e5ea9aef5468404eecc8c990e6852315b7d1a0e3 +Author: Joseph Myers +Date: Wed Oct 30 16:48:38 2024 +0000 + + Add tests of time, gettimeofday, clock_gettime + + There are no tests specifically focused on the functions time, + gettimeofday and clock_gettime, although there are some incidental + uses in tests of other functions. Add tests specifically for these + three functions. + + Tested for x86_64 and x86. + +Conflicts: + time/Makefile (new tests added) + +diff --git a/time/Makefile b/time/Makefile +index ef3bb767b825f76a..b31ae723642e33bd 100644 +--- a/time/Makefile ++++ b/time/Makefile +@@ -50,22 +50,28 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ + tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \ + tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \ + tst-settimeofday tst-itimer tst-gmtime tst-timegm \ +- tst-timespec_get tst-timespec_getres tst-strftime4 ++ tst-timespec_get tst-timespec_getres tst-strftime4 \ ++ tst-clock_gettime \ ++ tst-gettimeofday \ ++ tst-time \ + + tests-time64 := \ + tst-adjtime-time64 \ + tst-clock-time64 \ + tst-clock2-time64 \ ++ tst-clock_gettime-time64 \ + tst-clock_nanosleep-time64 \ + tst-clock_settime-time64 \ + tst-cpuclock1-time64 \ + tst-ctime-time64 \ + tst-difftime-time64 \ ++ tst-gettimeofday-time64 \ + tst-gmtime-time64 \ + tst-itimer-time64 \ + tst-mktime4-time64 \ + tst-settimeofday-time64 \ + tst-strftime4-time64 \ ++ tst-time-time64 \ + tst-timegm-time64 \ + tst-timespec_get-time64 \ + tst-timespec_getres-time64 \ +diff --git a/time/tst-clock_gettime-time64.c b/time/tst-clock_gettime-time64.c +new file mode 100644 +index 0000000000000000..5b215d11f8a0a424 +--- /dev/null ++++ b/time/tst-clock_gettime-time64.c +@@ -0,0 +1 @@ ++#include "tst-clock_gettime.c" +diff --git a/time/tst-clock_gettime.c b/time/tst-clock_gettime.c +new file mode 100644 +index 0000000000000000..51f24c0be2084a91 +--- /dev/null ++++ b/time/tst-clock_gettime.c +@@ -0,0 +1,184 @@ ++/* Test clock_gettime 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* Compare two struct timespec values, returning a value -1, 0 or 1. */ ++ ++int ++compare_timespec (const struct timespec *tv1, const struct timespec *tv2) ++{ ++ if (tv1->tv_sec < tv2->tv_sec) ++ return -1; ++ if (tv1->tv_sec > tv2->tv_sec) ++ return 1; ++ if (tv1->tv_nsec < tv2->tv_nsec) ++ return -1; ++ if (tv1->tv_nsec > tv2->tv_nsec) ++ return 1; ++ return 0; ++} ++ ++struct test_clockid ++{ ++ clockid_t clockid; ++ const char *name; ++ bool is_cputime; ++ bool fail_ok; ++}; ++ ++#define CLOCK(clockid) { clockid, # clockid, false, false } ++#define CLOCK_CPU(clockid) { clockid, # clockid, true, false } ++#define CLOCK_FAIL_OK(clockid) { clockid, # clockid, false, true } ++ ++static const struct test_clockid clocks[] = ++ { ++ CLOCK (CLOCK_REALTIME), ++#ifdef CLOCK_MONOTONIC ++ CLOCK (CLOCK_MONOTONIC), ++#endif ++#ifdef CLOCK_PROCESS_CPUTIME_ID ++ CLOCK_CPU (CLOCK_PROCESS_CPUTIME_ID), ++#endif ++#ifdef CLOCK_THREAD_CPUTIME_ID ++ CLOCK_CPU (CLOCK_THREAD_CPUTIME_ID), ++#endif ++#ifdef CLOCK_MONOTONIC_RAW ++ CLOCK (CLOCK_MONOTONIC_RAW), ++#endif ++#ifdef CLOCK_REALTIME_COARSE ++ CLOCK (CLOCK_REALTIME_COARSE), ++#endif ++#ifdef CLOCK_MONOTONIC_COARSE ++ CLOCK (CLOCK_MONOTONIC_COARSE), ++#endif ++#ifdef CLOCK_BOOTTIME ++ CLOCK (CLOCK_BOOTTIME), ++#endif ++#ifdef CLOCK_REALTIME_ALARM ++ CLOCK_FAIL_OK (CLOCK_REALTIME_ALARM), ++#endif ++#ifdef CLOCK_BOOTTIME_ALARM ++ CLOCK_FAIL_OK (CLOCK_BOOTTIME_ALARM), ++#endif ++#ifdef CLOCK_TAI ++ CLOCK (CLOCK_TAI), ++#endif ++ }; ++ ++ ++volatile int sigalrm_received; ++ ++void ++handle_sigalrm (int sig) ++{ ++ sigalrm_received = 1; ++} ++ ++int ++do_test (void) ++{ ++ /* Verify that the calls to clock_gettime succeed, that the time does ++ not decrease, and that time returns a truncated (not rounded) ++ version of the time. */ ++ for (size_t i = 0; i < sizeof clocks / sizeof clocks[0]; i++) ++ { ++ printf ("testing %s\n", clocks[i].name); ++ struct timespec ts1, ts2, ts3; ++ int ret; ++ time_t t1; ++ t1 = time (NULL); ++ TEST_VERIFY_EXIT (t1 != (time_t) -1); ++ ret = clock_gettime (clocks[i].clockid, &ts1); ++ if (clocks[i].fail_ok && ret == -1) ++ { ++ printf ("failed (OK for this clock): %m\n"); ++ continue; ++ } ++ TEST_VERIFY_EXIT (ret == 0); ++ if (clocks[i].clockid == CLOCK_REALTIME) ++ TEST_VERIFY (t1 <= ts1.tv_sec); ++ TEST_VERIFY (ts1.tv_nsec >= 0); ++ TEST_VERIFY (ts1.tv_nsec < 1000000000); ++ ret = clock_gettime (clocks[i].clockid, &ts2); ++ TEST_VERIFY_EXIT (ret == 0); ++ TEST_VERIFY (compare_timespec (&ts1, &ts2) <= 0); ++ TEST_VERIFY (ts2.tv_nsec >= 0); ++ TEST_VERIFY (ts2.tv_nsec < 1000000000); ++ /* Also verify that after sleeping, the time returned has ++ increased. Repeat several times to verify that each time, ++ the time from the time function is truncated not rounded. ++ For CPU time clocks, the time spent spinning on the CPU, and ++ so whether we end in the later half of a second, is not ++ predictable; thus, only test once for those clocks. */ ++ const struct timespec duration = { .tv_nsec = 100000000 }; ++ for (int j = 0; j < 5; j++) ++ { ++ if (clocks[i].is_cputime) ++ { ++ timer_t timer; ++ ret = timer_create (CLOCK_PROCESS_CPUTIME_ID, NULL, &timer); ++ TEST_VERIFY_EXIT (ret == 0); ++ sigalrm_received = 0; ++ xsignal (SIGALRM, handle_sigalrm); ++ struct itimerspec t = ++ { .it_value = ++ { ++ .tv_sec = 0, ++ .tv_nsec = 200000000 ++ } ++ }; ++ ret = timer_settime (timer, 0, &t, NULL); ++ TEST_VERIFY_EXIT (ret == 0); ++ while (sigalrm_received == 0) ++ ; ++ xsignal (SIGALRM, SIG_DFL); ++ ret = timer_delete (timer); ++ TEST_VERIFY_EXIT (ret == 0); ++ } ++ else ++ { ++ ret = nanosleep (&duration, NULL); ++ TEST_VERIFY_EXIT (ret == 0); ++ } ++ t1 = time (NULL); ++ TEST_VERIFY_EXIT (t1 != (time_t) -1); ++ ret = clock_gettime (clocks[i].clockid, &ts3); ++ TEST_VERIFY_EXIT (ret == 0); ++ TEST_VERIFY (compare_timespec (&ts2, &ts3) < 0); ++ if (clocks[i].clockid == CLOCK_REALTIME) ++ TEST_VERIFY (t1 <= ts3.tv_sec); ++ TEST_VERIFY (ts3.tv_nsec >= 0); ++ TEST_VERIFY (ts3.tv_nsec < 1000000000); ++ ts2 = ts3; ++ if (clocks[i].is_cputime) ++ break; ++ } ++ } ++ return 0; ++} ++ ++#define TIMEOUT 60 ++ ++#include +diff --git a/time/tst-gettimeofday-time64.c b/time/tst-gettimeofday-time64.c +new file mode 100644 +index 0000000000000000..6c08761ef995ce7c +--- /dev/null ++++ b/time/tst-gettimeofday-time64.c +@@ -0,0 +1 @@ ++#include "tst-gettimeofday.c" +diff --git a/time/tst-gettimeofday.c b/time/tst-gettimeofday.c +new file mode 100644 +index 0000000000000000..978ae28587d486f2 +--- /dev/null ++++ b/time/tst-gettimeofday.c +@@ -0,0 +1,93 @@ ++/* Test gettimeofday 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 ++ . */ ++ ++#include ++#include ++ ++#include ++#include ++ ++/* Compare two struct timeval values, returning a value -1, 0 or 1. */ ++ ++int ++compare_timeval (const struct timeval *tv1, const struct timeval *tv2) ++{ ++ if (tv1->tv_sec < tv2->tv_sec) ++ return -1; ++ if (tv1->tv_sec > tv2->tv_sec) ++ return 1; ++ if (tv1->tv_usec < tv2->tv_usec) ++ return -1; ++ if (tv1->tv_usec > tv2->tv_usec) ++ return 1; ++ return 0; ++} ++ ++int ++do_test (void) ++{ ++ struct timeval tv1, tv2, tv3; ++ int ret; ++ time_t t1; ++ /* Verify that the calls to gettimeofday succeed, that the time does ++ not decrease, and that time returns a truncated (not rounded) ++ version of the time. */ ++ t1 = time (NULL); ++ TEST_VERIFY_EXIT (t1 != (time_t) -1); ++ ret = gettimeofday (&tv1, NULL); ++ TEST_VERIFY_EXIT (ret == 0); ++ TEST_VERIFY (t1 <= tv1.tv_sec); ++ TEST_VERIFY (tv1.tv_usec >= 0); ++ TEST_VERIFY (tv1.tv_usec < 1000000); ++ ret = gettimeofday (&tv2, NULL); ++ TEST_VERIFY_EXIT (ret == 0); ++ TEST_VERIFY (compare_timeval (&tv1, &tv2) <= 0); ++ TEST_VERIFY (tv2.tv_usec >= 0); ++ TEST_VERIFY (tv2.tv_usec < 1000000); ++ /* Also verify that after sleeping, the time returned has increased. ++ Repeat several times to verify that each time, the time from the ++ time function is truncated not rounded. */ ++ const struct timespec duration = { .tv_nsec = 100000000 }; ++ for (int i = 0; i < 10; i++) ++ { ++ ret = nanosleep (&duration, NULL); ++ TEST_VERIFY_EXIT (ret == 0); ++ t1 = time (NULL); ++ TEST_VERIFY_EXIT (t1 != (time_t) -1); ++ ret = gettimeofday (&tv3, NULL); ++ TEST_VERIFY_EXIT (ret == 0); ++ TEST_VERIFY (compare_timeval (&tv2, &tv3) < 0); ++ TEST_VERIFY (t1 <= tv3.tv_sec); ++ TEST_VERIFY (tv3.tv_usec >= 0); ++ TEST_VERIFY (tv3.tv_usec < 1000000); ++ tv2 = tv3; ++ } ++ /* Also test with the obsolete tz argument not being NULL. */ ++ struct timezone tz = { 0 }; ++ t1 = time (NULL); ++ TEST_VERIFY_EXIT (t1 != (time_t) -1); ++ ret = gettimeofday (&tv3, &tz); ++ TEST_VERIFY_EXIT (ret == 0); ++ TEST_VERIFY (t1 <= tv3.tv_sec); ++ TEST_VERIFY (compare_timeval (&tv2, &tv3) <= 0); ++ TEST_VERIFY (tv3.tv_usec >= 0); ++ TEST_VERIFY (tv3.tv_usec < 1000000); ++ return 0; ++} ++ ++#include +diff --git a/time/tst-time-time64.c b/time/tst-time-time64.c +new file mode 100644 +index 0000000000000000..30e8d3c86ef973cc +--- /dev/null ++++ b/time/tst-time-time64.c +@@ -0,0 +1 @@ ++#include "tst-time.c" +diff --git a/time/tst-time.c b/time/tst-time.c +new file mode 100644 +index 0000000000000000..7f24bed3530e1c1e +--- /dev/null ++++ b/time/tst-time.c +@@ -0,0 +1,51 @@ ++/* Test time 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 ++ . */ ++ ++#include ++#include ++ ++#include ++#include ++ ++int ++do_test (void) ++{ ++ time_t t1, t2, t3, t4, t5, t6; ++ /* Verify that the calls to time succeed, that the value returned ++ directly equals that returned through the pointer passed, and ++ that the time does not decrease. */ ++ t1 = time (&t2); ++ TEST_VERIFY_EXIT (t1 != (time_t) -1); ++ TEST_VERIFY (t1 == t2); ++ t3 = time (NULL); ++ TEST_VERIFY_EXIT (t3 != (time_t) -1); ++ TEST_VERIFY (t3 >= t1); ++ /* Also verify that after sleeping, the time returned has ++ increased. */ ++ sleep (2); ++ t4 = time (&t5); ++ TEST_VERIFY_EXIT (t4 != (time_t) -1); ++ TEST_VERIFY (t4 == t5); ++ TEST_VERIFY (t4 > t3); ++ t6 = time (NULL); ++ TEST_VERIFY_EXIT (t6 != (time_t) -1); ++ TEST_VERIFY (t6 >= t4); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-66253-1.patch b/SOURCES/glibc-RHEL-66253-1.patch new file mode 100644 index 0000000..37b2506 --- /dev/null +++ b/SOURCES/glibc-RHEL-66253-1.patch @@ -0,0 +1,140 @@ +commit ddf71c550a5940deca74cc676f1cae134a891717 +Author: H.J. Lu +Date: Tue Apr 30 09:21:16 2024 -0700 + + libio: Sort test variables in Makefile + + Sort test variables in libio/Makefile using scripts/sort-makefile-lines.py. + Reviewed-by: Sunil K Pandey + +Conflicts: + libio/Makefile + (missing tst-bz28828 downstream) + +diff --git a/libio/Makefile b/libio/Makefile +index 10c2ed140a855877..31e27b022c73669a 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -51,22 +51,75 @@ routines := \ + \ + libc_fatal fmemopen oldfmemopen vtables + +-tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ +- tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \ +- tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf \ +- tst-mmap-setvbuf bug-ungetwc1 bug-ungetwc2 tst-atime tst-eof \ +- tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \ +- tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \ +- tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \ +- bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \ +- tst-memstream1 tst-memstream2 tst-memstream3 tst-memstream4 \ +- tst-wmemstream1 tst-wmemstream2 tst-wmemstream3 tst-wmemstream4 \ +- tst-wmemstream5 bug-memstream1 bug-wmemstream1 \ +- tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ +- tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ +- tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \ +- tst-sprintf-ub tst-sprintf-chk-ub tst-bz24051 tst-bz24153 \ +- tst-wfile-sync tst-getdelim ++tests = \ ++ bug-fopena+ \ ++ bug-fseek \ ++ bug-ftell \ ++ bug-memstream1 \ ++ bug-mmap-fflush \ ++ bug-rewind \ ++ bug-rewind2 \ ++ bug-ungetc \ ++ bug-ungetc2 \ ++ bug-ungetc3 \ ++ bug-ungetc4 \ ++ bug-ungetwc1 \ ++ bug-ungetwc2 \ ++ bug-wfflush \ ++ bug-wmemstream1 \ ++ bug-wsetpos \ ++ test-fmemopen \ ++ tst-atime \ ++ tst-bz22415 \ ++ tst-bz24051 \ ++ tst-bz24153 \ ++ tst-eof \ ++ tst-ext \ ++ tst-ext2 \ ++ tst-fgetc-after-eof \ ++ tst-fgetwc \ ++ tst-fgetws \ ++ tst-fopenloc2 \ ++ tst-fputws \ ++ tst-freopen \ ++ tst-fseek \ ++ tst-ftell-active-handler \ ++ tst-ftell-append \ ++ tst-ftell-partial-wide \ ++ tst-fwrite-error \ ++ tst-getdelim \ ++ tst-memstream1 \ ++ tst-memstream2 \ ++ tst-memstream3 \ ++ tst-memstream4 \ ++ tst-mmap-eofsync \ ++ tst-mmap-fflushsync \ ++ tst-mmap-offend \ ++ tst-mmap-setvbuf \ ++ tst-mmap2-eofsync \ ++ tst-popen1 \ ++ tst-setvbuf1 \ ++ tst-sprintf-chk-ub \ ++ tst-sprintf-ub \ ++ tst-sscanf \ ++ tst-swscanf \ ++ tst-ungetwc1 \ ++ tst-ungetwc2 \ ++ tst-wfile-sync \ ++ tst-widetext \ ++ tst-wmemstream1 \ ++ tst-wmemstream2 \ ++ tst-wmemstream3 \ ++ tst-wmemstream4 \ ++ tst-wmemstream5 \ ++ tst_getwc \ ++ tst_putwc \ ++ tst_swprintf \ ++ tst_swscanf \ ++ tst_wprintf \ ++ tst_wprintf2 \ ++ tst_wscanf \ ++ # tests + + tests-internal = tst-vtables tst-vtables-interposed + +@@ -200,16 +253,26 @@ tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \ + $(objpfx)tst-bz24228-mem.out + endif + +-tests += tst-cleanup-default tst-cleanup-default-static ++tests += \ ++ tst-cleanup-default \ ++ tst-cleanup-default-static \ ++ # tests + tests-static += tst-cleanup-default-static + tests-special += $(objpfx)tst-cleanup-default-cmp.out $(objpfx)tst-cleanup-default-static-cmp.out + LDFLAGS-tst-cleanup-default = -Wl,--gc-sections + LDFLAGS-tst-cleanup-default-static = -Wl,--gc-sections + + ifeq ($(have-gnu-retain)$(have-z-start-stop-gc),yesyes) +-tests += tst-cleanup-start-stop-gc tst-cleanup-start-stop-gc-static \ +- tst-cleanup-nostart-stop-gc tst-cleanup-nostart-stop-gc-static +-tests-static += tst-cleanup-start-stop-gc-static tst-cleanup-nostart-stop-gc-static ++tests += \ ++ tst-cleanup-nostart-stop-gc \ ++ tst-cleanup-nostart-stop-gc-static \ ++ tst-cleanup-start-stop-gc \ ++ tst-cleanup-start-stop-gc-static \ ++ # tests ++tests-static += \ ++ tst-cleanup-nostart-stop-gc-static \ ++ tst-cleanup-start-stop-gc-static \ ++ # tests-static + tests-special += $(objpfx)tst-cleanup-start-stop-gc-cmp.out \ + $(objpfx)tst-cleanup-start-stop-gc-static-cmp.out \ + $(objpfx)tst-cleanup-nostart-stop-gc-cmp.out \ diff --git a/SOURCES/glibc-RHEL-66253-2.patch b/SOURCES/glibc-RHEL-66253-2.patch new file mode 100644 index 0000000..3e89f22 --- /dev/null +++ b/SOURCES/glibc-RHEL-66253-2.patch @@ -0,0 +1,28 @@ +commit b2c3ee3724900975deaf5eae57640bb0c2d7315e +Author: Andreas Schwab +Date: Tue Jun 4 11:01:11 2024 +0200 + + Remove memory leak in fdopen (bug 31840) + + Deallocate the memory for the FILE structure when seeking to the end fails + in append mode. + + Fixes: ea33158c96 ("Fix offset caching for streams and use it for ftell (BZ #16680)") + +diff --git a/libio/iofdopen.c b/libio/iofdopen.c +index 498791b2872f4b93..e3596fa4c91644b7 100644 +--- a/libio/iofdopen.c ++++ b/libio/iofdopen.c +@@ -156,7 +156,11 @@ _IO_new_fdopen (int fd, const char *mode) + { + off64_t new_pos = _IO_SYSSEEK (&new_f->fp.file, 0, _IO_seek_end); + if (new_pos == _IO_pos_BAD && errno != ESPIPE) +- return NULL; ++ { ++ _IO_un_link (&new_f->fp); ++ free (new_f); ++ return NULL; ++ } + } + return &new_f->fp.file; + } diff --git a/SOURCES/glibc-RHEL-66253-3.patch b/SOURCES/glibc-RHEL-66253-3.patch new file mode 100644 index 0000000..7f57aba --- /dev/null +++ b/SOURCES/glibc-RHEL-66253-3.patch @@ -0,0 +1,120 @@ +commit d0106b6ae26c8cc046269358a77188105c99d5e3 +Author: Florian Weimer +Date: Tue Jun 4 14:37:35 2024 +0200 + + libio: Test for fdopen memory leak without SEEK_END support (bug 31840) + + The bug report used /dev/mem, but /proc/self/mem works as well + (if available). + +diff --git a/libio/Makefile b/libio/Makefile +index 31e27b022c73669a..418102c4c0d8c25a 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -76,6 +76,7 @@ tests = \ + tst-eof \ + tst-ext \ + tst-ext2 \ ++ tst-fdopen-seek-failure \ + tst-fgetc-after-eof \ + tst-fgetwc \ + tst-fgetws \ +@@ -220,6 +221,9 @@ tst_wprintf2-ARGS = "Some Text" + + test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++tst-fdopen-seek-failure-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-fdopen-seek-failure.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace \ +@@ -228,6 +232,7 @@ 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 + +@@ -244,8 +249,12 @@ shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \ + oldiofsetpos64 + + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \ +- $(objpfx)tst-bz22415-mem.out ++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. +@@ -333,6 +342,11 @@ $(objpfx)test-fmemopen-mem.out: $(objpfx)test-fmemopen.out + $(common-objpfx)malloc/mtrace $(objpfx)test-fmemopen.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 > $@; \ ++ $(evaluate-test) ++ + $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-fopenloc.mtrace > $@; \ + $(evaluate-test) +diff --git a/libio/tst-fdopen-seek-failure.c b/libio/tst-fdopen-seek-failure.c +new file mode 100644 +index 0000000000000000..5c4d40ab34158571 +--- /dev/null ++++ b/libio/tst-fdopen-seek-failure.c +@@ -0,0 +1,48 @@ ++/* Test for fdopen memory leak without SEEK_END support (bug 31840). ++ 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 ++ . */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ ++ /* This file is special because it is seekable, but only ++ with SEEK_SET, not SEEK_END. */ ++ int fd = open ("/proc/self/mem", O_RDWR); ++ if (fd < 0) ++ FAIL_UNSUPPORTED ("/proc/self/mem not found: %m"); ++ FILE *fp = fdopen (fd, "a"); ++ /* The fdopen call should have failed because it tried to use ++ SEEK_END. */ ++ TEST_VERIFY (fp == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ xclose (fd); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-67592-1.patch b/SOURCES/glibc-RHEL-67592-1.patch new file mode 100644 index 0000000..31e6cb5 --- /dev/null +++ b/SOURCES/glibc-RHEL-67592-1.patch @@ -0,0 +1,27 @@ +From ca7334d34b7811fc261c84c498fd4a19acd70530 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 28 Feb 2022 11:50:41 +0100 +Subject: [PATCH] manual: SA_ONSTACK is ignored without alternate stack +Content-type: text/plain; charset=UTF-8 + +The current stack is used. No SIGILL is generated. +--- + manual/signal.texi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/manual/signal.texi b/manual/signal.texi +index 8a12baf044..5c2ba7dae6 100644 +--- a/manual/signal.texi ++++ b/manual/signal.texi +@@ -1329,7 +1329,7 @@ Setting this flag for a signal other than @code{SIGCHLD} has no effect. + If this flag is set for a particular signal number, the system uses the + signal stack when delivering that kind of signal. @xref{Signal Stack}. + If a signal with this flag arrives and you have not set a signal stack, +-the system terminates the program with @code{SIGILL}. ++the normal user stack is used instead, as if the flag had not been set. + @end deftypevr + + @deftypevr Macro int SA_RESTART +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-67592-2.patch b/SOURCES/glibc-RHEL-67592-2.patch new file mode 100644 index 0000000..7c34b4b --- /dev/null +++ b/SOURCES/glibc-RHEL-67592-2.patch @@ -0,0 +1,89 @@ +From 87cd94bba4091d22e24116298ade33b712ada235 Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Tue, 10 Dec 2024 17:07:21 -0500 +Subject: [PATCH] manual: Document more sigaction flags +Content-type: text/plain; charset=UTF-8 + +Adds documentation for three-argument handler + +Adds remainder of the SA_* flags + +Reviewed-by: Florian Weimer +--- + manual/signal.texi | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/manual/signal.texi b/manual/signal.texi +index 5c2ba7dae6..2012980efe 100644 +--- a/manual/signal.texi ++++ b/manual/signal.texi +@@ -1141,6 +1141,15 @@ This is used in the same way as the @var{action} argument to the + @code{signal} function. The value can be @code{SIG_DFL}, + @code{SIG_IGN}, or a function pointer. @xref{Basic Signal Handling}. + ++@item void (*sa_sigaction) (int @var{signum}, siginfo_t *@var{info}, void *@var{ucontext}) ++This is an alternate to @code{sa_handler} that is used when the ++@code{sa_flags} includes the @code{flag SA_SIGINFO}. Note that this ++and @code{sa_handler} overlap; only ever set one at a time. ++ ++The contents of the @var{info} and @var{ucontext} structures are ++kernel and architecture dependent. Please see ++@manpageurl{sigaction,2} for details. ++ + @item sigset_t sa_mask + This specifies a set of signals to be blocked while the handler runs. + Blocking is explained in @ref{Blocking for Handler}. Note that the +@@ -1324,6 +1333,24 @@ delivered for both terminated children and stopped children. + Setting this flag for a signal other than @code{SIGCHLD} has no effect. + @end deftypevr + ++@deftypevr Macro int SA_NOCLDWAIT ++This flag is meaningful only for the @code{SIGCHLD} signal. When the ++flag is set, the terminated child will not wait for the parent to reap ++it, or become a zombie if not reaped. The child will instead be ++reaped by the kernel immediately on termination, similar to setting ++SIGCHLD to SIG_IGN. ++ ++Setting this flag for a signal other than @code{SIGCHLD} has no effect. ++@end deftypevr ++ ++@deftypevr Macro int SA_NODEFER ++Normally a signal is added to the signal mask while running its own ++handler; this negates that, so that the same signal can be received ++while it's handler is running. Note that if the signal is included in ++@code{sa_mask}, it is masked regardless of this flag. Only useful when ++assigning a function as a signal handler. ++@end deftypevr ++ + @deftypevr Macro int SA_ONSTACK + @standards{BSD, signal.h} + If this flag is set for a particular signal number, the system uses the +@@ -1332,6 +1359,12 @@ If a signal with this flag arrives and you have not set a signal stack, + the normal user stack is used instead, as if the flag had not been set. + @end deftypevr + ++@deftypevr Macro int SA_RESETHAND ++Resets the handler for a signal to SIG_DFL, at the moment specified ++handler function begins. I.e. the handler is called once, then the ++action resets. ++@end deftypevr ++ + @deftypevr Macro int SA_RESTART + @standards{BSD, signal.h} + This flag controls what happens when a signal is delivered during +@@ -1347,6 +1380,12 @@ clear, returning from a handler makes the function fail. + @xref{Interrupted Primitives}. + @end deftypevr + ++@deftypevr Macro int SA_SIGINFO ++Indicates that the @code{sa_sigaction} three-argument form of the ++handler should be used in setting up a handler instead of the ++one-argument @code{sa_handler} form. ++@end deftypevr ++ + @node Initial Signal Actions + @subsection Initial Signal Actions + @cindex initial signal actions +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-67592-3.patch b/SOURCES/glibc-RHEL-67592-3.patch new file mode 100644 index 0000000..c496c9c --- /dev/null +++ b/SOURCES/glibc-RHEL-67592-3.patch @@ -0,0 +1,38 @@ +From 298bc488fdc047da37482f4003023cb9adef78f8 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 11 Sep 2024 10:05:08 +0200 +Subject: [PATCH] manual: Extract the @manpageurl{func,sec} macro +Content-type: text/plain; charset=UTF-8 + +From the existing @manpagefunctionstub{func,sec} macro, +so that URLs can be included in the manual without the +stub text. + +Reviewed-by: Carlos O'Donell +--- + manual/macros.texi | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/manual/macros.texi b/manual/macros.texi +index 579da3fb81..f48dd4ec22 100644 +--- a/manual/macros.texi ++++ b/manual/macros.texi +@@ -282,10 +282,13 @@ cwd\comments\ + @macro standardsx {element, standard, header} + @end macro + ++@macro manpageurl {func, sec} ++@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html} ++@end macro ++ + @macro manpagefunctionstub {func,sec} + This documentation is a stub. For additional information on this +-function, consult the manual page +-@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html}. ++function, consult the manual page @manpageurl{\func\,\sec\}. + @xref{Linux Kernel}. + @end macro + +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-67592-4.patch b/SOURCES/glibc-RHEL-67592-4.patch new file mode 100644 index 0000000..034186c --- /dev/null +++ b/SOURCES/glibc-RHEL-67592-4.patch @@ -0,0 +1,85 @@ +From 37a0933e1bf97346b45463bde0c4631be8abaa07 Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Tue, 10 Dec 2024 16:57:21 -0500 +Subject: [PATCH] manual: make @manpageurl more specific to each output +Content-type: text/plain; charset=UTF-8 + +Tweak the @manpageurl macro to customize the output for +each of html, info, and pdf output. HTML and PDF (at +least, these days) support clicking on the link title, +whereas info does not. Add text to the intro section +explaining which man pages are normative and which +aren't. + +Conflicts + manual/resource.texi + Removed; unneeded +--- + manual/intro.texi | 14 +++++++++++++- + manual/macros.texi | 12 ++++++++++-- + manual/resource.texi | 3 +-- + 3 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/manual/intro.texi b/manual/intro.texi +index 879c1b38d9..d95648468d 100644 +--- a/manual/intro.texi ++++ b/manual/intro.texi +@@ -966,13 +966,25 @@ functionality is available on commercial systems. + + @Theglibc{} includes by reference the Linux man-pages + @value{man_pages_version} documentation to document the listed +-syscalls for the Linux kernel. For reference purposes only the latest ++syscalls for the Linux kernel. For reference purposes only, the latest + @uref{https://www.kernel.org/doc/man-pages/,Linux man-pages Project} + documentation can be accessed from the + @uref{https://www.kernel.org,Linux kernel} website. Where the syscall + has more specific documentation in this manual that more specific + documentation is considered authoritative. + ++Throughout this manual, when we refer to a man page, for example: ++@quotation ++@manpageurl{sendmsg,2} ++@end quotation ++@noindent ++we are referring primarily to the specific version noted above (the ++``normative'' version), typically accessed by running (for example) ++@code{man 2 sendmsg} on a system with that version installed. For ++convenience, we will also link to the online latest copy of the man ++pages, but keep in mind that version will almost always be newer than, ++and thus different than, the normative version noted above. ++ + Additional details on the Linux system call interface can be found in + @xref{System Calls}. + +diff --git a/manual/macros.texi b/manual/macros.texi +index f48dd4ec22..2003ce2678 100644 +--- a/manual/macros.texi ++++ b/manual/macros.texi +@@ -282,14 +282,22 @@ cwd\comments\ + @macro standardsx {element, standard, header} + @end macro + ++@ifhtml + @macro manpageurl {func, sec} +-@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html} ++@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html,,\func\(\sec\)} ++@xref{Linux Kernel} + @end macro ++@end ifhtml ++@ifnothtml ++@macro manpageurl {func, sec} ++\func\(\sec\) (Latest, online: @url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html}) ++@xref{Linux Kernel} ++@end macro ++@end ifnothtml + + @macro manpagefunctionstub {func,sec} + This documentation is a stub. For additional information on this + function, consult the manual page @manpageurl{\func\,\sec\}. +-@xref{Linux Kernel}. + @end macro + + @end ifclear +-- +2.43.5 + diff --git a/SOURCES/glibc-RHEL-67692-1.patch b/SOURCES/glibc-RHEL-67692-1.patch new file mode 100644 index 0000000..bc94037 --- /dev/null +++ b/SOURCES/glibc-RHEL-67692-1.patch @@ -0,0 +1,32 @@ +commit 4f20a1dc5242fb4bb8763e0451df898fa48e740c +Author: Martin Sebor +Date: Tue Jan 25 17:39:36 2022 -0700 + + stdlib: Avoid -Wuse-after-free in __add_to_environ [BZ #26779] + + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/setenv.c b/stdlib/setenv.c +index 893f081af6b5a21b..14fff422a2193864 100644 +--- a/stdlib/setenv.c ++++ b/stdlib/setenv.c +@@ -150,7 +150,9 @@ __add_to_environ (const char *name, const char *value, const char *combined, + { + char **new_environ; + +- /* We allocated this space; we can extend it. */ ++ /* We allocated this space; we can extend it. Avoid using the raw ++ reallocated pointer to avoid GCC -Wuse-after-free. */ ++ uintptr_t ip_last_environ = (uintptr_t)last_environ; + new_environ = (char **) realloc (last_environ, + (size + 2) * sizeof (char *)); + if (new_environ == NULL) +@@ -159,7 +161,7 @@ __add_to_environ (const char *name, const char *value, const char *combined, + return -1; + } + +- if (__environ != last_environ) ++ if ((uintptr_t)__environ != ip_last_environ) + memcpy ((char *) new_environ, (char *) __environ, + size * sizeof (char *)); + diff --git a/SOURCES/glibc-RHEL-67692-2.patch b/SOURCES/glibc-RHEL-67692-2.patch new file mode 100644 index 0000000..23e12cc --- /dev/null +++ b/SOURCES/glibc-RHEL-67692-2.patch @@ -0,0 +1,98 @@ +commit a6ccce23afc2a09a17ac2a86a2b726b58df609df +Author: Adhemerval Zanella +Date: Thu Feb 9 10:36:57 2023 -0300 + + stdlib: Simplify getenv + + And remove _STRING_ARCH_unaligned usage. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Wilco Dijkstra + +diff --git a/stdlib/getenv.c b/stdlib/getenv.c +index e359cc925f5a7dcf..0cfaf1412a65cca5 100644 +--- a/stdlib/getenv.c ++++ b/stdlib/getenv.c +@@ -15,76 +15,22 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include +-#include + #include + #include + #include + +- +-/* Return the value of the environment variable NAME. This implementation +- is tuned a bit in that it assumes no environment variable has an empty +- name which of course should always be true. We have a special case for +- one character names so that for the general case we can assume at least +- two characters which we can access. By doing this we can avoid using the +- `strncmp' most of the time. */ + char * + getenv (const char *name) + { +- char **ep; +- uint16_t name_start; +- + if (__environ == NULL || name[0] == '\0') + return NULL; + +- if (name[1] == '\0') +- { +- /* The name of the variable consists of only one character. Therefore +- the first two characters of the environment entry are this character +- and a '=' character. */ +-#if __BYTE_ORDER == __LITTLE_ENDIAN || !_STRING_ARCH_unaligned +- name_start = ('=' << 8) | *(const unsigned char *) name; +-#else +- name_start = '=' | ((*(const unsigned char *) name) << 8); +-#endif +- for (ep = __environ; *ep != NULL; ++ep) +- { +-#if _STRING_ARCH_unaligned +- uint16_t ep_start = *(uint16_t *) *ep; +-#else +- uint16_t ep_start = (((unsigned char *) *ep)[0] +- | (((unsigned char *) *ep)[1] << 8)); +-#endif +- if (name_start == ep_start) +- return &(*ep)[2]; +- } +- } +- else ++ size_t len = strlen (name); ++ for (char **ep = __environ; *ep != NULL; ++ep) + { +- size_t len = strlen (name); +-#if _STRING_ARCH_unaligned +- name_start = *(const uint16_t *) name; +-#else +- name_start = (((const unsigned char *) name)[0] +- | (((const unsigned char *) name)[1] << 8)); +-#endif +- len -= 2; +- name += 2; +- +- for (ep = __environ; *ep != NULL; ++ep) +- { +-#if _STRING_ARCH_unaligned +- uint16_t ep_start = *(uint16_t *) *ep; +-#else +- uint16_t ep_start = (((unsigned char *) *ep)[0] +- | (((unsigned char *) *ep)[1] << 8)); +-#endif +- +- if (name_start == ep_start && !strncmp (*ep + 2, name, len) +- && (*ep)[len + 2] == '=') +- return &(*ep)[len + 3]; +- } ++ if (name[0] == (*ep)[0] ++ && strncmp (name, *ep, len) == 0 && (*ep)[len] == '=') ++ return *ep + len + 1; + } + + return NULL; diff --git a/SOURCES/glibc-RHEL-67692-3.patch b/SOURCES/glibc-RHEL-67692-3.patch new file mode 100644 index 0000000..be1e8fb --- /dev/null +++ b/SOURCES/glibc-RHEL-67692-3.patch @@ -0,0 +1,75 @@ +commit 9401024e5e6be0e1c3870e185daae865cd4501f4 +Author: Joe Simmons-Talbott +Date: Fri Jun 30 14:31:45 2023 +0000 + + setenv.c: Get rid of alloca. + + Use malloc rather than alloca to avoid potential stack overflow. + + Reviewed-by: Adhemerval Zanella + +diff --git a/stdlib/setenv.c b/stdlib/setenv.c +index 14fff422a2193864..a55a661eaea13af2 100644 +--- a/stdlib/setenv.c ++++ b/stdlib/setenv.c +@@ -182,18 +182,11 @@ __add_to_environ (const char *name, const char *value, const char *combined, + { + const size_t varlen = namelen + 1 + vallen; + #ifdef USE_TSEARCH +- char *new_value; +- int use_alloca = __libc_use_alloca (varlen); +- if (__builtin_expect (use_alloca, 1)) +- new_value = (char *) alloca (varlen); +- else ++ char *new_value = malloc (varlen); ++ if (new_value == NULL) + { +- new_value = malloc (varlen); +- if (new_value == NULL) +- { +- UNLOCK; +- return -1; +- } ++ UNLOCK; ++ return -1; + } + # ifdef _LIBC + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), +@@ -209,35 +202,14 @@ __add_to_environ (const char *name, const char *value, const char *combined, + #endif + { + #ifdef USE_TSEARCH +- if (__glibc_unlikely (! use_alloca)) +- np = new_value; +- else ++ np = new_value; + #endif +- { +- np = malloc (varlen); +- if (__glibc_unlikely (np == NULL)) +- { +- UNLOCK; +- return -1; +- } +- +-#ifdef USE_TSEARCH +- memcpy (np, new_value, varlen); +-#else +- memcpy (np, name, namelen); +- np[namelen] = '='; +- memcpy (&np[namelen + 1], value, vallen); +-#endif +- } + /* And remember the value. */ + STORE_VALUE (np); + } + #ifdef USE_TSEARCH + else +- { +- if (__glibc_unlikely (! use_alloca)) +- free (new_value); +- } ++ free (new_value); + #endif + } + diff --git a/SOURCES/glibc-RHEL-67692-4.patch b/SOURCES/glibc-RHEL-67692-4.patch new file mode 100644 index 0000000..88637d8 --- /dev/null +++ b/SOURCES/glibc-RHEL-67692-4.patch @@ -0,0 +1,897 @@ +commit 7a61e7f557a97ab597d6fca5e2d1f13f65685c61 +Author: Florian Weimer +Date: Thu Nov 21 21:10:52 2024 +0100 + + stdlib: Make getenv thread-safe in more cases + + Async-signal-safety is preserved, too. In fact, getenv is fully + reentrant and can be called from the malloc call in setenv + (if a replacement malloc uses getenv during its initialization). + + This is relatively easy to implement because even before this change, + setenv, unsetenv, clearenv, putenv do not deallocate the environment + strings themselves as they are removed from the environment. + + The main changes are: + + * Use release stores for environment array updates, following + the usual pattern for safely publishing immutable data + (in this case, the environment strings). + + * Do not deallocate the environment array. Instead, keep older + versions around and adopt an exponential resizing policy. This + results in an amortized constant space leak per active environment + variable, but there already is such a leak for the variable itself + (and that is even length-dependent, and includes no-longer used + values). + + * Add a seqlock-like mechanism to retry getenv if a concurrent + unsetenv is observed. Without that, it is possible that + getenv returns NULL for a variable that is never unset. This + is visible on some AArch64 implementations with the newly + added stdlib/tst-getenv-unsetenv test case. The mechanism + is not a pure seqlock because it tolerates one write from + unsetenv. This avoids the need for a second copy of the + environ array that getenv can read from a signal handler + that happens to interrupt an unsetenv call. + + No manual updates are included with this patch because environ + usage with execve, posix_spawn, system is still not thread-safe + relative unsetenv. The new process may end up with an environment + that misses entries that were never unset. This is the same issue + described above for getenv. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + stdlib/Makefile + (missing tests downstream) + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 3375da0a934c17cb..603a330b1e8f1ba2 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -95,6 +95,9 @@ tests := \ + tst-canon-bz26341 \ + tst-cxa_atexit \ + tst-environ \ ++ tst-getenv-signal \ ++ tst-getenv-thread \ ++ tst-getenv-unsetenv \ + tst-getrandom \ + tst-limits \ + tst-makecontext \ +@@ -302,3 +305,7 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3 + '$(run-program-env)' '$(test-program-prefix-after-env)' \ + $(common-objpfx)stdlib/; \ + $(evaluate-test) ++ ++$(objpfx)tst-getenv-signal: $(shared-thread-library) ++$(objpfx)tst-getenv-thread: $(shared-thread-library) ++$(objpfx)tst-getenv-unsetenv: $(shared-thread-library) +diff --git a/stdlib/getenv.c b/stdlib/getenv.c +index 0cfaf1412a65cca5..07e20cc7f6943224 100644 +--- a/stdlib/getenv.c ++++ b/stdlib/getenv.c +@@ -15,24 +15,144 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include ++#include + #include + #include + ++struct environ_array *__environ_array_list; ++environ_counter __environ_counter; ++ + char * + getenv (const char *name) + { +- if (__environ == NULL || name[0] == '\0') +- return NULL; +- +- size_t len = strlen (name); +- for (char **ep = __environ; *ep != NULL; ++ep) ++ while (true) + { +- if (name[0] == (*ep)[0] +- && strncmp (name, *ep, len) == 0 && (*ep)[len] == '=') +- return *ep + len + 1; +- } ++ /* Used to deal with concurrent unsetenv. */ ++ environ_counter start_counter = atomic_load_acquire (&__environ_counter); ++ ++ /* We use relaxed MO for loading the string pointers because we ++ assume the strings themselves are immutable and that loads ++ through the string pointers carry a dependency. (This ++ depends on the the release MO store to __environ in ++ __add_to_environ.) Objects pointed to by pointers stored in ++ the __environ array are never modified or deallocated (except ++ perhaps if putenv is used, but then synchronization is the ++ responsibility of the applications). The backing store for ++ __environ is allocated zeroed. In summary, we can assume ++ that the pointers we observe are either valid or null, and ++ that only initialized string contents is visible. */ ++ char **start_environ = atomic_load_relaxed (&__environ); ++ if (start_environ == NULL || name[0] == '\0') ++ return NULL; ++ ++ size_t len = strlen (name); ++ for (char **ep = start_environ; ; ++ep) ++ { ++ char *entry = atomic_load_relaxed (ep); ++ if (entry == NULL) ++ break; ++ ++ /* If there is a match, return that value. It was valid at ++ one point, so we can return it. */ ++ if (name[0] == entry[0] ++ && strncmp (name, entry, len) == 0 && entry[len] == '=') ++ return entry + len + 1; ++ } ++ ++ /* The variable was not found. This might be a false negative ++ because unsetenv has shuffled around entries. Check if it is ++ necessary to retry. */ ++ ++ /* See Hans Boehm, Can Seqlocks Get Along with Programming Language ++ Memory Models?, Section 4. This is necessary so that loads in ++ the loop above are not ordered past the counter check below. */ ++ atomic_thread_fence_acquire (); ++ ++ if (atomic_load_acquire (&__environ_counter) == start_counter) ++ /* If we reach this point and there was a concurrent ++ unsetenv call which removed the key we tried to find, the ++ NULL return value is valid. We can also try again, not ++ find the value, and then return NULL (assuming there are ++ no further concurrent unsetenv calls). ++ ++ However, if getenv is called to find a value that is ++ present originally and not removed by any of the ++ concurrent unsetenv calls, we must not return NULL here. ++ ++ If the counter did not change, there was at most one ++ write to the array in unsetenv while the scanning loop ++ above was running. This means that there are at most two ++ different versions of the array to consider. For the ++ sake of argument, we assume that each load can make an ++ independent choice which version to use. An arbitrary ++ number of unsetenv and setenv calls may have happened ++ since start of getenv. Lets write E[0], E[1], ... for ++ the original environment elements, a(0) < (1) < ... for a ++ sequence of increasing integers that are the indices of ++ the environment variables remaining after the removals, and ++ N[0], N[1], ... for the new variables added by setenv or ++ putenv. Then at the start of the last unsetenv call, the ++ environment contains ++ ++ E[a(0)], E[a(1)], ..., N[0], N[1], ... + +- return NULL; ++ (the N[0], N[1], .... are optional.) Let's assume that ++ we are looking for the value E[j]. Then one of the ++ a(i) == j (otherwise we may return NULL here because ++ of a unsetenv for the value we are looking for). In the ++ discussion below it will become clear that the N[k] do ++ not actually matter. ++ ++ The two versions of array we can choose from differ only ++ in one element, say E[a(i)]. There are two cases: ++ ++ Case (A): E[a(i)] is an element being removed by unsetenv ++ (the target of the first write). We can see the original ++ version: ++ ++ ..., E[a(i-1)], E[a(i)], E[a(i+1)], ..., N[0], ... ++ ------- ++ And the overwritten version: ++ ++ ..., E[a(i-1)], E[a(i+1)], E[a(i+1)], ..., N[0], ... ++ --------- ++ ++ (The valueE[a(i+1)] can be the terminating NULL.) ++ As discussed, we are not considering the removal of the ++ variable being searched for, so a(i) != j, and the ++ variable getenv is looking for is available in either ++ version, and we would have found it above. ++ ++ Case (B): E[a(i)] is an element that has already been ++ moved forward and is now itself being overwritten with ++ its sucessor value E[a(i+1)]. The two versions of the ++ array look like this: ++ ++ ..., E[a(i-1)], E[a(i)], E[a(i)], E[a(i+1)], ..., N[0], ... ++ ------- ++ And with the overwrite in place: ++ ++ ..., E[a(i-1)], E[a(i)], E[a(i+1)], E[a(i+1)], ..., N[0], ... ++ --------- ++ ++ The key observation here is that even in the second ++ version with the overwrite present, the scanning loop ++ will still encounter the overwritten value E[a(i)] in the ++ previous array element. This means that as long as the ++ E[j] is still present among the initial E[a(...)] (as we ++ assumed because there is no concurrent unsetenv for ++ E[j]), we encounter it while scanning here in getenv. ++ ++ In summary, if there was at most one write, a negative ++ result is a true negative, and we can return NULL. This ++ is different from the seqlock paper, which retries if ++ there was any write at all. It avoids the need for a ++ second, unwritten copy for async-signal-safety. */ ++ return NULL; ++ /* If there was one more write, retry. This will never happen ++ in a signal handler that interrupted unsetenv because the ++ suspended unsetenv call cannot change the counter value. */ ++ } + } + libc_hidden_def (getenv) +diff --git a/stdlib/setenv.c b/stdlib/setenv.c +index a55a661eaea13af2..e3833bc514870bf4 100644 +--- a/stdlib/setenv.c ++++ b/stdlib/setenv.c +@@ -19,6 +19,9 @@ + # include + #endif + ++#include ++#include ++ + /* Pacify GCC; see the commentary about VALLEN below. This is needed + at least through GCC 4.9.2. Pacify GCC for the entire file, as + there seems to be no way to pacify GCC selectively, only for the +@@ -100,25 +103,51 @@ static void *known_values; + + #endif + ++/* Allocate a new environment array and put it o the ++ __environ_array_list. Returns NULL on memory allocation ++ failure. */ ++static struct environ_array * ++__environ_new_array (size_t required_size) ++{ ++ /* No backing array yet, or insufficient room. */ ++ size_t new_size; ++ if (__environ_array_list == NULL ++ || __environ_array_list->allocated * 2 < required_size) ++ /* Add some unused space for future growth. */ ++ new_size = required_size + 16; ++ else ++ new_size = __environ_array_list->allocated * 2; ++ ++ size_t new_size_in_bytes; ++ if (__builtin_mul_overflow (new_size, sizeof (char *), ++ &new_size_in_bytes) ++ || __builtin_add_overflow (new_size_in_bytes, ++ offsetof (struct environ_array, ++ array), ++ &new_size_in_bytes)) ++ { ++ __set_errno (ENOMEM); ++ return NULL; ++ } + +-/* If this variable is not a null pointer we allocated the current +- environment. */ +-static char **last_environ; +- ++ /* Zero-initialize everything, so that getenv can only ++ observe valid or null pointers. */ ++ struct environ_array *target_array = calloc (1, new_size_in_bytes); ++ if (target_array == NULL) ++ return NULL; ++ target_array->allocated = new_size; ++ assert (new_size >= target_array->allocated); ++ ++ /* Put it onto the list. */ ++ target_array->next = __environ_array_list; ++ __environ_array_list = target_array; ++ return target_array; ++} + +-/* This function is used by `setenv' and `putenv'. The difference between +- the two functions is that for the former must create a new string which +- is then placed in the environment, while the argument of `putenv' +- must be used directly. This is all complicated by the fact that we try +- to reuse values once generated for a `setenv' call since we can never +- free the strings. */ + int + __add_to_environ (const char *name, const char *value, const char *combined, + int replace) + { +- char **ep; +- size_t size; +- + /* Compute lengths before locking, so that the critical section is + less of a performance bottleneck. VALLEN is needed only if + COMBINED is null (unfortunately GCC is not smart enough to deduce +@@ -133,45 +162,85 @@ __add_to_environ (const char *name, const char *value, const char *combined, + LOCK; + + /* We have to get the pointer now that we have the lock and not earlier +- since another thread might have created a new environment. */ +- ep = __environ; ++ since another thread might have created a new environment. */ ++ char **start_environ = atomic_load_relaxed (&__environ); ++ char **ep = start_environ; + +- size = 0; ++ /* This gets written to __environ in the end. */ ++ char **result_environ = start_environ; ++ ++ /* Size of the environment if *ep == NULL. */ + if (ep != NULL) +- { +- for (; *ep != NULL; ++ep) +- if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') +- break; +- else +- ++size; +- } ++ for (; *ep != NULL; ++ep) ++ if (strncmp (*ep, name, namelen) == 0 && (*ep)[namelen] == '=') ++ break; + +- if (ep == NULL || __builtin_expect (*ep == NULL, 1)) ++ if (ep == NULL || __glibc_likely (*ep == NULL)) + { +- char **new_environ; +- +- /* We allocated this space; we can extend it. Avoid using the raw +- reallocated pointer to avoid GCC -Wuse-after-free. */ +- uintptr_t ip_last_environ = (uintptr_t)last_environ; +- new_environ = (char **) realloc (last_environ, +- (size + 2) * sizeof (char *)); +- if (new_environ == NULL) ++ /* The scanning loop above reached the end of the environment. ++ Add a new string to it. */ ++ replace = true; ++ ++ /* + 2 for the new entry and the terminating NULL. */ ++ size_t required_size = (ep - start_environ) + 2; ++ if (__environ_is_from_array_list (start_environ) ++ && required_size <= __environ_array_list->allocated) ++ /* The __environ array is ours, and we have room in it. We ++ can use ep as-is. Add a null terminator in case current ++ usage is less than previous usage. */ ++ ep[1] = NULL; ++ else + { +- UNLOCK; +- return -1; +- } ++ /* We cannot use __environ as is and need to copy over the ++ __environ contents into an array managed via ++ __environ_array_list. */ ++ ++ struct environ_array *target_array; ++ if (__environ_array_list != NULL ++ && required_size <= __environ_array_list->allocated) ++ /* Existing array has enough room. Contents is copied below. */ ++ target_array = __environ_array_list; ++ else ++ { ++ /* Allocate a new array. */ ++ target_array = __environ_new_array (required_size); ++ if (target_array == NULL) ++ { ++ UNLOCK; ++ return -1; ++ } ++ } ++ ++ /* Copy over the __environ array contents. This forward ++ copy slides backwards part of the array if __environ ++ points into target_array->array. This happens if an ++ application makes an assignment like: + +- if ((uintptr_t)__environ != ip_last_environ) +- memcpy ((char *) new_environ, (char *) __environ, +- size * sizeof (char *)); ++ environ = &environ[1]; + +- new_environ[size] = NULL; +- new_environ[size + 1] = NULL; +- ep = new_environ + size; ++ The forward copy avoids clobbering values that still ++ needing copying. This code handles the case ++ start_environ == ep == NULL, too. */ ++ size_t i; ++ for (i = 0; start_environ + i < ep; ++i) ++ /* Regular store because unless there has been direct ++ manipulation of the environment, target_array is still ++ a private copy. */ ++ target_array->array[i] = atomic_load_relaxed (start_environ + i); + +- last_environ = __environ = new_environ; ++ /* This is the new place where we should add the element. */ ++ ep = target_array->array + i; ++ ++ /* Add the null terminator in case there was a pointer there ++ previously. */ ++ ep[1] = NULL; ++ ++ /* And __environ should be repointed to our array. */ ++ result_environ = &target_array->array[0]; ++ } + } +- if (*ep == NULL || replace) ++ ++ if (replace || *ep == NULL) + { + char *np; + +@@ -213,7 +282,12 @@ __add_to_environ (const char *name, const char *value, const char *combined, + #endif + } + +- *ep = np; ++ /* Use release MO so that loads are sufficient to observe the ++ pointer contents because the CPU carries the dependency for ++ us. This also acts as a thread fence, making getenv ++ async-signal-safe. */ ++ atomic_store_release (ep, np); ++ atomic_store_release (&__environ, result_environ); + } + + UNLOCK; +@@ -249,18 +323,40 @@ unsetenv (const char *name) + + LOCK; + +- ep = __environ; ++ ep = atomic_load_relaxed (&__environ); + if (ep != NULL) +- while (*ep != NULL) ++ while (true) + { +- if (!strncmp (*ep, name, len) && (*ep)[len] == '=') ++ char *entry = atomic_load_relaxed (ep); ++ if (entry == NULL) ++ break; ++ if (strncmp (entry, name, len) == 0 && entry[len] == '=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + +- do +- dp[0] = dp[1]; +- while (*dp++); ++ while (true) ++ { ++ char *next_value = atomic_load_relaxed (dp + 1); ++ /* This store overwrites a value that has been ++ removed, or that has already been written to a ++ previous value. Release MO so that this store does ++ not get reordered before the counter update in the ++ previous loop iteration. */ ++ atomic_store_release (dp, next_value); ++ /* Release store synchronizes with acquire loads in ++ getenv. Non-atomic update because there is just ++ one writer due to the lock. ++ ++ See discussion of the counter check in getenv for ++ an explanation why this is sufficient synchronization. */ ++ atomic_store_release (&__environ_counter, ++ atomic_load_relaxed (&__environ_counter) ++ + 1); ++ if (next_value == NULL) ++ break; ++ ++dp; ++ } + /* Continue the loop in case NAME appears again. */ + } + else +@@ -279,17 +375,20 @@ int + clearenv (void) + { + LOCK; +- +- if (__environ == last_environ && __environ != NULL) ++ char **start_environ = atomic_load_relaxed (&__environ); ++ if (__environ_is_from_array_list (start_environ)) + { +- /* We allocated this environment so we can free it. */ +- free (__environ); +- last_environ = NULL; ++ /* Store null pointers to avoid strange effects when the array ++ is reused in setenv. */ ++ for (char **ep = start_environ; *ep != NULL; ++ep) ++ atomic_store_relaxed (ep, NULL); ++ /* Update the counter similar to unsetenv, so that the writes in ++ setenv do not need to update the counter. */ ++ atomic_store_release (&__environ_counter, ++ atomic_load_relaxed (&__environ_counter) + 1); + } + +- /* Clear the environment pointer removes the whole environment. */ +- __environ = NULL; +- ++ atomic_store_relaxed (&__environ, NULL); + UNLOCK; + + return 0; +@@ -300,6 +399,14 @@ libc_freeres_fn (free_mem) + /* Remove all traces. */ + clearenv (); + ++ /* Clear all backing arrays. */ ++ while (__environ_array_list != NULL) ++ { ++ void *ptr = __environ_array_list; ++ __environ_array_list = __environ_array_list->next; ++ free (ptr); ++ } ++ + /* Now remove the search tree. */ + __tdestroy (known_values, free); + known_values = NULL; +diff --git a/stdlib/setenv.h b/stdlib/setenv.h +new file mode 100644 +index 0000000000000000..036f4274aa29b722 +--- /dev/null ++++ b/stdlib/setenv.h +@@ -0,0 +1,73 @@ ++/* Common declarations for the setenv/getenv family of 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 ++ 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 ++ . */ ++ ++#ifndef _SETENV_H ++#define _SETENV_H ++ ++#include ++#include ++ ++/* We use an exponential sizing policy for environment arrays. The ++ arrays are not deallocating during the lifetime of the process. ++ This adds between one and two additional pointers per active ++ environemnt entry, on top of what is used by setenv to keep track ++ of environment values used before. */ ++struct environ_array ++{ ++ struct environ_array *next; /* Previously used environment array. */ ++ size_t allocated; /* Number of allocated array elments. */ ++ char *array[]; /* The actual environment array. */ ++}; ++ ++/* After initialization, and until the user resets environ (perhaps by ++ calling clearenv), &__environ[0] == &environ_array_list->array[0]. */ ++extern struct environ_array *__environ_array_list attribute_hidden; ++ ++/* Returns true if EP (which should be an __environ value) is a ++ pointer managed by setenv. */ ++static inline bool ++__environ_is_from_array_list (char **ep) ++{ ++ struct environ_array *eal = atomic_load_relaxed (&__environ_array_list); ++ return eal != NULL && &eal->array[0] == ep; ++} ++ ++/* Counter for detecting concurrent modification in unsetenv. ++ Ideally, this should be a 64-bit counter that cannot wrap around, ++ but given that counter wrapround is probably impossible to hit ++ (2**32 operations in unsetenv concurrently with getenv), using ++ seems unnecessary. */ ++#if __HAVE_64B_ATOMICS ++typedef uint64_t environ_counter; ++#else ++typedef uint32_t environ_counter; ++#endif ++ ++/* Updated by unsetenv to detect multiple overwrites in getenv. */ ++extern environ_counter __environ_counter attribute_hidden; ++ ++/* This function is used by `setenv' and `putenv'. The difference between ++ the two functions is that for the former must create a new string which ++ is then placed in the environment, while the argument of `putenv' ++ must be used directly. This is all complicated by the fact that we try ++ to reuse values once generated for a `setenv' call since we can never ++ free the strings. */ ++int __add_to_environ (const char *name, const char *value, ++ const char *combines, int replace) attribute_hidden; ++ ++#endif /* _SETENV_H */ +diff --git a/stdlib/tst-environ.c b/stdlib/tst-environ.c +index 223e8de9a227ff90..b5f0ca24202d462d 100644 +--- a/stdlib/tst-environ.c ++++ b/stdlib/tst-environ.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #define VAR "FOOBAR" + +@@ -50,11 +51,7 @@ do_test (void) + + /* Getting this value should now be possible. */ + valp = getenv (VAR); +- if (valp == NULL || strcmp (valp, "one") != 0) +- { +- puts ("getenv #2 failed"); +- result = 1; +- } ++ TEST_COMPARE_STRING (valp, "one"); + + /* Try to replace without the replace flag set. This should fail. */ + if (setenv (VAR, "two", 0) != 0) +@@ -65,11 +62,7 @@ do_test (void) + + /* The value shouldn't have changed. */ + valp = getenv (VAR); +- if (valp == NULL || strcmp (valp, "one") != 0) +- { +- puts ("getenv #3 failed"); +- result = 1; +- } ++ TEST_COMPARE_STRING (valp, "one"); + + /* Now replace the value using putenv. */ + if (putenv (putenv_val) != 0) +diff --git a/stdlib/tst-getenv-signal.c b/stdlib/tst-getenv-signal.c +new file mode 100644 +index 0000000000000000..86bb03ff2dbbac08 +--- /dev/null ++++ b/stdlib/tst-getenv-signal.c +@@ -0,0 +1,94 @@ ++/* Test getenv from a signal handler interrupting environment updates. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to false by the main thread after doing all the setenv ++ calls. */ ++static bool running = true; ++ ++/* Used to synchronize the start of signal sending. */ ++static pthread_barrier_t barrier; ++ ++/* Identity of the main thread. */ ++static pthread_t main_thread; ++ ++/* Send SIGUSR1 signals to main_thread. */ ++static void * ++signal_thread (void *ignored) ++{ ++ xpthread_barrier_wait (&barrier); ++ while (__atomic_load_n (&running, __ATOMIC_RELAXED)) ++ xpthread_kill (main_thread, SIGUSR1); ++ return NULL; ++} ++ ++/* Call getenv from a signal handler. */ ++static void ++signal_handler (int signo) ++{ ++ TEST_COMPARE_STRING (getenv ("unset_variable"), NULL); ++ char *value = getenv ("set_variable"); ++ TEST_VERIFY (strncmp (value, "value", strlen ("value")) == 0); ++} ++ ++static int ++do_test (void) ++{ ++ /* Added to the environment using putenv. */ ++ char *variables[30]; ++ for (int i = 0; i < array_length (variables); ++i) ++ variables[i] = xasprintf ("v%d=%d", i, i); ++ ++ xsignal (SIGUSR1, signal_handler); ++ TEST_COMPARE (setenv ("set_variable", "value", 1), 0); ++ xraise (SIGUSR1); ++ main_thread = pthread_self (); ++ xpthread_barrier_init (&barrier, NULL, 2); ++ pthread_t thr = xpthread_create (NULL, signal_thread, NULL); ++ xpthread_barrier_wait (&barrier); ++ ++ for (int i = 0; i < array_length (variables); ++i) ++ { ++ char buf[30]; ++ TEST_COMPARE (setenv ("temporary_variable", "1", 1), 0); ++ snprintf (buf, sizeof (buf), "V%d", i); ++ TEST_COMPARE (setenv (buf, buf + 1, 1), 0); ++ TEST_COMPARE (putenv (variables[i]), 0); ++ snprintf (buf, sizeof (buf), "value%d", i); ++ TEST_COMPARE (setenv ("set_variable", buf, 1), 0); ++ TEST_COMPARE (unsetenv ("temporary_variable"), 0); ++ } ++ ++ __atomic_store_n (&running, false, __ATOMIC_RELAXED); ++ xpthread_join (thr); ++ xpthread_barrier_destroy (&barrier); ++ ++ for (int i = 0; i < array_length (variables); ++i) ++ free (variables[i]); ++ return 0; ++} ++ ++#include +diff --git a/stdlib/tst-getenv-thread.c b/stdlib/tst-getenv-thread.c +new file mode 100644 +index 0000000000000000..2668ae1d9f23ef6f +--- /dev/null ++++ b/stdlib/tst-getenv-thread.c +@@ -0,0 +1,62 @@ ++/* Test getenv with concurrent setenv. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to false by the main thread after doing all the setenv ++ calls. */ ++static bool running = true; ++ ++/* Used to synchronize the start of the getenv thread. */ ++static pthread_barrier_t barrier; ++ ++/* Invoke getenv for a nonexisting environment variable in a loop. ++ This checks that concurrent setenv does not invalidate the ++ environment array while getenv reads it. */ ++static void * ++getenv_thread (void *ignored) ++{ ++ xpthread_barrier_wait (&barrier); ++ while (__atomic_load_n (&running, __ATOMIC_RELAXED)) ++ TEST_VERIFY (getenv ("unset_variable") == NULL); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xpthread_barrier_init (&barrier, NULL, 2); ++ pthread_t thr = xpthread_create (NULL, getenv_thread, NULL); ++ xpthread_barrier_wait (&barrier); ++ for (int i = 0; i < 1000; ++i) ++ { ++ char buf[30]; ++ snprintf (buf, sizeof (buf), "V%d", i); ++ TEST_COMPARE (setenv (buf, buf + 1, 1), 0); ++ } ++ __atomic_store_n (&running, false, __ATOMIC_RELAXED); ++ xpthread_join (thr); ++ xpthread_barrier_destroy (&barrier); ++ return 0; ++} ++ ++#include +diff --git a/stdlib/tst-getenv-unsetenv.c b/stdlib/tst-getenv-unsetenv.c +new file mode 100644 +index 0000000000000000..4d42b5fd698b81c6 +--- /dev/null ++++ b/stdlib/tst-getenv-unsetenv.c +@@ -0,0 +1,75 @@ ++/* Test getenv with concurrent unsetenv. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to synchronize the start of each test iteration. */ ++static pthread_barrier_t barrier; ++ ++/* Number of iterations. */ ++enum { iterations = 10000 }; ++ ++/* Check that even with concurrent unsetenv, a variable that is known ++ to be there is found. */ ++static void * ++getenv_thread (void *ignored) ++{ ++ for (int i = 0; i < iterations; ++i) ++ { ++ xpthread_barrier_wait (&barrier); ++ TEST_COMPARE_STRING (getenv ("variable"), "value"); ++ xpthread_barrier_wait (&barrier); ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xpthread_barrier_init (&barrier, NULL, 2); ++ pthread_t thr = xpthread_create (NULL, getenv_thread, NULL); ++ ++ char *variables[50]; ++ for (int i = 0; i < array_length (variables); ++i) ++ variables[i] = xasprintf ("V%d", i); ++ ++ for (int i = 0; i < iterations; ++i) ++ { ++ clearenv (); ++ for (int j = 0; j < array_length (variables); ++j) ++ TEST_COMPARE (setenv (variables[j], variables[j] + 1, 1), 0); ++ TEST_COMPARE (setenv ("variable", "value", 1), 0); ++ xpthread_barrier_wait (&barrier); ++ /* Test runs. */ ++ for (int j = 0; j < array_length (variables); ++j) ++ TEST_COMPARE (unsetenv (variables[j]), 0); ++ xpthread_barrier_wait (&barrier); ++ } ++ xpthread_join (thr); ++ xpthread_barrier_destroy (&barrier); ++ for (int i = 0; i < array_length (variables); ++i) ++ free (variables[i]); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-68850-1.patch b/SOURCES/glibc-RHEL-68850-1.patch new file mode 100644 index 0000000..adcdece --- /dev/null +++ b/SOURCES/glibc-RHEL-68850-1.patch @@ -0,0 +1,76 @@ +commit 4b7cfcc3fbfab55a1bbb32a2da69c048060739d6 +Author: Florian Weimer +Date: Mon Nov 25 17:32:54 2024 +0100 + + debug: Wire up tst-longjmp_chk3 + + The test was added in commit ac8cc9e300a002228eb7e660df3e7b333d9a7414 + without all the required Makefile scaffolding. Tweak the test + so that it actually builds (including with dynamic SIGSTKSZ). + + Reviewed-by: Adhemerval Zanella + +Conflicts: + debug/Makefile (fixup context) + +diff --git a/debug/Makefile b/debug/Makefile +index 9fbc40dc69b477ca..ddae3817aef9afad 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -192,13 +192,14 @@ tests = backtrace-tst \ + test-strcpy_chk \ + test-stpcpy_chk \ + tst-longjmp_chk2 \ ++ tst-longjmp_chk3 \ + tst-backtrace2 \ + tst-backtrace3 \ + tst-backtrace4 \ + tst-backtrace5 \ + tst-backtrace6 \ + tst-realpath-chk \ +- $(tests-all-chk) ++ $(tests-all-chk) \ + + ifeq ($(have-ssp),yes) + tests += tst-ssp-1 +diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c +index 4434937c597dbe10..dfdecca9ef8a1cf6 100644 +--- a/debug/tst-longjmp_chk3.c ++++ b/debug/tst-longjmp_chk3.c +@@ -18,9 +18,12 @@ + + #include + #include ++#include + #include + +-static char buf[SIGSTKSZ * 4]; ++#include ++ ++static char *buf; + static jmp_buf jb; + + static void +@@ -49,8 +52,10 @@ do_test (void) + set_fortify_handler (handler); + + /* Create a valid signal stack and enable it. */ ++ size_t bufsize = SIGSTKSZ * 4; ++ buf = xmalloc (bufsize); + ss.ss_sp = buf; +- ss.ss_size = sizeof (buf); ++ ss.ss_size = bufsize; + ss.ss_flags = 0; + if (sigaltstack (&ss, NULL) < 0) + { +@@ -65,8 +70,8 @@ do_test (void) + + /* Shrink the signal stack so the jmpbuf is now invalid. + We adjust the start & end to handle stacks that grow up & down. */ +- ss.ss_sp = buf + sizeof (buf) / 2; +- ss.ss_size = sizeof (buf) / 4; ++ ss.ss_sp = buf + bufsize / 2; ++ ss.ss_size = bufsize / 4; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("second sigaltstack failed: %m\n"); diff --git a/SOURCES/glibc-RHEL-68850-2.patch b/SOURCES/glibc-RHEL-68850-2.patch new file mode 100644 index 0000000..f6e4789 --- /dev/null +++ b/SOURCES/glibc-RHEL-68850-2.patch @@ -0,0 +1,20 @@ +commit 4836a9af89f1b4d482e6c72ff67e36226d36434c +Author: Florian Weimer +Date: Tue Nov 26 19:26:13 2024 +0100 + + debug: Fix tst-longjmp_chk3 build failure on Hurd + + Explicitly include for _exit and getpid. + +diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c +index dfdecca9ef8a1cf6..254cd671902ca9a0 100644 +--- a/debug/tst-longjmp_chk3.c ++++ b/debug/tst-longjmp_chk3.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include + diff --git a/SOURCES/glibc-RHEL-68857.patch b/SOURCES/glibc-RHEL-68857.patch new file mode 100644 index 0000000..c453aa4 --- /dev/null +++ b/SOURCES/glibc-RHEL-68857.patch @@ -0,0 +1,164 @@ +commit b371ed272695919a332d30bd2754a82e5e683178 +Author: Joseph Myers +Date: Mon Oct 21 20:56:48 2024 +0000 + + Check time arguments to pthread_timedjoin_np and pthread_clockjoin_np + + The pthread_timedjoin_np and pthread_clockjoin_np functions do not + check that a valid time has been specified. The documentation for + these functions in the glibc manual isn't sufficiently detailed to say + if they should, but consistency with POSIX functions such as + pthread_mutex_timedlock and pthread_cond_timedwait strongly indicates + that an EINVAL error is appropriate (even if there might be some + ambiguity about exactly where such a check should go in relation to + other checks for whether the thread exists, whether it's immediately + joinable, etc.). Copy the logic for such a check used in + pthread_rwlock_common.c. + + pthread_join_common had some logic calling valid_nanoseconds before + commit 9e92278ffad441daf588ff1ff5bd8094aa33fbfd, "nptl: Remove + clockwait_tid"; I haven't checked exactly what cases that detected. + + Tested for x86_64 and x86. + + +Conflicts: + sysdeps/pthread/Makefile (renamed test) + +diff --git a/nptl/pthread_join_common.c b/nptl/pthread_join_common.c +index 617056ef10671607..d71b5ee2d7c7cda0 100644 +--- a/nptl/pthread_join_common.c ++++ b/nptl/pthread_join_common.c +@@ -49,6 +49,12 @@ __pthread_clockjoin_ex (pthread_t threadid, void **thread_return, + /* We cannot wait for the thread. */ + return EINVAL; + ++ /* Make sure the clock and time specified are valid. */ ++ if (abstime ++ && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid) ++ || ! valid_nanoseconds (abstime->tv_nsec))) ++ return EINVAL; ++ + struct pthread *self = THREAD_SELF; + int result = 0; + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 5a1b26fa3c0e6061..2d4cb1ac62d15f4c 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -129,6 +129,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-cancel30 \ + tst-spin5 \ + tst-sem19 \ ++ tst-join16 \ + # tests + + tests-time64 := \ +@@ -136,6 +137,7 @@ tests-time64 := \ + tst-cnd-timedwait-time64 \ + tst-cond11-time64 \ + tst-join14-time64 \ ++ tst-join16-time64 \ + tst-mtx-timedlock-time64 \ + tst-rwlock14-time64 \ + tst-sem5-time64 \ +diff --git a/sysdeps/pthread/tst-join16-time64.c b/sysdeps/pthread/tst-join16-time64.c +new file mode 100644 +index 0000000000000000..730cc5656308c30c +--- /dev/null ++++ b/sysdeps/pthread/tst-join16-time64.c +@@ -0,0 +1 @@ ++#include "tst-join16.c" +diff --git a/sysdeps/pthread/tst-join16.c b/sysdeps/pthread/tst-join16.c +new file mode 100644 +index 0000000000000000..8bf37b5e42fc46f6 +--- /dev/null ++++ b/sysdeps/pthread/tst-join16.c +@@ -0,0 +1,87 @@ ++/* Test pthread_timedjoin_np and pthread_clockjoin_np with an invalid timeout. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define CLOCK_USE_TIMEDJOIN (-1) ++ ++static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; ++ ++static void * ++tf (void *arg) ++{ ++ xpthread_mutex_lock (&lock); ++ xpthread_mutex_unlock (&lock); ++ return (void *) 42l; ++} ++ ++static int ++do_test_clock (clockid_t clockid) ++{ ++ const clockid_t clockid_for_get = ++ (clockid == CLOCK_USE_TIMEDJOIN) ? CLOCK_REALTIME : clockid; ++ ++ xpthread_mutex_lock (&lock); ++ pthread_t th = xpthread_create (NULL, tf, NULL); ++ ++ void *status; ++ int ret; ++ struct timespec timeout = xclock_now (clockid_for_get); ++ timeout.tv_sec += 2; ++ timeout.tv_nsec = -1; ++ if (clockid == CLOCK_USE_TIMEDJOIN) ++ ret = pthread_timedjoin_np (th, &status, &timeout); ++ else ++ ret = pthread_clockjoin_np (th, &status, clockid, &timeout); ++ TEST_COMPARE (ret, EINVAL); ++ timeout.tv_nsec = 1000000000; ++ if (clockid == CLOCK_USE_TIMEDJOIN) ++ ret = pthread_timedjoin_np (th, &status, &timeout); ++ else ++ ret = pthread_clockjoin_np (th, &status, clockid, &timeout); ++ TEST_COMPARE (ret, EINVAL); ++ xpthread_mutex_unlock (&lock); ++ timeout.tv_nsec = 0; ++ ret = pthread_join (th, &status); ++ TEST_COMPARE (ret, 0); ++ if (status != (void *) 42l) ++ FAIL_EXIT1 ("return value %p, expected %p\n", status, (void *) 42l); ++ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ puts ("testing pthread_timedjoin_np"); ++ do_test_clock (CLOCK_USE_TIMEDJOIN); ++ puts ("testing CLOCK_REALTIME"); ++ do_test_clock (CLOCK_REALTIME); ++ puts ("testing CLOCK_MONOTONIC"); ++ do_test_clock (CLOCK_MONOTONIC); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-69028.patch b/SOURCES/glibc-RHEL-69028.patch new file mode 100644 index 0000000..802b4f9 --- /dev/null +++ b/SOURCES/glibc-RHEL-69028.patch @@ -0,0 +1,223 @@ +commit 99671e72bb27a3cb98860bdc4c0e25961ce96b3e +Author: Joseph Myers +Date: Fri Nov 22 16:58:51 2024 +0000 + + Add multithreaded test of sem_getvalue + + Test coverage of sem_getvalue is fairly limited. Add a test that runs + it on threads on each CPU. For this purpose I adapted + tst-skeleton-thread-affinity.c; it didn't seem very suitable to use + as-is or include directly in a different test doing things per-CPU, + but did seem a suitable starting point (thus sharing + tst-skeleton-affinity.c) for such testing. + + Tested for x86_64. + +Conflicts: + sysdeps/unix/sysv/linux/Makefile (new test added) + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 9b7e214219943531..617f7718b2a5779d 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -382,7 +382,8 @@ CFLAGS-gai.c += -DNEED_NETLINK + endif + + ifeq ($(subdir),nptl) +-tests += tst-align-clone tst-getpid1 ++tests += tst-align-clone tst-getpid1 \ ++ tst-sem_getvalue-affinity \ + + # tst-rseq-nptl is an internal test because it requires a definition of + # __NR_rseq from the internal system call list. +diff --git a/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c b/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c +new file mode 100644 +index 0000000000000000..4176f67533357909 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c +@@ -0,0 +1,185 @@ ++/* Test sem_getvalue across CPUs. Based on tst-skeleton-thread-affinity.c. ++ Copyright (C) 2015-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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct conf; ++static bool early_test (struct conf *); ++ ++static int ++setaffinity (size_t size, const cpu_set_t *set) ++{ ++ int ret = pthread_setaffinity_np (pthread_self (), size, set); ++ if (ret != 0) ++ { ++ errno = ret; ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++getaffinity (size_t size, cpu_set_t *set) ++{ ++ int ret = pthread_getaffinity_np (pthread_self (), size, set); ++ if (ret != 0) ++ { ++ errno = ret; ++ return -1; ++ } ++ return 0; ++} ++ ++#include "tst-skeleton-affinity.c" ++ ++static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; ++static sem_t sem; ++ ++static void * ++tf (void *arg) ++{ ++ void *ret = NULL; ++ xpthread_mutex_lock (&lock); ++ int semval; ++ if (sem_getvalue (&sem, &semval) != 0) ++ { ++ printf ("sem_getvalue failed: %m\n"); ++ ret = (void *) 1; ++ } ++ else if (semval != 12345) ++ { ++ printf ("sem_getvalue returned %d not 12345\n", semval); ++ ret = (void *) 1; ++ } ++ xpthread_mutex_unlock (&lock); ++ return ret; ++} ++ ++static int ++stop_and_join_threads (struct conf *conf, cpu_set_t *set, ++ pthread_t *pinned_first, pthread_t *pinned_last) ++{ ++ int failed = 0; ++ for (pthread_t *p = pinned_first; p < pinned_last; ++p) ++ { ++ int cpu = p - pinned_first; ++ if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), set)) ++ continue; ++ ++ void *retval = (void *) 1; ++ int ret = pthread_join (*p, &retval); ++ if (ret != 0) ++ { ++ printf ("error: Failed to join thread %d: %s\n", cpu, strerror (ret)); ++ fflush (stdout); ++ /* Cannot shut down cleanly with threads still running. */ ++ abort (); ++ } ++ if (retval != NULL) ++ failed = 1; ++ } ++ return failed; ++} ++ ++static bool ++early_test (struct conf *conf) ++{ ++ int ret; ++ ret = sem_init (&sem, 0, 12345); ++ if (ret != 0) ++ { ++ printf ("error: sem_init failed: %m\n"); ++ return false; ++ } ++ xpthread_mutex_lock (&lock); ++ pthread_t *pinned_threads ++ = calloc (conf->last_cpu + 1, sizeof (*pinned_threads)); ++ cpu_set_t *initial_set = CPU_ALLOC (conf->set_size); ++ cpu_set_t *scratch_set = CPU_ALLOC (conf->set_size); ++ ++ if (pinned_threads == NULL || initial_set == NULL || scratch_set == NULL) ++ { ++ puts ("error: Memory allocation failure"); ++ return false; ++ } ++ if (getaffinity (CPU_ALLOC_SIZE (conf->set_size), initial_set) < 0) ++ { ++ printf ("error: pthread_getaffinity_np failed: %m\n"); ++ return false; ++ } ++ ++ pthread_attr_t attr; ++ ret = pthread_attr_init (&attr); ++ if (ret != 0) ++ { ++ printf ("error: pthread_attr_init failed: %s\n", strerror (ret)); ++ return false; ++ } ++ support_set_small_thread_stack_size (&attr); ++ ++ /* Spawn a thread pinned to each available CPU. */ ++ for (int cpu = 0; cpu <= conf->last_cpu; ++cpu) ++ { ++ if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), initial_set)) ++ continue; ++ CPU_ZERO_S (CPU_ALLOC_SIZE (conf->set_size), scratch_set); ++ CPU_SET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), scratch_set); ++ ret = pthread_attr_setaffinity_np ++ (&attr, CPU_ALLOC_SIZE (conf->set_size), scratch_set); ++ if (ret != 0) ++ { ++ printf ("error: pthread_attr_setaffinity_np for CPU %d failed: %s\n", ++ cpu, strerror (ret)); ++ stop_and_join_threads (conf, initial_set, ++ pinned_threads, pinned_threads + cpu); ++ return false; ++ } ++ ret = pthread_create (pinned_threads + cpu, &attr, ++ tf, (void *) (uintptr_t) cpu); ++ if (ret != 0) ++ { ++ printf ("error: pthread_create for CPU %d failed: %s\n", ++ cpu, strerror (ret)); ++ stop_and_join_threads (conf, initial_set, ++ pinned_threads, pinned_threads + cpu); ++ return false; ++ } ++ } ++ ++ /* Main thread. */ ++ xpthread_mutex_unlock (&lock); ++ int failed = stop_and_join_threads (conf, initial_set, ++ pinned_threads, ++ pinned_threads + conf->last_cpu + 1); ++ ++ printf ("info: Main thread ran on %d CPU(s) of %d available CPU(s)\n", ++ CPU_COUNT_S (CPU_ALLOC_SIZE (conf->set_size), scratch_set), ++ CPU_COUNT_S (CPU_ALLOC_SIZE (conf->set_size), initial_set)); ++ ++ pthread_attr_destroy (&attr); ++ CPU_FREE (scratch_set); ++ CPU_FREE (initial_set); ++ free (pinned_threads); ++ return failed == 0; ++} diff --git a/SOURCES/glibc-RHEL-69633-1.patch b/SOURCES/glibc-RHEL-69633-1.patch new file mode 100644 index 0000000..bfe625f --- /dev/null +++ b/SOURCES/glibc-RHEL-69633-1.patch @@ -0,0 +1,87 @@ +commit f745d78e2628cd5b13ca119ae0c0e21d08ad1906 +Author: Joseph Myers +Date: Fri Nov 8 01:53:48 2024 +0000 + + Avoid uninitialized result in sem_open when file does not exist + + A static analyzer apparently reported an uninitialized use of the + variable result in sem_open in the case where the file is required to + exist but does not exist. + + The report appears to be correct; set result to SEM_FAILED in that + case, and add a test for it. + + Note: the test passes for me even without the sem_open fix, I guess + because result happens to get value SEM_FAILED (i.e. 0) when + uninitialized. + + Tested for x86_64. + +Conflicts: + sysdeps/pthread/Makefile (new test added) + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 2d4cb1ac62d15f4c..de8b66bc3b6bf6ad 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -128,6 +128,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-pthread_kill-exiting \ + tst-cancel30 \ + tst-spin5 \ ++ tst-sem17 \ + tst-sem19 \ + tst-join16 \ + # tests +diff --git a/sysdeps/pthread/sem_open.c b/sysdeps/pthread/sem_open.c +index 770ab17cdbb47b83..124d95dce4186ae7 100644 +--- a/sysdeps/pthread/sem_open.c ++++ b/sysdeps/pthread/sem_open.c +@@ -75,6 +75,7 @@ __sem_open (const char *name, int oflag, ...) + goto try_create; + + /* Return. errno is already set. */ ++ result = SEM_FAILED; + } + else + /* Check whether we already have this semaphore mapped and +diff --git a/sysdeps/pthread/tst-sem17.c b/sysdeps/pthread/tst-sem17.c +new file mode 100644 +index 0000000000000000..c3f05d196f4ef17a +--- /dev/null ++++ b/sysdeps/pthread/tst-sem17.c +@@ -0,0 +1,35 @@ ++/* Test sem_open with missing 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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++int ++do_test (void) ++{ ++ sem_unlink ("/glibc-tst-sem17"); ++ errno = 0; ++ sem_t *s = sem_open ("/glibc-tst-sem17", 0); ++ TEST_VERIFY (s == SEM_FAILED); ++ TEST_COMPARE (errno, ENOENT); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-69633-2.patch b/SOURCES/glibc-RHEL-69633-2.patch new file mode 100644 index 0000000..9bc9060 --- /dev/null +++ b/SOURCES/glibc-RHEL-69633-2.patch @@ -0,0 +1,45 @@ +commit c7dcf594f4c52fa7e2cc76918c8aa9abb98e9625 +Author: Joseph Myers +Date: Fri Nov 8 17:08:09 2024 +0000 + + Rename new tst-sem17 test to tst-sem18 + + As noted by Adhemerval, we already have a tst-sem17 in nptl. + + Tested for x86_64. + +Conflicts: + sysdeps/pthread/Makefile (renamed test) + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index de8b66bc3b6bf6ad..43fcdf1182e735e1 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -128,7 +128,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-pthread_kill-exiting \ + tst-cancel30 \ + tst-spin5 \ +- tst-sem17 \ ++ tst-sem18 \ + tst-sem19 \ + tst-join16 \ + # tests +diff --git a/sysdeps/pthread/tst-sem17.c b/sysdeps/pthread/tst-sem18.c +similarity index 92% +rename from sysdeps/pthread/tst-sem17.c +rename to sysdeps/pthread/tst-sem18.c +index c3f05d196f4ef17a..1be207bcbeeb56f1 100644 +--- a/sysdeps/pthread/tst-sem17.c ++++ b/sysdeps/pthread/tst-sem18.c +@@ -24,9 +24,9 @@ + int + do_test (void) + { +- sem_unlink ("/glibc-tst-sem17"); ++ sem_unlink ("/glibc-tst-sem18"); + errno = 0; +- sem_t *s = sem_open ("/glibc-tst-sem17", 0); ++ sem_t *s = sem_open ("/glibc-tst-sem18", 0); + TEST_VERIFY (s == SEM_FAILED); + TEST_COMPARE (errno, ENOENT); + return 0; diff --git a/SOURCES/glibc-RHEL-70395-1.patch b/SOURCES/glibc-RHEL-70395-1.patch new file mode 100644 index 0000000..27c145a --- /dev/null +++ b/SOURCES/glibc-RHEL-70395-1.patch @@ -0,0 +1,85 @@ +commit 03b8d764109be48a53b18abd4b5050e8cdc2c6da +Author: Siddhesh Poyarekar +Date: Thu Nov 21 17:13:33 2024 -0500 + + nptl: Add smoke test for pthread_getcpuclockid failure + + Exercise the case where an exited thread will cause + pthread_getcpuclockid to fail. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Florian Weimer + +Conflicts: + nptl/Makefile (new test added) + +diff --git a/nptl/Makefile b/nptl/Makefile +index 9a56d34313d06444..f89bb07747cf5522 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -306,7 +306,8 @@ tests = tst-attr2 tst-attr3 tst-default-attr \ + tst-pthread-gdb-attach tst-pthread-gdb-attach-static \ + tst-pthread_exit-nothreads \ + tst-pthread_exit-nothreads-static \ +- tst-thread-setspecific ++ tst-thread-setspecific \ ++ tst-pthread-getcpuclockid-invalid \ + + tests-nolibpthread = \ + tst-pthread_exit-nothreads \ +diff --git a/nptl/tst-pthread-getcpuclockid-invalid.c b/nptl/tst-pthread-getcpuclockid-invalid.c +new file mode 100644 +index 0000000000000000..e88a56342767a83e +--- /dev/null ++++ b/nptl/tst-pthread-getcpuclockid-invalid.c +@@ -0,0 +1,50 @@ ++/* Smoke test to verify that pthread_getcpuclockid fails with ESRCH when the ++ thread in question has exited. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++void * ++thr (void *in) ++{ ++ return in; ++} ++ ++int ++do_test (void) ++{ ++ clockid_t c; ++ pthread_t t = xpthread_create (NULL, thr, NULL); ++ ++ int ret = 0; ++ while ((ret = pthread_getcpuclockid (t, &c)) == 0) ++ sched_yield (); ++ ++ TEST_COMPARE (ret, ESRCH); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-70395-2.patch b/SOURCES/glibc-RHEL-70395-2.patch new file mode 100644 index 0000000..49bee5c --- /dev/null +++ b/SOURCES/glibc-RHEL-70395-2.patch @@ -0,0 +1,51 @@ +commit 19a198f05802fcc05441c364ed75311ef3f6d663 +Author: Siddhesh Poyarekar +Date: Thu Nov 28 06:30:40 2024 -0500 + + pthread_getcpuclockid: Add descriptive comment to smoke test + + Add a descriptive comment to the tst-pthread-cpuclockid-invalid test and + also drop pthread_getcpuclockid from the TODO-testing list since it now + has full coverage. + + Signed-off-by: Siddhesh Poyarekar + +diff --git a/nptl/TODO-testing b/nptl/TODO-testing +index e076e5624f1cfbaa..f50d2ceb51b247c3 100644 +--- a/nptl/TODO-testing ++++ b/nptl/TODO-testing +@@ -10,10 +10,6 @@ pthread_attr_[sg]etstack + + some more tests needed + +-pthread_getcpuclockid +- +- check that value is reset -> rt subdir +- + pthread_getschedparam + pthread_setschedparam + +diff --git a/nptl/tst-pthread-getcpuclockid-invalid.c b/nptl/tst-pthread-getcpuclockid-invalid.c +index e88a56342767a83e..7ac46acad8fe0fd7 100644 +--- a/nptl/tst-pthread-getcpuclockid-invalid.c ++++ b/nptl/tst-pthread-getcpuclockid-invalid.c +@@ -1,5 +1,4 @@ +-/* Smoke test to verify that pthread_getcpuclockid fails with ESRCH when the +- thread in question has exited. ++/* pthread_getcpuclockid should fail with ESRCH when the thread exits. + Copyright the GNU Toolchain Authors. + This file is part of the GNU C Library. + +@@ -17,6 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + ++/* The input thread descriptor to pthread_getcpuclockid needs to be valid when ++ the function is called. For the purposes of this test, this means that the ++ thread should not be detached, have exited, but not joined. This should be ++ good enough to complete coverage for pthread_getcpuclockid alongside ++ tst-clock2. */ ++ + #include + #include + #include diff --git a/SOURCES/glibc-RHEL-71547.patch b/SOURCES/glibc-RHEL-71547.patch new file mode 100644 index 0000000..a279913 --- /dev/null +++ b/SOURCES/glibc-RHEL-71547.patch @@ -0,0 +1,108 @@ +commit 9a4b0eaf726f5404c6683d5c7c5e86f61c3f3fbc +Author: Aurelien Jarno +Date: Sat Dec 14 11:44:11 2024 +0100 + + iconv: do not report error exit with transliteration [BZ #32448] + + Commit 6cbf845fcdc7 ("iconv: Preserve iconv -c error exit on invalid + inputs (bug 32046)") changed the error exit code to report an error when + an input character has been transliterated. This looks like a bug as the + moto in the iconv program is to report an error code in the same + condition as the iconv() function. + + This happens because the STANDARD_TO_LOOP_ERR_HANDLER macro sets a + default value for result and later updates it if the transliteration + succeed. With the changes, setting the default value also marks the + input as illegal. + + Fix that by setting up the default value of result only when the + transliteration is not used. This works because __gconv_transliterate() + calls __gconv_mark_illegal_input() to return an error. At the same time + also fix the typo outself -> ourselves. + + Fixes: 6cbf845fcdc7 + Resolves: BZ #32448 + Signed-off-by: Aurelien Jarno + +diff --git a/iconv/loop.c b/iconv/loop.c +index 4df48342105d9ddc..7193e8f20104bf84 100644 +--- a/iconv/loop.c ++++ b/iconv/loop.c +@@ -212,12 +212,13 @@ + points. */ + #define STANDARD_TO_LOOP_ERR_HANDLER(Incr) \ + { \ +- result = __gconv_mark_illegal_input (step_data); \ +- \ + if (irreversible == NULL) \ +- /* This means we are in call from __gconv_transliterate. In this \ +- case we are not doing any error recovery outself. */ \ +- break; \ ++ { \ ++ /* This means we are in call from __gconv_transliterate. In this \ ++ case we are not doing any error recovery ourselves. */ \ ++ result = __gconv_mark_illegal_input (step_data); \ ++ break; \ ++ } \ + \ + /* If needed, flush any conversion state, so that __gconv_transliterate \ + starts with current shift state. */ \ +@@ -228,6 +229,8 @@ + result = __gconv_transliterate \ + (step, step_data, *inptrp, \ + &inptr, inend, &outptr, irreversible); \ ++ else \ ++ result = __gconv_mark_illegal_input (step_data); \ + \ + REINIT_PARAMS; \ + \ +diff --git a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh +index 14b7c08c9152be1b..932f4a3e204a0e23 100644 +--- a/iconv/tst-iconv_prog.sh ++++ b/iconv/tst-iconv_prog.sh +@@ -209,12 +209,13 @@ hangarray=( + "\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE" + ) + +-# List of option combinations that *should* lead to an error +-errorarray=( ++# List of option combinations with their expected return code ++testarray=( + # Converting from/to invalid character sets should cause error +-"\x00\x00;;INVALID;INVALID" +-"\x00\x00;;INVALID;UTF-8" +-"\x00\x00;;UTF-8;INVALID" ++"\x00\x00;;INVALID;INVALID;1" ++"\x00\x00;;INVALID;UTF-8;1" ++"\x00\x00;;UTF-8;INVALID;1" ++"\xc3\xa9;;UTF-8;ASCII//TRANSLIT;0" + ) + + # Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret +@@ -261,7 +262,7 @@ done + + check_errtest_result () + { +- if [ "$ret" -eq "1" ]; then # we errored out as expected ++ if [ "$ret" -eq "$eret" ]; then # we got the expected return code + result="PASS" + else + result="FAIL" +@@ -274,11 +275,12 @@ check_errtest_result () + fi + } + +-for errorcommand in "${errorarray[@]}"; do +- twobyte="$(echo "$errorcommand" | cut -d";" -f 1)" +- c="$(echo "$errorcommand" | cut -d";" -f 2)" +- from="$(echo "$errorcommand" | cut -d";" -f 3)" +- to="$(echo "$errorcommand" | cut -d";" -f 4)" ++for testcommand in "${testarray[@]}"; do ++ twobyte="$(echo "$testcommand" | cut -d";" -f 1)" ++ c="$(echo "$testcommand" | cut -d";" -f 2)" ++ from="$(echo "$testcommand" | cut -d";" -f 3)" ++ to="$(echo "$testcommand" | cut -d";" -f 4)" ++ eret="$(echo "$testcommand" | cut -d";" -f 5)" + execute_test + check_errtest_result + done diff --git a/SOURCES/glibc-RHEL-75810-2.patch b/SOURCES/glibc-RHEL-75810-2.patch new file mode 100644 index 0000000..00ab284 --- /dev/null +++ b/SOURCES/glibc-RHEL-75810-2.patch @@ -0,0 +1,236 @@ +commit 36fcdfbbc5463e55581fec67141df3493fb81f7e +Author: Florian Weimer +Date: Fri Jan 24 08:04:23 2025 +0100 + + Revert "stdlib: Support malloc-managed environ arrays for compatibility" + + This reverts commit b62759db04b8ed7f829c06f1d7c3b8fb70616493. + + Reason for revert: Incompatible with “env -i” and coreutils (bug 32588). + + Reviewed-by: H.J. Lu + +Conflicts: + stdlib/Makefile + (different test list) + +diff --git a/csu/init-first.c b/csu/init-first.c +index b1ee92332f478429..316fed22706b1870 100644 +--- a/csu/init-first.c ++++ b/csu/init-first.c +@@ -61,7 +61,6 @@ _init_first (int argc, char **argv, char **envp) + __libc_argc = argc; + __libc_argv = argv; + __environ = envp; +- __environ_startup = envp; + + #ifndef SHARED + /* First the initialization which normally would be done by the +diff --git a/csu/libc-start.c b/csu/libc-start.c +index 4f1801c4af35a012..a2fc2f6f9665a48f 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -244,7 +244,6 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + char **ev = &argv[argc + 1]; + + __environ = ev; +- __environ_startup = ev; + + /* Store the lowest stack address. This is done in ld.so if this is + the code for the DSO. */ +diff --git a/include/unistd.h b/include/unistd.h +index 781dbabde0aad494..5824485629793ccb 100644 +--- a/include/unistd.h ++++ b/include/unistd.h +@@ -182,9 +182,6 @@ libc_hidden_proto (__sbrk) + extern int __libc_enable_secure attribute_relro; + rtld_hidden_proto (__libc_enable_secure) + +-/* Original value of __environ. Initialized by _init_first (dynamic) +- or __libc_start_main (static). */ +-extern char **__environ_startup attribute_hidden; + + /* Various internal function. */ + extern void __libc_check_standard_fds (void) attribute_hidden; +diff --git a/posix/environ.c b/posix/environ.c +index 2430b47d8eee148c..a0ed0d80eab207f8 100644 +--- a/posix/environ.c ++++ b/posix/environ.c +@@ -10,5 +10,3 @@ weak_alias (__environ, environ) + /* The SVR4 ABI says `_environ' will be the name to use + in case the user overrides the weak alias `environ'. */ + weak_alias (__environ, _environ) +- +-char **__environ_startup; +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 3f98e55763c75758..4cbf47d215353681 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -126,7 +126,6 @@ tests := \ + tst-setcontext7 \ + tst-setcontext8 \ + tst-setcontext9 \ +- tst-setenv-malloc \ + tst-strfmon_l \ + tst-strfrom \ + tst-strfrom-locale \ +diff --git a/stdlib/setenv.c b/stdlib/setenv.c +index e02114103fc5957c..e3833bc514870bf4 100644 +--- a/stdlib/setenv.c ++++ b/stdlib/setenv.c +@@ -191,52 +191,52 @@ __add_to_environ (const char *name, const char *value, const char *combined, + ep[1] = NULL; + else + { +- /* We cannot use __environ as is and need a larger allocation. */ +- +- if (start_environ == __environ_startup +- || __environ_is_from_array_list (start_environ)) +- { +- /* Allocate a new array, managed in the list. */ +- struct environ_array *target_array +- = __environ_new_array (required_size); +- if (target_array == NULL) +- { +- UNLOCK; +- return -1; +- } +- result_environ = &target_array->array[0]; +- +- /* Copy over the __environ array contents. This code +- handles the case start_environ == ep == NULL, too. */ +- size_t i; +- for (i = 0; start_environ + i < ep; ++i) +- /* Regular store because unless there has been direct +- manipulation of the environment, target_array is still +- a private copy. */ +- result_environ[i] = atomic_load_relaxed (start_environ + i); +- } ++ /* We cannot use __environ as is and need to copy over the ++ __environ contents into an array managed via ++ __environ_array_list. */ ++ ++ struct environ_array *target_array; ++ if (__environ_array_list != NULL ++ && required_size <= __environ_array_list->allocated) ++ /* Existing array has enough room. Contents is copied below. */ ++ target_array = __environ_array_list; + else + { +- /* Otherwise the application installed its own pointer. +- Historically, this pointer was managed using realloc. +- Continue doing so. This disables multi-threading +- support. */ +- result_environ = __libc_reallocarray (start_environ, +- required_size, +- sizeof (*result_environ)); +- if (result_environ == NULL) ++ /* Allocate a new array. */ ++ target_array = __environ_new_array (required_size); ++ if (target_array == NULL) + { + UNLOCK; + return -1; + } + } + ++ /* Copy over the __environ array contents. This forward ++ copy slides backwards part of the array if __environ ++ points into target_array->array. This happens if an ++ application makes an assignment like: ++ ++ environ = &environ[1]; ++ ++ The forward copy avoids clobbering values that still ++ needing copying. This code handles the case ++ start_environ == ep == NULL, too. */ ++ size_t i; ++ for (i = 0; start_environ + i < ep; ++i) ++ /* Regular store because unless there has been direct ++ manipulation of the environment, target_array is still ++ a private copy. */ ++ target_array->array[i] = atomic_load_relaxed (start_environ + i); ++ + /* This is the new place where we should add the element. */ +- ep = result_environ + (required_size - 2); ++ ep = target_array->array + i; + + /* Add the null terminator in case there was a pointer there + previously. */ + ep[1] = NULL; ++ ++ /* And __environ should be repointed to our array. */ ++ result_environ = &target_array->array[0]; + } + } + +diff --git a/stdlib/tst-setenv-malloc.c b/stdlib/tst-setenv-malloc.c +deleted file mode 100644 +index 18a9d36842e67aa5..0000000000000000 +--- a/stdlib/tst-setenv-malloc.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* Test using setenv with a malloc-allocated environ variable. +- 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 +- . */ +- +-/* This test is not in the scope for POSIX or any other standard, but +- some applications assume that environ is a heap-allocated pointer +- after a call to setenv on an empty environment. */ +- +-#include +-#include +-#include +-#include +- +-static const char *original_path; +-static char **save_environ; +- +-static void +-rewrite_environ (void) +-{ +- save_environ = environ; +- environ = xmalloc (sizeof (*environ)); +- *environ = NULL; +- TEST_COMPARE (setenv ("A", "1", 1), 0); +- TEST_COMPARE (setenv ("B", "2", 1), 0); +- TEST_VERIFY (environ != save_environ); +- TEST_COMPARE_STRING (environ[0], "A=1"); +- TEST_COMPARE_STRING (environ[1], "B=2"); +- TEST_COMPARE_STRING (environ[2], NULL); +- TEST_COMPARE_STRING (getenv ("PATH"), NULL); +- free (environ); +- environ = save_environ; +- TEST_COMPARE_STRING (getenv ("PATH"), original_path); +-} +- +-static int +-do_test (void) +-{ +- original_path = getenv ("PATH"); +- rewrite_environ (); +- +- /* Test again after reallocated the environment due to an initial +- setenv call. */ +- TEST_COMPARE (setenv ("TST_SETENV_MALLOC", "1", 1), 0); +- TEST_VERIFY (environ != save_environ); +- rewrite_environ (); +- +- return 0; +-} +- +-#include diff --git a/SOURCES/glibc-RHEL-75810-3.patch b/SOURCES/glibc-RHEL-75810-3.patch new file mode 100644 index 0000000..3fa2f84 --- /dev/null +++ b/SOURCES/glibc-RHEL-75810-3.patch @@ -0,0 +1,299 @@ +commit 12b4a1fc6ecfc278a87159164bdf1d682deb18e2 +Author: Florian Weimer +Date: Fri Jan 24 10:40:28 2025 +0100 + + stdlib: Re-implement free (environ) compatibility kludge for setenv + + For the originally failing application (userhelper from usermode), + it is not actually necessary to call realloc on the environ + pointer. Yes, there will be a memory leak because the application + assigns a heap-allocated pointer to environ that it never frees, + but this leak was always there: the old realloc-based setenv had + a hidden internal variable, last_environ, that was used in a similar + way to __environ_array_list. The application is not impacted by + the leak anyway because the relevant operations do not happen in + a loop. + + The change here just uses a separte heap allocation and points + environ to that. This means that if an application calls + free (environ) and restores the environ pointer to the value + at process start, and does not modify the environment further, + nothing bad happens. + + This change should not invalidate any previous testing that went into + the original getenv thread safety change, commit 7a61e7f557a97ab597d6 + ("stdlib: Make getenv thread-safe in more cases"). + + The new test cases are modeled in part on the env -i use case from + bug 32588 (with !DO_MALLOC && !DO_EARLY_SETENV), and the previous + stdlib/tst-setenv-malloc test. The DO_MALLOC && !DO_EARLY_SETENV + case in the new test should approximate what userhelper from the + usermode package does. + + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 4cbf47d215353681..4f5de988cee07932 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -97,6 +97,10 @@ tests := \ + tst-concurrent-quick_exit \ + tst-cxa_atexit \ + tst-environ \ ++ tst-environ-change-1 \ ++ tst-environ-change-2 \ ++ tst-environ-change-3 \ ++ tst-environ-change-4 \ + tst-getenv-signal \ + tst-getenv-thread \ + tst-getenv-unsetenv \ +diff --git a/stdlib/setenv.c b/stdlib/setenv.c +index e3833bc514870bf4..035a2a6ce8a95ce6 100644 +--- a/stdlib/setenv.c ++++ b/stdlib/setenv.c +@@ -118,24 +118,21 @@ __environ_new_array (size_t required_size) + else + new_size = __environ_array_list->allocated * 2; + +- size_t new_size_in_bytes; +- if (__builtin_mul_overflow (new_size, sizeof (char *), +- &new_size_in_bytes) +- || __builtin_add_overflow (new_size_in_bytes, +- offsetof (struct environ_array, +- array), +- &new_size_in_bytes)) ++ /* Zero-initialize everything, so that getenv can only ++ observe valid or null pointers. */ ++ char **new_array = calloc (new_size, sizeof (*new_array)); ++ if (new_array == NULL) ++ return NULL; ++ ++ struct environ_array *target_array = malloc (sizeof (*target_array)); ++ if (target_array == NULL) + { +- __set_errno (ENOMEM); ++ free (new_array); + return NULL; + } + +- /* Zero-initialize everything, so that getenv can only +- observe valid or null pointers. */ +- struct environ_array *target_array = calloc (1, new_size_in_bytes); +- if (target_array == NULL) +- return NULL; + target_array->allocated = new_size; ++ target_array->array = new_array; + assert (new_size >= target_array->allocated); + + /* Put it onto the list. */ +@@ -236,7 +233,7 @@ __add_to_environ (const char *name, const char *value, const char *combined, + ep[1] = NULL; + + /* And __environ should be repointed to our array. */ +- result_environ = &target_array->array[0]; ++ result_environ = target_array->array; + } + } + +@@ -402,6 +399,7 @@ libc_freeres_fn (free_mem) + /* Clear all backing arrays. */ + while (__environ_array_list != NULL) + { ++ free (__environ_array_list->array); + void *ptr = __environ_array_list; + __environ_array_list = __environ_array_list->next; + free (ptr); +diff --git a/stdlib/setenv.h b/stdlib/setenv.h +index 036f4274aa29b722..42b86fff1008bc81 100644 +--- a/stdlib/setenv.h ++++ b/stdlib/setenv.h +@@ -29,9 +29,18 @@ + of environment values used before. */ + struct environ_array + { +- struct environ_array *next; /* Previously used environment array. */ ++ /* The actual environment array. Use a separate allocation (and not ++ a flexible array member) so that calls like free (environ) that ++ have been encountered in some applications do not crash ++ immediately. With such a call, if the application restores the ++ original environ pointer at process start and does not modify the ++ environment again, a use-after-free situation only occurs during ++ __libc_freeres, which is only called during memory debugging. ++ With subsequent setenv calls, there is still heap corruption, but ++ that happened with the old realloc-based implementation, too. */ ++ char **array; + size_t allocated; /* Number of allocated array elments. */ +- char *array[]; /* The actual environment array. */ ++ struct environ_array *next; /* Previously used environment array. */ + }; + + /* After initialization, and until the user resets environ (perhaps by +@@ -44,7 +53,7 @@ static inline bool + __environ_is_from_array_list (char **ep) + { + struct environ_array *eal = atomic_load_relaxed (&__environ_array_list); +- return eal != NULL && &eal->array[0] == ep; ++ return eal != NULL && eal->array == ep; + } + + /* Counter for detecting concurrent modification in unsetenv. +diff --git a/stdlib/tst-environ-change-1.c b/stdlib/tst-environ-change-1.c +new file mode 100644 +index 0000000000000000..4241ad4c63ea2e33 +--- /dev/null ++++ b/stdlib/tst-environ-change-1.c +@@ -0,0 +1,3 @@ ++#define DO_EARLY_SETENV 0 ++#define DO_MALLOC 0 ++#include "tst-environ-change-skeleton.c" +diff --git a/stdlib/tst-environ-change-2.c b/stdlib/tst-environ-change-2.c +new file mode 100644 +index 0000000000000000..b20be124902125e8 +--- /dev/null ++++ b/stdlib/tst-environ-change-2.c +@@ -0,0 +1,3 @@ ++#define DO_EARLY_SETENV 0 ++#define DO_MALLOC 1 ++#include "tst-environ-change-skeleton.c" +diff --git a/stdlib/tst-environ-change-3.c b/stdlib/tst-environ-change-3.c +new file mode 100644 +index 0000000000000000..e77996a6cb0ac601 +--- /dev/null ++++ b/stdlib/tst-environ-change-3.c +@@ -0,0 +1,3 @@ ++#define DO_EARLY_SETENV 1 ++#define DO_MALLOC 0 ++#include "tst-environ-change-skeleton.c" +diff --git a/stdlib/tst-environ-change-4.c b/stdlib/tst-environ-change-4.c +new file mode 100644 +index 0000000000000000..633ef7bda84eb2a8 +--- /dev/null ++++ b/stdlib/tst-environ-change-4.c +@@ -0,0 +1,3 @@ ++#define DO_EARLY_SETENV 1 ++#define DO_MALLOC 1 ++#include "tst-environ-change-skeleton.c" +diff --git a/stdlib/tst-environ-change-skeleton.c b/stdlib/tst-environ-change-skeleton.c +new file mode 100644 +index 0000000000000000..c9b02844369207d9 +--- /dev/null ++++ b/stdlib/tst-environ-change-skeleton.c +@@ -0,0 +1,118 @@ ++/* Test deallocation of the environ pointer. ++ 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 ++ . */ ++ ++/* This test is not in the scope for POSIX or any other standard, but ++ some applications assume that environ is a heap-allocated pointer ++ after a call to setenv on an empty environment. They also try to ++ save and restore environ in an attempt to undo a temporary ++ modification of the environment array, but this does not work if ++ setenv was called before. ++ ++ Before including this file, these macros need to be defined ++ to 0 or 1: ++ ++ DO_EARLY_SETENV If 1, perform a setenv call before changing environ. ++ DO_MALLOC If 1, use a heap pointer for the empty environment. ++ ++ Note that this test will produce errors under valgrind and other ++ memory tracers that call __libc_freeres because free (environ) ++ deallocates a pointer still used internally. */ ++ ++#include ++#include ++#include ++#include ++ ++static void ++check_rewritten (void) ++{ ++ TEST_COMPARE_STRING (environ[0], "tst_environ_change_a=1"); ++ TEST_COMPARE_STRING (environ[1], "tst_environ_change_b=2"); ++ TEST_COMPARE_STRING (environ[2], NULL); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_a"), "1"); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_b"), "2"); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_early"), NULL); ++ TEST_COMPARE_STRING (getenv ("PATH"), NULL); ++} ++ ++static int ++do_test (void) ++{ ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_a"), NULL); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_b"), NULL); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_early_setenv"), NULL); ++#if DO_EARLY_SETENV ++ TEST_COMPARE (setenv ("tst_environ_change_early_setenv", "1", 1), 0); ++#else ++ /* Must come back after environ reset. */ ++ char *original_path = xstrdup (getenv ("PATH")); ++#endif ++ ++ char **save_environ = environ; ++#if DO_MALLOC ++ environ = xmalloc (sizeof (*environ)); ++#else ++ char *environ_array[1]; ++ environ = environ_array; ++#endif ++ *environ = NULL; ++ TEST_COMPARE (setenv ("tst_environ_change_a", "1", 1), 0); ++ TEST_COMPARE (setenv ("tst_environ_change_b", "2", 1), 0); ++#if !DO_EARLY_SETENV ++ /* Early setenv results in reuse of the heap-allocated environ array ++ that does not change as more pointers are added to it. */ ++ TEST_VERIFY (environ != save_environ); ++#endif ++ check_rewritten (); ++ ++ bool check_environ = true; ++#if DO_MALLOC ++ /* Disable further checks if the free call clobbers the environ ++ contents. Whether that is the case depends on the internal ++ setenv allocation policy and the heap layout. */ ++ check_environ = environ != save_environ; ++ /* Invalid: Causes internal use-after-free condition. Yet this has ++ to be supported for compatibility with some applications. */ ++ free (environ); ++#endif ++ ++ environ = save_environ; ++ ++#if DO_EARLY_SETENV ++ /* With an early setenv, the internal environ array was overwritten. ++ Historically, this triggered a use-after-free problem because of ++ the use of realloc internally in setenv, but it may appear as if ++ the original environment had been restored. In the current code, ++ we can only support this if the free (environ) above call did not ++ clobber the array, otherwise getenv will see invalid pointers. ++ Due to the use-after-free, invalid pointers could be seen with ++ the old implementation as well, but the triggering conditions ++ were different. */ ++ if (check_environ) ++ check_rewritten (); ++#else ++ TEST_VERIFY (check_environ); ++ TEST_COMPARE_STRING (getenv ("PATH"), original_path); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_a"), NULL); ++ TEST_COMPARE_STRING (getenv ("tst_environ_change_b"), NULL); ++#endif ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-75810.patch b/SOURCES/glibc-RHEL-75810.patch new file mode 100644 index 0000000..361e0a2 --- /dev/null +++ b/SOURCES/glibc-RHEL-75810.patch @@ -0,0 +1,249 @@ +commit b62759db04b8ed7f829c06f1d7c3b8fb70616493 +Author: Florian Weimer +Date: Wed Jan 22 13:48:56 2025 +0100 + + stdlib: Support malloc-managed environ arrays for compatibility + + Some applications set environ to a heap-allocated pointer, call + setenv (expecting it to call realloc), free environ, and then + restore the original environ pointer. This breaks after + commit 7a61e7f557a97ab597d6fca5e2d1f13f65685c61 ("stdlib: Make + getenv thread-safe in more cases") because after the setenv call, + the environ pointer does not point to the start of a heap allocation. + Instead, setenv creates a separate allocation and changes environ + to point into that. This means that the free call in the application + results in heap corruption. + + The interim approach was more compatible with other libcs because + it does not assume that the incoming environ pointer is allocated + as if by malloc (if it was written by the application). However, + it seems to be more important to stay compatible with previous + glibc version: assume the incoming pointer is heap allocated, + and preserve this property after setenv calls. + + Reviewed-by: Carlos O'Donell + +Conflicts: + stdlib/Makefile + (test list difference) + +diff --git a/csu/init-first.c b/csu/init-first.c +index 316fed22706b1870..b1ee92332f478429 100644 +--- a/csu/init-first.c ++++ b/csu/init-first.c +@@ -61,6 +61,7 @@ _init_first (int argc, char **argv, char **envp) + __libc_argc = argc; + __libc_argv = argv; + __environ = envp; ++ __environ_startup = envp; + + #ifndef SHARED + /* First the initialization which normally would be done by the +diff --git a/csu/libc-start.c b/csu/libc-start.c +index a2fc2f6f9665a48f..4f1801c4af35a012 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -244,6 +244,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + char **ev = &argv[argc + 1]; + + __environ = ev; ++ __environ_startup = ev; + + /* Store the lowest stack address. This is done in ld.so if this is + the code for the DSO. */ +diff --git a/include/unistd.h b/include/unistd.h +index 5824485629793ccb..781dbabde0aad494 100644 +--- a/include/unistd.h ++++ b/include/unistd.h +@@ -182,6 +182,9 @@ libc_hidden_proto (__sbrk) + extern int __libc_enable_secure attribute_relro; + rtld_hidden_proto (__libc_enable_secure) + ++/* Original value of __environ. Initialized by _init_first (dynamic) ++ or __libc_start_main (static). */ ++extern char **__environ_startup attribute_hidden; + + /* Various internal function. */ + extern void __libc_check_standard_fds (void) attribute_hidden; +diff --git a/posix/environ.c b/posix/environ.c +index a0ed0d80eab207f8..2430b47d8eee148c 100644 +--- a/posix/environ.c ++++ b/posix/environ.c +@@ -10,3 +10,5 @@ weak_alias (__environ, environ) + /* The SVR4 ABI says `_environ' will be the name to use + in case the user overrides the weak alias `environ'. */ + weak_alias (__environ, _environ) ++ ++char **__environ_startup; +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 4cbf47d215353681..3f98e55763c75758 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -126,6 +126,7 @@ tests := \ + tst-setcontext7 \ + tst-setcontext8 \ + tst-setcontext9 \ ++ tst-setenv-malloc \ + tst-strfmon_l \ + tst-strfrom \ + tst-strfrom-locale \ +diff --git a/stdlib/setenv.c b/stdlib/setenv.c +index e3833bc514870bf4..e02114103fc5957c 100644 +--- a/stdlib/setenv.c ++++ b/stdlib/setenv.c +@@ -191,52 +191,52 @@ __add_to_environ (const char *name, const char *value, const char *combined, + ep[1] = NULL; + else + { +- /* We cannot use __environ as is and need to copy over the +- __environ contents into an array managed via +- __environ_array_list. */ +- +- struct environ_array *target_array; +- if (__environ_array_list != NULL +- && required_size <= __environ_array_list->allocated) +- /* Existing array has enough room. Contents is copied below. */ +- target_array = __environ_array_list; +- else ++ /* We cannot use __environ as is and need a larger allocation. */ ++ ++ if (start_environ == __environ_startup ++ || __environ_is_from_array_list (start_environ)) + { +- /* Allocate a new array. */ +- target_array = __environ_new_array (required_size); ++ /* Allocate a new array, managed in the list. */ ++ struct environ_array *target_array ++ = __environ_new_array (required_size); + if (target_array == NULL) + { + UNLOCK; + return -1; + } ++ result_environ = &target_array->array[0]; ++ ++ /* Copy over the __environ array contents. This code ++ handles the case start_environ == ep == NULL, too. */ ++ size_t i; ++ for (i = 0; start_environ + i < ep; ++i) ++ /* Regular store because unless there has been direct ++ manipulation of the environment, target_array is still ++ a private copy. */ ++ result_environ[i] = atomic_load_relaxed (start_environ + i); ++ } ++ else ++ { ++ /* Otherwise the application installed its own pointer. ++ Historically, this pointer was managed using realloc. ++ Continue doing so. This disables multi-threading ++ support. */ ++ result_environ = __libc_reallocarray (start_environ, ++ required_size, ++ sizeof (*result_environ)); ++ if (result_environ == NULL) ++ { ++ UNLOCK; ++ return -1; ++ } + } +- +- /* Copy over the __environ array contents. This forward +- copy slides backwards part of the array if __environ +- points into target_array->array. This happens if an +- application makes an assignment like: +- +- environ = &environ[1]; +- +- The forward copy avoids clobbering values that still +- needing copying. This code handles the case +- start_environ == ep == NULL, too. */ +- size_t i; +- for (i = 0; start_environ + i < ep; ++i) +- /* Regular store because unless there has been direct +- manipulation of the environment, target_array is still +- a private copy. */ +- target_array->array[i] = atomic_load_relaxed (start_environ + i); + + /* This is the new place where we should add the element. */ +- ep = target_array->array + i; ++ ep = result_environ + (required_size - 2); + + /* Add the null terminator in case there was a pointer there + previously. */ + ep[1] = NULL; +- +- /* And __environ should be repointed to our array. */ +- result_environ = &target_array->array[0]; + } + } + +diff --git a/stdlib/tst-setenv-malloc.c b/stdlib/tst-setenv-malloc.c +new file mode 100644 +index 0000000000000000..18a9d36842e67aa5 +--- /dev/null ++++ b/stdlib/tst-setenv-malloc.c +@@ -0,0 +1,64 @@ ++/* Test using setenv with a malloc-allocated environ variable. ++ 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 ++ . */ ++ ++/* This test is not in the scope for POSIX or any other standard, but ++ some applications assume that environ is a heap-allocated pointer ++ after a call to setenv on an empty environment. */ ++ ++#include ++#include ++#include ++#include ++ ++static const char *original_path; ++static char **save_environ; ++ ++static void ++rewrite_environ (void) ++{ ++ save_environ = environ; ++ environ = xmalloc (sizeof (*environ)); ++ *environ = NULL; ++ TEST_COMPARE (setenv ("A", "1", 1), 0); ++ TEST_COMPARE (setenv ("B", "2", 1), 0); ++ TEST_VERIFY (environ != save_environ); ++ TEST_COMPARE_STRING (environ[0], "A=1"); ++ TEST_COMPARE_STRING (environ[1], "B=2"); ++ TEST_COMPARE_STRING (environ[2], NULL); ++ TEST_COMPARE_STRING (getenv ("PATH"), NULL); ++ free (environ); ++ environ = save_environ; ++ TEST_COMPARE_STRING (getenv ("PATH"), original_path); ++} ++ ++static int ++do_test (void) ++{ ++ original_path = getenv ("PATH"); ++ rewrite_environ (); ++ ++ /* Test again after reallocated the environment due to an initial ++ setenv call. */ ++ TEST_COMPARE (setenv ("TST_SETENV_MALLOC", "1", 1), 0); ++ TEST_VERIFY (environ != save_environ); ++ rewrite_environ (); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-75938.patch b/SOURCES/glibc-RHEL-75938.patch new file mode 100644 index 0000000..a1827ea --- /dev/null +++ b/SOURCES/glibc-RHEL-75938.patch @@ -0,0 +1,54 @@ +commit 68ee0f704cb81e9ad0a78c644a83e1e9cd2ee578 +Author: Siddhesh Poyarekar +Date: Tue Jan 21 16:11:06 2025 -0500 + + Fix underallocation of abort_msg_s struct (CVE-2025-0395) + + Include the space needed to store the length of the message itself, in + addition to the message string. This resolves BZ #32582. + + Signed-off-by: Siddhesh Poyarekar + Reviewed: Adhemerval Zanella + +diff -Nrup a/assert/assert.c b/assert/assert.c +--- a/assert/assert.c 2025-01-29 14:45:37.480532858 -0500 ++++ b/assert/assert.c 2025-01-29 14:54:03.824306418 -0500 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -66,7 +67,8 @@ __assert_fail_base (const char *fmt, con + (void) __fxprintf (NULL, "%s", str); + (void) fflush (stderr); + +- total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1); ++ total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1, ++ GLRO(dl_pagesize)); + struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (__glibc_likely (buf != MAP_FAILED)) +diff -Nrup a/sysdeps/posix/libc_fatal.c b/sysdeps/posix/libc_fatal.c +--- a/sysdeps/posix/libc_fatal.c 2025-01-29 14:45:36.603528055 -0500 ++++ b/sysdeps/posix/libc_fatal.c 2025-01-29 15:57:20.910535347 -0500 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -123,7 +124,8 @@ __libc_message (const char *fmt, ...) + + WRITEV_FOR_FATAL (fd, iov, nlist, total); + +- total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1); ++ total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1, ++ GLRO(dl_pagesize)); + struct abort_msg_s *buf = __mmap (NULL, total, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); diff --git a/SOURCES/glibc-upstream-2.34-373.patch b/SOURCES/glibc-upstream-2.34-373.patch new file mode 100644 index 0000000..01b4007 Binary files /dev/null and b/SOURCES/glibc-upstream-2.34-373.patch differ diff --git a/SOURCES/wrap-find-debuginfo.sh b/SOURCES/wrap-find-debuginfo.sh index 4cbb01b..59c7356 100644 --- a/SOURCES/wrap-find-debuginfo.sh +++ b/SOURCES/wrap-find-debuginfo.sh @@ -40,21 +40,13 @@ trap cleanup 0 sysroot_path="$1" shift +# Resolve symbolic link, so that the activities below only alter the +# file it points to. +ldso_path="$(readlink -f "$sysroot_path/$1")" +shift script_path="$1" shift -# See ldso_path setting in glibc.spec. -ldso_path= -for ldso_candidate in `find "$sysroot_path" -maxdepth 2 \ - -regextype posix-extended -regex '.*/ld(-.*|64|)\.so\.[0-9]+$' -type f` ; do - if test -z "$ldso_path" ; then - ldso_path="$ldso_candidate" - else - echo "error: multiple ld.so candidates: $ldso_path, $ldso_candidate" - exit 1 - fi -done - # libc.so.6 always uses this name, so it is simpler to locate. libc_path=`find "$sysroot_path" -name libc.so.6` diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index ccce97c..b57d635 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -157,7 +157,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 122%{?dist} +Release: 168%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -199,6 +199,75 @@ Source11: parse-SUPPORTED.py Source12: ChangeLog.old Source13: nscd-sysusers.conf +# glibc_ldso: ABI-specific program interpreter name. Used for debuginfo +# extraction (wrap-find-debuginfo.sh) and smoke testing ($run_ldso below). +# +# glibc_has_libnldbl: -lnldbl is supported for long double as double. +# +# glibc_has_libmvec: libmvec is available. +# +# glibc_rtld_early_cflags: The ABI baseline for architectures with +# potentially a later baseline. The --with-rtld-early-cflags= +# configure option is passed to the main glibc build if this macro is +# defined. +%ifarch %{ix86} +%global glibc_ldso /lib/ld-linux.so.2 +%global glibc_has_libnldbl 0 +%global glibc_has_libmvec 0 +%endif +%ifarch aarch64 +%global glibc_ldso /lib/ld-linux-aarch64.so.1 +%global glibc_has_libnldbl 0 +%global glibc_has_libmvec 0 +%endif +%ifarch ppc +%global glibc_ldso /lib/ld.so.1 +%global glibc_has_libnldbl 1 +%global glibc_has_libmvec 0 +%endif +%ifarch ppc64 +%global glibc_ldso /lib64/ld64.so.1 +%global glibc_has_libnldbl 1 +%global glibc_has_libmvec 0 +%endif +%ifarch ppc64le +%global glibc_ldso /lib64/ld64.so.2 +%global glibc_has_libnldbl 1 +%global glibc_has_libmvec 0 +%define glibc_rtld_early_cflags -mcpu=power8 +%endif +%ifarch riscv64 +%global glibc_ldso /lib/ld-linux-riscv64-lp64d.so.1 +%global glibc_has_libnldbl 0 +%global glibc_has_libmvec 0 +%endif +%ifarch s390 +%global glibc_ldso /lib/ld.so.1 +%global glibc_has_libnldbl 1 +%global glibc_has_libmvec 0 +%define glibc_rtld_early_cflags -march=z13 +%endif +%ifarch s390x +%global glibc_ldso /lib/ld64.so.1 +%global glibc_has_libnldbl 1 +%global glibc_has_libmvec 0 +%define glibc_rtld_early_cflags -march=z13 +%endif +%ifarch x86_64 x86_64_v2 x86_64_v3 x86_64_v4 +%global glibc_ldso /lib64/ld-linux-x86-64.so.2 +%global glibc_has_libnldbl 0 +%global glibc_has_libmvec 1 +%define glibc_rtld_early_cflags -march=x86-64 +%endif + +# This is necessary to enable source RPM building under noarch, as +# used by some build environments. +%ifarch noarch +%global glibc_ldso /lib/ld.so +%global glibc_has_libnldbl 0 +%global glibc_has_libmvec 0 +%endif + ###################################################################### # Activate the wrapper script for debuginfo generation, by rewriting # the definition of __debug_install_post. @@ -210,7 +279,7 @@ local original = rpm.expand("%{macrobody:__debug_install_post}") -- Avoid embedded newlines that confuse the macro definition. original = original:match("^%s*(.-)%s*$"):gsub("\\\n", "") rpm.define("__debug_install_post bash " .. wrapper - .. " " .. sysroot .. " " .. original) + .. " " .. sysroot .. " %{_prefix}/%{glibc_ldso} " .. original) } # sysroot package support. These contain arch-specific packages, so @@ -853,12 +922,216 @@ Patch614: glibc-RHEL-46723-2.patch Patch615: glibc-RHEL-36148-1.patch Patch616: glibc-RHEL-36148-2.patch Patch617: glibc-RHEL-36148-3.patch +Patch618: glibc-RHEL-49489-1.patch +Patch619: glibc-RHEL-49489-2.patch +Patch620: glibc-RHEL-54447-1.patch +Patch621: glibc-RHEL-54447-2.patch +Patch622: glibc-RHEL-54447-3.patch +Patch623: glibc-RHEL-54447-4.patch +Patch624: glibc-RHEL-54447-5.patch +Patch625: glibc-RHEL-54447-6.patch +Patch626: glibc-RHEL-54447-7.patch +Patch627: glibc-RHEL-54447-8.patch +Patch628: glibc-RHEL-54447-9.patch +Patch629: glibc-RHEL-54447-10.patch +Patch630: glibc-RHEL-46979-1.patch +Patch631: glibc-RHEL-46979-2.patch +Patch632: glibc-RHEL-46979-3.patch +Patch633: glibc-RHEL-46979-4.patch +Patch634: glibc-RHEL-59494-1.patch +Patch635: glibc-RHEL-59494-2.patch +Patch636: glibc-RHEL-59494-3.patch +Patch637: glibc-RHEL-41189.patch +Patch638: glibc-RHEL-46728.patch +Patch639: glibc-RHEL-46734.patch +Patch640: glibc-RHEL-46735.patch +Patch641: glibc-RHEL-60466-1.patch +Patch642: glibc-RHEL-60466-2.patch +Patch643: glibc-RHEL-46739-1.patch +Patch644: glibc-RHEL-46739-2.patch +Patch645: glibc-RHEL-46739-3.patch +Patch646: glibc-RHEL-46739-4.patch +Patch647: glibc-RHEL-46739-5.patch +Patch648: glibc-RHEL-46739-6.patch +Patch649: glibc-RHEL-46739-7.patch +Patch650: glibc-RHEL-46739-8.patch +Patch651: glibc-RHEL-46739-9.patch +Patch652: glibc-RHEL-46739-10.patch +Patch653: glibc-RHEL-46739-11.patch +Patch654: glibc-RHEL-50545-1.patch +Patch655: glibc-RHEL-50545-2.patch +Patch656: glibc-RHEL-50545-3.patch +Patch657: glibc-RHEL-50545-4.patch +Patch658: glibc-RHEL-50545-5.patch +Patch659: glibc-RHEL-50545-6.patch +Patch660: glibc-RHEL-50545-7.patch +Patch661: glibc-RHEL-50545-8.patch +Patch662: glibc-RHEL-50545-9.patch +Patch663: glibc-RHEL-50545-10.patch +Patch664: glibc-RHEL-50545-11.patch +Patch665: glibc-RHEL-50545-12.patch +Patch666: glibc-RHEL-50545-13.patch +Patch667: glibc-RHEL-50545-14.patch +Patch668: glibc-RHEL-50662-1.patch +Patch669: glibc-RHEL-50662-2.patch +Patch670: glibc-RHEL-50662-3.patch +Patch671: glibc-RHEL-50662-4.patch +Patch672: glibc-RHEL-50662-5.patch +Patch673: glibc-RHEL-50662-6.patch +Patch674: glibc-RHEL-46724.patch +Patch675: glibc-RHEL-66253-1.patch +Patch676: glibc-RHEL-66253-2.patch +Patch677: glibc-RHEL-66253-3.patch +Patch678: glibc-RHEL-46733-1.patch +Patch679: glibc-RHEL-46733-2.patch +Patch680: glibc-RHEL-46733-3.patch +Patch681: glibc-RHEL-54413.patch +Patch682: glibc-RHEL-46736-1.patch +Patch683: glibc-RHEL-46736-2.patch +Patch684: glibc-RHEL-46736-3.patch +Patch685: glibc-RHEL-46736-4.patch +Patch686: glibc-RHEL-46736-5.patch +Patch687: glibc-RHEL-46736-6.patch +Patch688: glibc-RHEL-46736-7.patch +Patch689: glibc-RHEL-46736-8.patch +Patch690: glibc-RHEL-46736-9.patch +Patch691: glibc-RHEL-46736-10.patch +Patch692: glibc-RHEL-46736-11.patch +Patch693: glibc-RHEL-50548-1.patch +Patch694: glibc-RHEL-50548-2.patch +Patch695: glibc-RHEL-50548-3.patch +Patch696: glibc-RHEL-46725-1.patch +Patch697: glibc-RHEL-46725-2.patch +Patch698: glibc-RHEL-46725-3.patch +Patch699: glibc-RHEL-46725-4.patch +Patch700: glibc-RHEL-46725-5.patch +Patch701: glibc-RHEL-46725-6.patch +Patch702: glibc-RHEL-46725-7.patch +Patch703: glibc-RHEL-46725-8.patch +Patch704: glibc-RHEL-46725-9.patch +Patch705: glibc-RHEL-46725-10.patch +Patch706: glibc-RHEL-46725-11.patch +Patch707: glibc-RHEL-46725-12.patch +Patch708: glibc-RHEL-1915-1.patch +Patch709: glibc-RHEL-1915-2.patch +Patch710: glibc-RHEL-1915-3.patch +Patch711: glibc-RHEL-1915-4.patch +Patch712: glibc-RHEL-1915-5.patch +Patch713: glibc-RHEL-1915-6.patch +Patch714: glibc-RHEL-1915-7.patch +Patch715: glibc-RHEL-1915-8.patch +Patch716: glibc-RHEL-1915-9.patch +Patch717: glibc-RHEL-47467.patch +Patch718: glibc-RHEL-56032.patch +Patch719: glibc-RHEL-67692-1.patch +Patch720: glibc-RHEL-67692-2.patch +Patch721: glibc-RHEL-67692-3.patch +Patch722: glibc-RHEL-67692-4.patch +Patch723: glibc-RHEL-46738-1.patch +Patch724: glibc-RHEL-46738-2.patch +Patch725: glibc-RHEL-46738-3.patch +Patch726: glibc-RHEL-46738-4.patch +Patch727: glibc-RHEL-65356-1.patch +Patch728: glibc-RHEL-65356-2.patch +Patch729: glibc-RHEL-38225-1.patch +Patch730: glibc-RHEL-38225-2.patch +Patch731: glibc-RHEL-54250.patch +Patch732: glibc-RHEL-56743.patch +Patch733: glibc-RHEL-57586.patch +Patch734: glibc-RHEL-56539.patch +Patch735: glibc-RHEL-56540-1.patch +Patch736: glibc-RHEL-56540-2.patch +Patch737: glibc-RHEL-56540-3.patch +Patch738: glibc-RHEL-58671.patch +Patch739: glibc-RHEL-46740.patch +Patch740: glibc-RHEL-65910.patch +Patch741: glibc-RHEL-69028.patch +Patch742: glibc-RHEL-70395-1.patch +Patch743: glibc-RHEL-70395-2.patch +Patch744: glibc-RHEL-68850-1.patch +Patch745: glibc-RHEL-68850-2.patch +Patch746: glibc-RHEL-61568.patch +Patch747: glibc-RHEL-58979.patch +Patch748: glibc-RHEL-65354.patch +Patch749: glibc-RHEL-56542-1.patch +Patch750: glibc-RHEL-56542-2.patch +Patch751: glibc-RHEL-56542-3.patch +Patch752: glibc-RHEL-56542-4.patch +Patch753: glibc-RHEL-56542-5.patch +Patch754: glibc-RHEL-56542-6.patch +Patch755: glibc-RHEL-56542-7.patch +Patch756: glibc-RHEL-56542-8.patch +Patch757: glibc-RHEL-56542-9.patch +Patch758: glibc-RHEL-65358-1.patch +Patch759: glibc-RHEL-65358-2.patch +Patch760: glibc-RHEL-65358-3.patch +Patch761: glibc-RHEL-65358-4.patch +Patch762: glibc-RHEL-65358-5.patch +Patch763: glibc-RHEL-58989-1.patch +Patch764: glibc-RHEL-58989-2.patch +Patch765: glibc-RHEL-62716-1.patch +Patch766: glibc-RHEL-62716-2.patch +Patch767: glibc-RHEL-68857.patch +Patch768: glibc-RHEL-69633-1.patch +Patch769: glibc-RHEL-69633-2.patch +Patch770: glibc-RHEL-58987-1.patch +Patch771: glibc-RHEL-58987-2.patch +Patch772: glibc-RHEL-61559-1.patch +Patch773: glibc-RHEL-61559-2.patch +Patch774: glibc-RHEL-61559-3.patch +Patch775: glibc-RHEL-61559-4.patch +Patch776: glibc-RHEL-50550.patch +Patch777: glibc-RHEL-65359-1.patch +Patch778: glibc-RHEL-65359-2.patch +Patch779: glibc-RHEL-65359-3.patch +Patch780: glibc-RHEL-65359-4.patch +Patch781: glibc-RHEL-75810.patch +Patch782: glibc-RHEL-46761-1.patch +Patch783: glibc-RHEL-46761-2.patch +Patch784: glibc-RHEL-46761-3.patch +Patch785: glibc-RHEL-46761-4.patch +Patch786: glibc-RHEL-75810-2.patch +Patch787: glibc-RHEL-75810-3.patch +Patch788: glibc-RHEL-46761-5.patch +Patch789: glibc-RHEL-75938.patch +Patch790: glibc-RHEL-67592-1.patch +Patch791: glibc-RHEL-67592-2.patch +Patch792: glibc-RHEL-67592-3.patch +Patch793: glibc-RHEL-67592-4.patch +Patch794: glibc-RHEL-2419-1.patch +Patch795: glibc-RHEL-2419-2.patch +Patch796: glibc-RHEL-2419-3.patch +Patch797: glibc-RHEL-2419-4.patch +Patch798: glibc-RHEL-2419-5.patch +Patch799: glibc-RHEL-2419-6.patch +Patch800: glibc-RHEL-2419-7.patch +Patch801: glibc-RHEL-2419-8.patch +Patch802: glibc-RHEL-2419-9.patch +Patch803: glibc-RHEL-2419-10.patch +Patch804: glibc-RHEL-46738-5.patch +Patch805: glibc-RHEL-46761-6.patch +Patch806: glibc-RHEL-24740-1.patch +Patch807: glibc-RHEL-24740-2.patch +Patch808: glibc-RHEL-24740-3.patch +Patch809: glibc-RHEL-71547.patch ############################################################################## # Continued list of core "glibc" package information: ############################################################################## Obsoletes: glibc-profile < 2.4 Provides: ldconfig +Provides: /sbin/ldconfig +Provides: /usr/sbin/ldconfig +# Historic file paths provided for backwards compatibility. +Provides: %{glibc_ldso} +Provides: /%{_lib}/libanl.so.1 +Provides: /%{_lib}/libc.so.6 +Provides: /%{_lib}/libdl.so.2 +Provides: /%{_lib}/libm.so.6 +Provides: /%{_lib}/libpthread.so.0 +Provides: /%{_lib}/libresolv.so.2 +Provides: /%{_lib}/librt.so.1 +Provides: /%{_lib}/libutil.so.1 # The dynamic linker supports DT_GNU_HASH Provides: rtld(GNU_HASH) @@ -1892,17 +2165,20 @@ build # distribution that supports multiple installed glibc versions. %define glibc_sysroot $RPM_BUILD_ROOT -# Remove existing file lists. -find . -type f -name '*.filelist' -exec rm -rf {} \; - -# Reload compiler and build options that were used during %%build. -GCC=`cat Gcc` +# Create symbolic links for Features/UsrMove (aka UsrMerge, MoveToUsr). +# See below: Remove UsrMove symbolic links. +usrmove_file_names="bin lib lib64 sbin" +for d in $usrmove_file_names ; do + mkdir -p "%{glibc_sysroot}/usr/$d" + ln -s "usr/$d" "%{glibc_sysroot}/$d" +done %ifarch riscv64 -# RISC-V ABI wants to install everything in /lib64/lp64d or /usr/lib64/lp64d. +# RISC-V ABI wants to install everything in /usr/lib64/lp64d. +# Make these be symlinks to /usr/lib64. See: # Make these be symlinks to /lib64 or /usr/lib64 respectively. See: # https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/DRHT5YTPK4WWVGL3GIN5BF2IKX2ODHZ3/ -for d in %{glibc_sysroot}%{_libdir} %{glibc_sysroot}/%{_lib}; do +for d in %{glibc_sysroot}%{_libdir}; do mkdir -p $d (cd $d && ln -sf . lp64d) done @@ -1918,6 +2194,16 @@ popd # via hardlinks, so we must group them ourselves. hardlink -c %{glibc_sysroot}/usr/lib/locale +%if %{glibc_autorequires} +mkdir -p %{glibc_sysroot}/%{_rpmconfigdir} %{glibc_sysroot}/%{_fileattrsdir} +sed < %{SOURCE3} \ + -e s/@VERSION@/%{version}/ \ + -e s/@RELEASE@/%{baserelease}/ \ + -e s/@SYMVER@/%{glibc_autorequires_symver}/ \ + > %{glibc_sysroot}/%{_rpmconfigdir}/glibc.req +cp %{SOURCE4} %{glibc_sysroot}/%{_fileattrsdir}/glibc.attr +%endif + # install_different: # Install all core libraries into DESTDIR/SUBDIR. Either the file is # installed as a copy or a symlink to the default install (if it is the @@ -1953,7 +2239,7 @@ install_different() libbase=${lib#*/} # Take care that `libbaseso' has a * that needs expanding so # take care with quoting. - libbaseso=$(basename %{glibc_sysroot}/%{_lib}/${libbase}.so.*) + libbaseso=$(basename %{glibc_sysroot}/%{_libdir}/${libbase}.so.*) # Only install if different from default build library. if cmp -s ${lib}.so ../build-%{target}/${lib}.so; then ln -sf "$subdir_up"/$libbaseso $libdestdir/$libbaseso @@ -1979,11 +2265,10 @@ install -p -D -m 0644 %{SOURCE13} ${RPM_BUILD_ROOT}%{_sysusersdir}/nscd.conf # XXX: This looks like a bug in glibc that accidentally installed these # wrong files. We probably don't need this today. rm -f %{glibc_sysroot}/%{_libdir}/libNoVersion* -rm -f %{glibc_sysroot}/%{_lib}/libNoVersion* # Remove the old nss modules. -rm -f %{glibc_sysroot}/%{_lib}/libnss1-* -rm -f %{glibc_sysroot}/%{_lib}/libnss-*.so.1 +rm -f %{glibc_sysroot}%{_libdir}/libnss1-* +rm -f %{glibc_sysroot}%{_libdir}/libnss-*.so.1 # This statically linked binary is no longer necessary in a world where # the default Fedora install uses an initramfs, and further we have rpm-ostree @@ -2157,13 +2442,6 @@ mkdir -p %{glibc_sysroot}/var/{db,run}/nscd touch %{glibc_sysroot}/var/{db,run}/nscd/{passwd,group,hosts,services} touch %{glibc_sysroot}/var/run/nscd/{socket,nscd.pid} -# Move libpcprofile.so and libmemusage.so into the proper library directory. -# They can be moved without any real consequences because users would not use -# them directly. -mkdir -p %{glibc_sysroot}%{_libdir} -mv -f %{glibc_sysroot}/%{_lib}/lib{pcprofile,memusage}.so \ - %{glibc_sysroot}%{_libdir} - # Disallow linking against libc_malloc_debug. rm %{glibc_sysroot}%{_libdir}/libc_malloc_debug.so @@ -2189,7 +2467,14 @@ done # that have old linker scripts that reference this file. We ship this only # in compat-libpthread-nonshared sub-package. ############################################################################## -ar cr %{glibc_sysroot}%{_prefix}/%{_lib}/libpthread_nonshared.a +ar cr %{glibc_sysroot}%{_libdir}/libpthread_nonshared.a + +# Remove UsrMove symbolic links. +# These should not end in the packaged contents. +# They are part of the filesystem package. +for d in $usrmove_file_names ; do + rm "%{glibc_sysroot}/$d" +done ############################################################################### # Sysroot package creation. @@ -2251,365 +2536,83 @@ popd # installed files. ############################################################################## -############################################################################## -# Build the file lists used for describing the package and subpackages. -############################################################################## -# There are several main file lists (and many more for -# the langpack sub-packages (langpack-${lang}.filelist)): -# * master.filelist -# - Master file list from which all other lists are built. -# * glibc.filelist -# - Files for the glibc packages. -# * common.filelist -# - Flies for the common subpackage. -# * utils.filelist -# - Files for the utils subpackage. -# * nscd.filelist -# - Files for the nscd subpackage. -# * devel.filelist -# - Files for the devel subpackage. -# * doc.filelist -# - Files for the documentation subpackage. -# * headers.filelist -# - Files for the headers subpackage. -# * static.filelist -# - Files for the static subpackage. -# * libnsl.filelist -# - Files for the libnsl subpackage -# * nss_db.filelist -# * nss_hesiod.filelist -# - File lists for nss_* NSS module subpackages. -# * nss-devel.filelist -# - File list with the .so symbolic links for NSS packages. -# * compat-libpthread-nonshared.filelist. -# - File list for compat-libpthread-nonshared subpackage. +# Placement of files in subpackages is mostly controlled by the +# %%files section below. There are some exceptions where a subset of +# files are put in one package and need to be elided from another +# package, and it's not possible to do this easily using explicit file +# lists or directory matching. For these exceptions. .filelist file +# are created. -# Create the main file lists. This way we can append to any one of them later -# wihtout having to create it. Note these are removed at the start of the -# install phase. -touch master.filelist -touch glibc.filelist -touch common.filelist -touch utils.filelist -touch gconv.filelist -touch nscd.filelist -touch devel.filelist -touch doc.filelist -touch headers.filelist -touch static.filelist -touch libnsl.filelist -touch nss_db.filelist -touch nss_hesiod.filelist -touch nss-devel.filelist -touch compat-libpthread-nonshared.filelist +# Make the sorting below more consistent. +export LC_ALL=C -############################################################################### -# Master file list, excluding a few things. -############################################################################### -{ - # List all files or links that we have created during install. - # Files with 'etc' are configuration files, likewise 'gconv-modules' - # and 'gconv-modules.cache' are caches, and we exclude them. - find %{glibc_sysroot} \( -type f -o -type l \) \ - \( \ - -name etc -printf "%%%%config " -o \ - -name gconv-modules.cache \ - -printf "%%%%verify(not md5 size mtime) " -o \ - -name gconv-modules* \ - -printf "%%%%verify(not md5 size mtime) %%%%config(noreplace) " \ - , \ - ! -path "*/lib/debug/*" -printf "/%%P\n" \) - # List all directories with a %%dir prefix. We omit the info directory and - # all directories in (and including) /usr/share/locale. - find %{glibc_sysroot} -type d \ - \( -path '*%{_prefix}/share/locale' -prune -o \ - \( -path '*%{_prefix}/share/*' \ -%if %{with docs} - ! -path '*%{_infodir}' -o \ -%endif - -path "*%{_prefix}/include/*" \ - \) -printf "%%%%dir /%%P\n" \) -} | { - # Also remove the *.mo entries. We will add them to the - # language specific sub-packages. - # libnss_ files go into subpackages related to NSS modules. - # and .*/share/i18n/charmaps/.*), they go into the sub-package - # "locale-source". /sys-root/ files are put into the sysroot package. - sed -e '\,.*/share/locale/\([^/_]\+\).*/LC_MESSAGES/.*\.mo,d' \ - -e '\,.*/share/i18n/locales/.*,d' \ - -e '\,.*/share/i18n/charmaps/.*,d' \ - -e '\,.*/etc/\(localtime\|nsswitch.conf\|ld\.so\.conf\|ld\.so\.cache\|default\|rpc\|gai\.conf\),d' \ - -e '\,.*/%{_libdir}/lib\(pcprofile\|memusage\)\.so,d' \ - -e '\,.*/bin/\(memusage\|mtrace\|xtrace\|pcprofiledump\),d' \ - -e '\,.*/sys-root,d' -} | sort > master.filelist +# `make_sysroot_filelist PATH FIND-ARGS LIST` writes %%files section +# lines for files and directories in the sysroot under PATH to the +# file LIST, with FIND-ARGS passed to the find command. The output is +# passed through sort. +make_sysroot_filelist () { + ( + find "%{glibc_sysroot}$1" \( -type f -o -type l \) $2 \ + -printf "$1/%%P\n" || true + find "%{glibc_sysroot}$1" -type d $2 -printf "%%%%dir $1/%%P\n" || true + ) | sort > "$3" +} -# The master file list is now used by each subpackage to list their own -# files. We go through each package and subpackage now and create their lists. -# Each subpackage picks the files from the master list that they need. -# The order of the subpackage list generation does not matter. +# `remove_from_filelist FILE1 FILE2` removes the lines from FILE1 +# which are also in FILE2. The lines must not contain tabs, and the +# file is sorted as a side effect. The input files must be sorted +# according to the sort command. +remove_from_filelist () { + comm -23 "$1" "$2" > "$1.tmp" + mv "$1.tmp" "$1" +} -# Make the master file list read-only after this point to avoid accidental -# modification. -chmod 0444 master.filelist - -############################################################################### -# glibc -############################################################################### - -# Add all files with the following exceptions: -# - The info files '%{_infodir}/dir' -# - The partial (lib*_p.a) static libraries, include files. -# - The static files, objects, unversioned DSOs, and nscd. -# - The bin, locale, some sbin, and share. -# - We want iconvconfig in the main package and we do this by using -# a double negation of -v and [^i] so it removes all files in -# sbin *but* iconvconfig. -# - All the libnss files (we add back the ones we want later). -# - All bench test binaries. -# - The aux-cache, since it's handled specially in the files section. -# - Extra gconv modules. We add the required modules later. -cat master.filelist \ - | grep -v \ - -e '%{_infodir}' \ - -e '%{_libdir}/lib.*_p.a' \ - -e '%{_prefix}/include' \ - -e '%{_libdir}/lib.*\.a' \ - -e '%{_libdir}/.*\.o' \ - -e '%{_libdir}/lib.*\.so' \ - -e '%{_libdir}/gconv/.*\.so$' \ - -e '%{_libdir}/gconv/gconv-modules.d/gconv-modules-extra\.conf$' \ - -e 'nscd' \ - -e '%{_prefix}/bin' \ - -e '%{_prefix}/lib/locale' \ - -e '%{_prefix}/sbin/[^i]' \ - -e '%{_prefix}/share' \ - -e '/var/db/Makefile' \ - -e '/libnss_.*\.so[0-9.]*$' \ - -e '/libnsl' \ - -e 'glibc-benchtests' \ - -e 'aux-cache' \ - > glibc.filelist - -# Add specific files: -# - The nss_files, nss_compat, and nss_db files. -# - The libmemusage.so and libpcprofile.so used by utils. -for module in compat files dns; do - cat master.filelist \ - | grep -E \ - -e "/libnss_$module(\.so\.[0-9.]+|-[0-9.]+\.so)$" \ - >> glibc.filelist -done -grep -e "libmemusage.so" -e "libpcprofile.so" master.filelist >> glibc.filelist - -############################################################################### -# glibc-gconv-extra -############################################################################### - -grep -e "gconv-modules-extra.conf" master.filelist > gconv.filelist - -# Put the essential gconv modules into the main package. -GconvBaseModules="ANSI_X3.110 ISO8859-15 ISO8859-1 CP1252" -GconvBaseModules="$GconvBaseModules UNICODE UTF-16 UTF-32 UTF-7" -%ifarch s390 s390x -GconvBaseModules="$GconvBaseModules ISO-8859-1_CP037_Z900 UTF8_UTF16_Z9" -GconvBaseModules="$GconvBaseModules UTF16_UTF32_Z9 UTF8_UTF32_Z9" -%endif -GconvAllModules=$(cat master.filelist | - sed -n 's|%{_libdir}/gconv/\(.*\)\.so|\1|p') - -# Put the base modules into glibc and the rest into glibc-gconv-extra -for conv in $GconvAllModules; do - if echo $GconvBaseModules | grep -q $conv; then - grep -E -e "%{_libdir}/gconv/$conv.so$" \ - master.filelist >> glibc.filelist - else - grep -E -e "%{_libdir}/gconv/$conv.so$" \ - master.filelist >> gconv.filelist - fi -done - -############################################################################### -# glibc-devel -############################################################################### - -# Static libraries that land in glibc-devel, not glibc-static. -devel_static_library_pattern='/lib\(\(c\|nldbl\|mvec\)_nonshared\|g\|ieee\|mcheck\|pthread\|dl\|rt\|util\|anl\)\.a$' -# Static libraries neither in glibc-devel nor in glibc-static. -other_static_library_pattern='/libpthread_nonshared\.a' - -grep '%{_libdir}/lib.*\.a' master.filelist \ - | grep "$devel_static_library_pattern" \ - | grep -v "$other_static_library_pattern" \ - > devel.filelist - -# Put all of the object files and *.so (not the versioned ones) into the -# devel package. -grep '%{_libdir}/.*\.o' < master.filelist >> devel.filelist -grep '%{_libdir}/lib.*\.so' < master.filelist >> devel.filelist -# The exceptions are: -# - libmemusage.so and libpcprofile.so in glibc used by utils. -# - libnss_*.so which are in nss-devel. -sed -i -e '\,libmemusage.so,d' \ - -e '\,libpcprofile.so,d' \ - -e '\,/libnss_[a-z]*\.so$,d' \ - devel.filelist - -%if %{glibc_autorequires} -mkdir -p %{glibc_sysroot}/%{_rpmconfigdir} %{glibc_sysroot}/%{_fileattrsdir} -sed < %{SOURCE4} \ - -e s/@VERSION@/%{version}/ \ - -e s/@RELEASE@/%{release}/ \ - -e s/@SYMVER@/%{glibc_autorequires_symver}/ \ - > %{glibc_sysroot}/%{_rpmconfigdir}/glibc.req -cp %{SOURCE5} %{glibc_sysroot}/%{_fileattrsdir}/glibc.attr -%endif - -############################################################################### -# glibc-doc -############################################################################### - -%if %{with docs} -# Put the info files into the doc file list, but exclude the generated dir. -grep '%{_infodir}' master.filelist | grep -v '%{_infodir}/dir' > doc.filelist -grep '%{_docdir}' master.filelist >> doc.filelist -%endif - -############################################################################### -# glibc-headers -############################################################################### +# `split_sysroot_file_list DIR FIND-ARGS REGEXP MAIN-LIST EXCEPTIONS-LIST` +# creates a list of files in the sysroot subdirectory # DIR. +# Files and directories are enumerated with the find command, +# passing FIND-ARGS as an extra argument. Those output paths that +# match REGEXP (an POSIX extended regular expression; all whitespace +# in it is removed before matching) are put into EXCEPTIONS-LIST. The +# remaining files are put into MAIN-LIST. +split_sysroot_file_list () { + make_sysroot_filelist "$1" "$2" "$4" + grep -E -e "$(printf %%s "$3" | tr -d '[:space:]')" < "$4" > "$5" + remove_from_filelist "$4" "$5" +} +# glibc-devel historically contains a subset of the files in +# /usr/include/gnu. The remaining headers are in glibc-headers-*. +# The -regex clause skips /usr/include, which is owned by the +# filesystem package. The x86_64 exception is required because there +# are headers that should be part of the glibc32 package only. %if %{need_headers_package} -# The glibc-headers package includes only common files which are identical -# across all multilib packages. We must keep gnu/stubs.h and gnu/lib-names.h -# in the glibc-headers package, but the -32, -64, -64-v1, and -64-v2 versions -# go into glibc-devel. -grep '%{_prefix}/include/gnu/stubs-.*\.h$' < master.filelist >> devel.filelist || : -grep '%{_prefix}/include/gnu/lib-names-.*\.h$' < master.filelist >> devel.filelist || : -# Put the include files into headers file list. -grep '%{_prefix}/include' < master.filelist \ - | egrep -v '%{_prefix}/include/gnu/stubs-.*\.h$' \ - | egrep -v '%{_prefix}/include/gnu/lib-names-.*\.h$' \ - > headers.filelist -%else -# If there is no glibc-headers package, all header files go into the -# glibc-devel package. -grep '%{_prefix}/include' < master.filelist >> devel.filelist +split_sysroot_file_list \ + %{_includedir} '( + ! -regex .*%{_includedir}$ +%ifarch x86_64 + ! -regex .*%{_includedir}/gnu/.*-32\.h$ +%endif + )' \ + '%{_includedir}/gnu/(stubs|lib-names)-.*\.h$' \ + headers.filelist devel.filelist %endif -############################################################################### -# glibc-static -############################################################################### - -# Put the rest of the static files into the static package. -grep '%{_libdir}/lib.*\.a' < master.filelist \ - | grep -v "$devel_static_library_pattern" \ - | grep -v "$other_static_library_pattern" \ - > static.filelist - -############################################################################### -# glibc-common -############################################################################### - -# All of the bin and certain sbin files go into the common package except -# iconvconfig which needs to go in glibc. Likewise nscd is excluded because -# it goes in nscd. The iconvconfig binary is kept in the main glibc package -# because we use it in the post-install scriptlet to rebuild the -# gconv-modules.cache. The makedb binary is in nss_db. -grep '%{_prefix}/bin' master.filelist \ - | grep -v '%{_prefix}/bin/makedb' \ - >> common.filelist -grep '%{_prefix}/sbin' master.filelist \ - | grep -v '%{_prefix}/sbin/iconvconfig' \ - | grep -v 'nscd' >> common.filelist -# All of the files under share go into the common package since they should be -# multilib-independent. -# Exceptions: -# - The actual share directory, not owned by us. -# - The info files which go into doc, and the info directory. -# - All documentation files, which go into doc. -grep '%{_prefix}/share' master.filelist \ - | grep -v \ - -e '%{_prefix}/share/info/libc.info.*' \ - -e '%%dir %{prefix}/share/info' \ - -e '%%dir %{prefix}/share' \ - -e '%{_docdir}' \ - >> common.filelist - -############################################################################### -# nscd -############################################################################### - -# The nscd binary must go into the nscd subpackage. -echo '%{_prefix}/sbin/nscd' > nscd.filelist - -############################################################################### -# glibc-utils -############################################################################### - -# Add the utils scripts and programs to the utils subpackage. -cat > utils.filelist < nss_$module.filelist -done -grep -E "%{_prefix}/bin/makedb$" master.filelist >> nss_db.filelist - -############################################################################### -# nss-devel -############################################################################### - -# Symlinks go into the nss-devel package (instead of the main devel -# package). -grep '/libnss_[a-z]*\.so$' master.filelist > nss-devel.filelist - -############################################################################### -# libnsl -############################################################################### - -# Prepare the libnsl-related file lists. -grep -E '/libnsl\.so\.[0-9]+$' master.filelist > libnsl.filelist -test $(wc -l < libnsl.filelist) -eq 1 - -%if %{with benchtests} -############################################################################### -# glibc-benchtests -############################################################################### - -# List of benchmarks. -find build-%{target}/benchtests -type f -executable | while read b; do - echo "%{_prefix}/libexec/glibc-benchtests/$(basename $b)" -done >> benchtests.filelist -# ... and the makefile. -for b in %{SOURCE2} %{SOURCE3}; do - echo "%{_prefix}/libexec/glibc-benchtests/$(basename $b)" >> benchtests.filelist -done -# ... and finally, the comparison scripts. -echo "%{_prefix}/libexec/glibc-benchtests/benchout.schema.json" >> benchtests.filelist -echo "%{_prefix}/libexec/glibc-benchtests/compare_bench.py*" >> benchtests.filelist -echo "%{_prefix}/libexec/glibc-benchtests/import_bench.py*" >> benchtests.filelist -echo "%{_prefix}/libexec/glibc-benchtests/validate_benchout.py*" >> benchtests.filelist -%endif - -############################################################################### -# compat-libpthread-nonshared -############################################################################### -echo "%{_libdir}/libpthread_nonshared.a" >> compat-libpthread-nonshared.filelist +# The primary gconv converters are in the glibc package, the rest goes +# into glibc-gconv-extra. The Z9 and Z900 subpatterns are for +# s390x-specific converters. The -name clause skips over files +# that are not loadable gconv modules. +split_sysroot_file_list \ + %{_libdir}/gconv '-name *.so' \ + 'gconv/ + (ANSI_X3\.110 + |CP1252 + |ISO8859-15? + |UNICODE + |UTF-[0-9]+ + |ISO-8859-1_CP037_Z900 + |UTF(8|16)_UTF(16|32)_Z9 + )\.so$' \ + gconv-extra.filelist glibc.filelist ############################################################################## # Run the glibc testsuite @@ -2679,18 +2682,12 @@ fi echo ====================TESTING END===================== PLTCMD='/^Relocation section .*\(\.rela\?\.plt\|\.rela\.IA_64\.pltoff\)/,/^$/p' echo ====================PLT RELOCS LD.SO================ -readelf -Wr %{glibc_sysroot}/%{_lib}/ld-*.so | sed -n -e "$PLTCMD" +readelf -Wr %{glibc_sysroot}%{_libdir}/ld-*.so | sed -n -e "$PLTCMD" echo ====================PLT RELOCS LIBC.SO============== -readelf -Wr %{glibc_sysroot}/%{_lib}/libc-*.so | sed -n -e "$PLTCMD" +readelf -Wr %{glibc_sysroot}%{_libdir}/libc-*.so | sed -n -e "$PLTCMD" echo ====================PLT RELOCS END================== -# Obtain a way to run the dynamic loader. Avoid matching the symbolic -# link and then pick the first loader (although there should be only -# one). Use -maxdepth 2 to avoid descending into the /sys-root/ -# sub-tree. See wrap-find-debuginfo.sh. -ldso_path="$(find %{glibc_sysroot}/ -maxdepth 2 -regextype posix-extended \ - -regex '.*/ld(-.*|64|)\.so\.[0-9]+$' -type f | LC_ALL=C sort | head -n1)" -run_ldso="$ldso_path --library-path %{glibc_sysroot}/%{_lib}" +run_ldso="%{glibc_sysroot}/%{_prefix}%{glibc_ldso} --library-path %{glibc_sysroot}/%{_libdir}" # Show the auxiliary vector as seen by the new library # (even if we do not perform the valgrind test). @@ -2916,17 +2913,45 @@ update_gconv_modules_cache () %systemd_postun_with_restart nscd.service %files -f glibc.filelist -%dir %{_prefix}/%{_lib}/audit +%{_sbindir}/ldconfig +%{_sbindir}/iconvconfig +%{_libexecdir}/getconf +%{_prefix}%{glibc_ldso} +%{_libdir}/libBrokenLocale.so.1 +%{_libdir}/libSegFault.so +%{_libdir}/libanl.so.1 +%{_libdir}/libc.so.6 +%{_libdir}/libc_malloc_debug.so.0 +%{_libdir}/libdl.so.2 +%{_libdir}/libm.so.6 +%{_libdir}/libmemusage.so +%{_libdir}/libnss_compat.so.2 +%{_libdir}/libnss_dns.so.2 +%{_libdir}/libnss_files.so.2 +%{_libdir}/libpcprofile.so +%{_libdir}/libpthread.so.0 +%{_libdir}/libresolv.so.2 +%{_libdir}/librt.so.1 +%{_libdir}/libthread_db.so.1 +%{_libdir}/libutil.so.1 +%{_libdir}/audit +%if %{glibc_has_libmvec} +%{_libdir}/libmvec.so.1 +%endif %if %{buildpower10} -%dir /%{_libdir}/glibc-hwcaps/power10 +%{_libdir}/glibc-hwcaps %endif %verify(not md5 size mtime link) %config(noreplace) /etc/nsswitch.conf %verify(not md5 size mtime) %config(noreplace) /etc/ld.so.conf %verify(not md5 size mtime) %config(noreplace) /etc/rpc %dir /etc/ld.so.conf.d -%dir %{_prefix}/libexec/getconf %dir %{_libdir}/gconv %dir %{_libdir}/gconv/gconv-modules.d +%verify(not md5 size mtime) %config(noreplace) %{_libdir}/gconv/gconv-modules +%verify(not md5 size mtime) %{_libdir}/gconv/gconv-modules.cache +%ifarch s390x +%verify(not md5 size mtime) %config(noreplace) %{_libdir}/gconv/gconv-modules.d/gconv-modules-s390.conf +%endif %dir %attr(0700,root,root) /var/cache/ldconfig %attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/cache/ldconfig/aux-cache %attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/ld.so.cache @@ -2935,10 +2960,31 @@ update_gconv_modules_cache () %{!?_licensedir:%global license %%doc} %license COPYING COPYING.LIB LICENSES -%files -f common.filelist common +%files common +%{_bindir}/catchsegv +%{_bindir}/gencat +%{_bindir}/getconf +%{_bindir}/getent +%{_bindir}/iconv +%{_bindir}/ld.so +%{_bindir}/ldd +%{_bindir}/locale +%{_bindir}/localedef +%{_bindir}/pldd +%{_bindir}/sotruss +%{_bindir}/sprof +%{_bindir}/tzselect +%{_bindir}/zdump +%{_sbindir}/zic +%dir %{_datarootdir}/i18n +%dir %{_datarootdir}/i18n/locales +%dir %{_datarootdir}/i18n/charmaps %dir %{_prefix}/lib/locale -%dir %{_prefix}/lib/locale/C.utf8 -%{_prefix}/lib/locale/C.utf8/* +%{_datarootdir}/locale/locale.alias +%{_prefix}/lib/locale/C.utf8 +%ifarch %{ix86} +%{_bindir}/lddlibc4 +%endif %files all-langpacks %{_prefix}/lib/locale/locale-archive @@ -2946,37 +2992,78 @@ update_gconv_modules_cache () %{_prefix}/share/locale/*/LC_MESSAGES/libc.mo %files locale-source -%dir %{_prefix}/share/i18n/locales -%{_prefix}/share/i18n/locales/* -%dir %{_prefix}/share/i18n/charmaps -%{_prefix}/share/i18n/charmaps/* +%{_datarootdir}/i18n/locales +%{_datarootdir}/i18n/charmaps +%if %{need_headers_package} %files -f devel.filelist devel +%else +%files devel +%{_includedir}/* +%endif %if %{glibc_autorequires} %attr(0755,root,root) %{_rpmconfigdir}/glibc.req %{_fileattrsdir}/glibc.attr %endif - -%if %{with docs} -%files -f doc.filelist doc +%{_libdir}/*.o +%{_libdir}/libBrokenLocale.so +%{_libdir}/libanl.a +%{_libdir}/libanl.so +%{_libdir}/libc.so +%{_libdir}/libc_nonshared.a +%{_libdir}/libdl.a +%{_libdir}/libg.a +%{_libdir}/libm.so +%{_libdir}/libmcheck.a +%{_libdir}/libpthread.a +%{_libdir}/libresolv.so +%{_libdir}/librt.a +%{_libdir}/libthread_db.so +%{_libdir}/libutil.a +%if %{glibc_has_libnldbl} +%{_libdir}/libnldbl_nonshared.a +%endif +%if %{glibc_has_libmvec} +%{_libdir}/libmvec.so %endif -%files -f static.filelist static +%if %{with docs} +%files doc +%{_datarootdir}/doc +%{_infodir}/*.info* +%endif + +%files static +%{_libdir}/libBrokenLocale.a +%{_libdir}/libc.a +%{_libdir}/libm.a +%{_libdir}/libresolv.a +%if %{glibc_has_libmvec} +%{_libdir}/libm-%{version}.a +%{_libdir}/libmvec.a +%endif %if %{need_headers_package} %files -f headers.filelist -n %{headers_package_name} %endif -%files -f utils.filelist utils +%files utils +%{_bindir}/memusage +%{_bindir}/memusagestat +%{_bindir}/mtrace +%{_bindir}/pcprofiledump +%{_bindir}/xtrace -%files -f gconv.filelist gconv-extra +%files -f gconv-extra.filelist gconv-extra +%verify(not md5 size mtime) %config(noreplace) %{_libdir}/gconv/gconv-modules.d/gconv-modules-extra.conf -%files -f nscd.filelist -n nscd +%files -n nscd +%{_sbindir}/nscd %config(noreplace) /etc/nscd.conf %dir %attr(0755,root,root) /var/run/nscd %dir %attr(0755,root,root) /var/db/nscd -/lib/systemd/system/nscd.service -/lib/systemd/system/nscd.socket +%{_prefix}/lib/systemd/system/nscd.service +%{_prefix}/lib/systemd/system/nscd.socket %{_tmpfilesdir}/nscd.conf %attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/nscd.pid %attr(0666,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/socket @@ -2991,20 +3078,28 @@ update_gconv_modules_cache () %ghost %config(missingok,noreplace) /etc/sysconfig/nscd %{_sysusersdir}/nscd.conf -%files -f nss_db.filelist -n nss_db +%files -n nss_db +%{_bindir}/makedb +%{_libdir}/libnss_db.so.2 /var/db/Makefile -%files -f nss_hesiod.filelist -n nss_hesiod +%files -n nss_hesiod +%{_libdir}/libnss_hesiod.so.2 %doc hesiod/README.hesiod -%files -f nss-devel.filelist nss-devel +%files nss-devel +%{_libdir}/libnss_compat.so +%{_libdir}/libnss_db.so +%{_libdir}/libnss_hesiod.so -%files -f libnsl.filelist -n libnsl -/%{_lib}/libnsl.so.1 +%files -n libnsl +%{_libdir}/libnsl.so.1 %if %{with benchtests} -%files benchtests -f benchtests.filelist +%files benchtests +%{_libexecdir}/glibc-benchtests %endif -%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared +%files -n compat-libpthread-nonshared +%{_libdir}/libpthread_nonshared.a %if %{without bootstrap} %files -n sysroot-%{_arch}-%{sysroot_dist}-glibc @@ -3012,6 +3107,176 @@ update_gconv_modules_cache () %endif %changelog +* Thu Feb 13 2025 Florian Weimer - 2.34-168 +- Fix transliteration regression in iconv tool (RHEL-71547) + +* Thu Feb 13 2025 Florian Weimer - 2.34-167 +- POWER10 string function optimizations (RHEL-24740) + +* Tue Feb 11 2025 Arjun Shankar - 2.34-166 +- Revert: Backport: debug: Add regression tests for BZ 30932 (RHEL-46761) + +* Mon Feb 10 2025 Florian Weimer - 2.34-165 +- Hide internal struct _IO_FILE ABI change in installed header (RHEL-46738) + +* Fri Feb 7 2025 Carlos O'Donell - 2.34-164 +- Fix missed wakeup in POSIX thread condition variables (RHEL-2419) + +* Tue Feb 4 2025 DJ Delorie - 2.34-163 +- manual: sigaction's sa_flags field and SA_SIGINFO (RHEL-67592) + +* Wed Jan 29 2025 Patsy Griffin - 2.34-162 +- CVE-2025-0395: fix underallocation of abort_msg_s struct (RHEL-75938) + +* Tue Jan 28 2025 Frédéric Bérat - 2.34-161 +- Backport: debug: Add regression tests for BZ 30932 (RHEL-46761) + +* Mon Jan 27 2025 Florian Weimer - 2.34-160 +- Rebuild with gcc-11.5.0-2.el9 (RHEL-76359) + +* Fri Jan 24 2025 Florian Weimer - 2.34-159 +- setenv: Rework free(environ) compatibility support (RHEL-75810) + +* Thu Jan 23 2025 Florian Weimer - 2.34-158 +- Add tests extracted from upstream printf regression tests (RHEL-46761) + +* Thu Jan 23 2025 Florian Weimer - 2.34-157 +- Restore compatibility with environ/malloc usage pattern (RHEL-75810) + +* Thu Jan 23 2025 Florian Weimer - 2.34-156 +- Additional test for assert (RHEL-65359) + +* Thu Jan 23 2025 Florian Weimer - 2.34-155 +- Change utimensat to accept NULL pathname arguments (RHEL-50550) + +* Tue Jan 21 2025 Florian Weimer - 2.34-154 +- Add test for inheritance of thread affinity mask (RHEL-61559) + +* Mon Jan 20 2025 Florian Weimer - 2.34-153 +- Additional dynamic linker dependency sorting tests (RHEL-58987) + +* Fri Jan 10 2025 Frédéric Bérat - 2.34-152 +- Additional TLS test cases (RHEL-58989) +- Additional mremap test cases (RHEL-62716) +- Fix pthread_timedjoin_np error handling and increase test coverage (RHEL-68857) +- Avoid uninitialized result in sem_open when file does not exist (RHEL-69633) + +* Fri Jan 10 2025 Frédéric Bérat - 2.34-151 +- Lock all stdio streams during exit +- Support concurrent calls to exit (RHEL-65358) + +* Fri Jan 10 2025 Frédéric Bérat - 2.34-150 +- Backport test implementation to verify readdir behavior (RHEL-56542) +- Backport the deallocation attributes commit for opendir/fdopendir (RHEL-56543) +- Backport: Fix bug bz#27454 and test implementation to verify + fdopendir behavior (RHEL-56544) +- Backport test implementation to verify closedir behavior + (RHEL-56541) + +* Wed Jan 08 2025 Frédéric Bérat - 2.34-149 +- Backport: fix the glibc manual to handle spaces for @deftypefun + references. (RHEL-65356) +- Backport verbosity patches for glibc math (RHEL-38225) +- Backport getdelim test coverage improvements (RHEL-54250) +- Backport mkdirat mode test (RHEL-56743) +- Backport: cover the documentation coverage gap adding thread safety + annotations for clock_gettime and clock_getres (RHEL-57586) +- Backport test implementation to verify lstat behavior (RHEL-56539) +- Backport test implementation to verify rewinddir behavior + (RHEL-56540) +- Backport elf/tst-startup-errno test (RHEL-58671) +- Backport: Identify unsafe macros in the glibc documentation (RHEL-46740) +- Backport: testsuite fixes for rhel-57588, rhel-57589, and rhel-57590 (RHEL-65910) +- Backport new multi-threaded test for sem_getvalue (RHEL-69028) +- Backport pthread_getcpuclockid tests (RHEL-70395) +- Backport: Debug/tst-longjmp_chk3 needs to be enabled (RHEL-68850) +- Backport: Improve pthread_spin_trylock test coverage (RHEL-61568) +- Backport: Implement test to verify dynamic linker behaves correctly in case + of hash collision for the symbol name and symbol version. (RHEL-58979) +- Backport: Improve sem_trywait test coverage (RHEL-65354) + +* Thu Dec 19 2024 DJ Delorie - 2.34-148 +- Increase ungetc test coverage, guarantee single char pushback (RHEL-46738) + +* Mon Dec 16 2024 Florian Weimer - 2.34-147 +- Make getenv thread-safe in more cases (RHEL-67692) + +* Mon Dec 9 2024 Florian Weimer - 2.34-146 +- Use UsrMove path destination in the RPM files (RHEL-65334) + +* Thu Dec 5 2024 DJ Delorie - 2.34-145 +- add GB18030-2022 charmap and tests (RHEL-56032) + +* Mon Dec 2 2024 Florian Weimer - 2.34-144 +- Document struct link_map and interaction with dlinfo (RHEL-47467) + +* Wed Nov 20 2024 Patsy Griffin - 2.34-143 +- iconv: Support in-place conversions (RHEL-1915) + +* Mon Nov 18 2024 Florian Weimer - 2.34-142 +- Add printf function family tests (RHEL-46725) + +* Mon Nov 11 2024 Arjun Shankar - 2.34-141 +- Add error and FUSE based tests for fchmod (RHEL-50548) + +* Thu Nov 7 2024 Florian Weimer - 2.34-140 +- Add more tests for freopen (RHEL-46736) + +* Thu Nov 7 2024 Florian Weimer - 2.34-139 +- Add more tests of getline (RHEL-54413) + +* Thu Nov 7 2024 Florian Weimer - 2.34-138 +- Add fclose testcases (RHEL-46733) + +* Thu Nov 7 2024 Florian Weimer - 2.34-137 +- Fix memory leak after fdopen seek failure (RHEL-66253) + +* Thu Nov 7 2024 Florian Weimer - 2.34-136 +- Document rules for mixing stdio streams and file descriptors (RHEL-46724) + +* Wed Nov 06 2024 Patsy Griffin - 2.34-135 +- Support clearing options in /etc/resolv.conf, RES_OPTIONS with a - prefix +- Introduce the strict-error/RES_STRICTERR stub resolver option (RHEL-50662) + +* Wed Oct 23 2024 DJ Delorie - 2.34-134 +- Test Implementation to verify mkstemp behavior, + with FUSE support (RHEL-50545) + +* Mon Sep 30 2024 Arjun Shankar - 2.34-133 +- strtod: Fix subnormal rounding; do not set errno upon overflowing payload; + and add several new tests (RHEL-46739) + +* Fri Sep 27 2024 Florian Weimer - 2.34-132 +- Remove some unused ppc64le string functions (RHEL-60466) + +* Thu Sep 26 2024 Arjun Shankar - 2.34-131 +- Add new test for fread (RHEL-46735) + +* Thu Sep 26 2024 Arjun Shankar - 2.34-130 +- Add new test for fdopen (RHEL-46734) + +* Tue Sep 24 2024 DJ Delorie - 2.34-129 +- Add fgets testcases (RHEL-46728) + +* Tue Sep 24 2024 DJ Delorie - 2.34-128 +- manual: Add Descriptor-Relative Access section (RHEL-41189) + +* Tue Sep 24 2024 Florian Weimer - 2.34-127 +- Switch to upstream approach for building xtest during make check (RHEL-59494) + +* Thu Sep 19 2024 Florian Weimer - 2.34-126 +- Ensure that xtests can be built (RHEL-59494) + +* Thu Sep 5 2024 DJ Delorie - 2.34-125 +- elf: Rework exception handling in the dynamic loader (RHEL-46979) + +* Thu Sep 5 2024 Siddhesh Poyarekar - 2.34-124 +- Fix ungetc leak and invalid read (RHEL-54447) + +* Tue Sep 03 2024 Patsy Griffin - 2.34-123 +- s390x: Fix segfault in wcsncmp +- Enhanced test coverage for strncmp, wcsncmp (RHEL-49489) + * Wed Aug 28 2024 Patsy Griffin - 2.34-122 - elf: Clarify and invert second argument of _dl_allocate_tls_init - elf: Avoid re-initializing already allocated TLS in dlopen (RHEL-36148)