commit
7005c9e39e
194
glibc-RHEL-71530-1.patch
Normal file
194
glibc-RHEL-71530-1.patch
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
commit 1b0a2062c8938c7333cd118d85d9976c4e7c92af
|
||||||
|
Author: Andreas Schwab <schwab@suse.de>
|
||||||
|
Date: Mon Jun 10 12:19:17 2024 +0200
|
||||||
|
|
||||||
|
iconv: Fix matching of multi-character transliterations (bug 31859)
|
||||||
|
|
||||||
|
Only return __GCONV_INCOMPLETE_INPUT for a partial match when the end of
|
||||||
|
the input buffer is reached. Otherwise it is a non-match, and other
|
||||||
|
patterns should be tried.
|
||||||
|
|
||||||
|
diff --git a/iconv/Makefile b/iconv/Makefile
|
||||||
|
index 63afc853ff65967a..65b4a44ab86cf0dc 100644
|
||||||
|
--- a/iconv/Makefile
|
||||||
|
+++ b/iconv/Makefile
|
||||||
|
@@ -57,6 +57,10 @@ tests = \
|
||||||
|
tst-iconv-opt \
|
||||||
|
# tests
|
||||||
|
|
||||||
|
+test-srcs := \
|
||||||
|
+ tst-translit-mchar \
|
||||||
|
+ # test-srcs
|
||||||
|
+
|
||||||
|
others = iconv_prog iconvconfig
|
||||||
|
install-others-programs = $(inst_bindir)/iconv
|
||||||
|
install-sbin = iconvconfig
|
||||||
|
@@ -73,6 +77,7 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
||||||
|
ifeq ($(run-built-tests),yes)
|
||||||
|
xtests-special += $(objpfx)test-iconvconfig.out
|
||||||
|
tests-special += $(objpfx)tst-iconv_prog.out
|
||||||
|
+tests-special += $(objpfx)tst-translit-mchar.out
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Make a copy of the file because gconv module names are constructed
|
||||||
|
@@ -92,6 +97,8 @@ $(objpfx)tst-gconv-init-failure.out: \
|
||||||
|
$(objpfx)gconv-modules $(objpfx)tst-gconv-init-failure-mod.so
|
||||||
|
endif
|
||||||
|
|
||||||
|
+generated-dirs += tst-translit
|
||||||
|
+
|
||||||
|
include ../Rules
|
||||||
|
|
||||||
|
ifeq ($(run-built-tests),yes)
|
||||||
|
@@ -126,3 +133,11 @@ $(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
|
||||||
|
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
|
||||||
|
'$(run-program-env)' > $@; \
|
||||||
|
$(evaluate-test)
|
||||||
|
+
|
||||||
|
+$(objpfx)tst-translit-mchar.out: tst-translit-mchar.sh \
|
||||||
|
+ $(objpfx)tst-translit-mchar \
|
||||||
|
+ tst-translit-locale
|
||||||
|
+ $(SHELL) $< $(common-objpfx) '$(run-program-prefix-before-env)' \
|
||||||
|
+ '$(run-program-env)' '$(run-program-prefix-after-env)' \
|
||||||
|
+ $< > $@; \
|
||||||
|
+ $(evaluate-test)
|
||||||
|
diff --git a/iconv/gconv_trans.c b/iconv/gconv_trans.c
|
||||||
|
index 08b7a3f71dad5f1e..44f0fd849a3f82a3 100644
|
||||||
|
--- a/iconv/gconv_trans.c
|
||||||
|
+++ b/iconv/gconv_trans.c
|
||||||
|
@@ -150,7 +150,7 @@ __gconv_transliterate (struct __gconv_step *step,
|
||||||
|
|
||||||
|
/* Nothing found, continue searching. */
|
||||||
|
}
|
||||||
|
- else if (cnt > 0)
|
||||||
|
+ else if (cnt > 0 && winbuf + cnt == winbufend)
|
||||||
|
/* This means that the input buffer contents matches a prefix of
|
||||||
|
an entry. Since we cannot match it unless we get more input,
|
||||||
|
we will tell the caller about it. */
|
||||||
|
diff --git a/iconv/tst-translit-locale b/iconv/tst-translit-locale
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..712b08628a64dc11
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/iconv/tst-translit-locale
|
||||||
|
@@ -0,0 +1,10 @@
|
||||||
|
+# Test multi-character transliteration rule
|
||||||
|
+
|
||||||
|
+LC_CTYPE
|
||||||
|
+copy "POSIX"
|
||||||
|
+
|
||||||
|
+translit_start
|
||||||
|
+"ÄÄ" "AA"
|
||||||
|
+translit_end
|
||||||
|
+
|
||||||
|
+END LC_CTYPE
|
||||||
|
diff --git a/iconv/tst-translit-mchar.c b/iconv/tst-translit-mchar.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..7d432ea6679b60fa
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/iconv/tst-translit-mchar.c
|
||||||
|
@@ -0,0 +1,48 @@
|
||||||
|
+/* Test multi-character transliterations.
|
||||||
|
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||||
|
+ This file is part of the GNU C Library.
|
||||||
|
+
|
||||||
|
+ The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
+ modify it under the terms of the GNU Lesser General Public
|
||||||
|
+ License as published by the Free Software Foundation; either
|
||||||
|
+ version 2.1 of the License, or (at your option) any later version.
|
||||||
|
+
|
||||||
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
+ Lesser General Public License for more details.
|
||||||
|
+
|
||||||
|
+ You should have received a copy of the GNU Lesser General Public
|
||||||
|
+ License along with the GNU C Library; if not, see
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <locale.h>
|
||||||
|
+#include <iconv.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ iconv_t cd;
|
||||||
|
+ /* An input sequence that shares a common prefix with a transliteration
|
||||||
|
+ rule. */
|
||||||
|
+ char input[] = "ÄÅ";
|
||||||
|
+ char *inptr = input;
|
||||||
|
+ char outbuf[10];
|
||||||
|
+ char *outptr = outbuf;
|
||||||
|
+ size_t inlen = sizeof (input), outlen = sizeof (outbuf);
|
||||||
|
+ size_t n;
|
||||||
|
+
|
||||||
|
+ xsetlocale (LC_CTYPE, "tst-translit");
|
||||||
|
+
|
||||||
|
+ cd = iconv_open ("ASCII//TRANSLIT", "UTF-8");
|
||||||
|
+ TEST_VERIFY (cd != (iconv_t) -1);
|
||||||
|
+
|
||||||
|
+ /* This call used to loop infinitely. */
|
||||||
|
+ n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
|
||||||
|
+ TEST_VERIFY (iconv_close (cd) == 0);
|
||||||
|
+ return n == 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/iconv/tst-translit-mchar.sh b/iconv/tst-translit-mchar.sh
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ab7a7f872911cf21
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/iconv/tst-translit-mchar.sh
|
||||||
|
@@ -0,0 +1,51 @@
|
||||||
|
+#!/bin/sh
|
||||||
|
+# Testing of multi-character transliterations
|
||||||
|
+# Copyright (C) 2024 Free Software Foundation, Inc.
|
||||||
|
+# This file is part of the GNU C Library.
|
||||||
|
+
|
||||||
|
+# The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
+# modify it under the terms of the GNU Lesser General Public
|
||||||
|
+# License as published by the Free Software Foundation; either
|
||||||
|
+# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
+
|
||||||
|
+# The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
+# Lesser General Public License for more details.
|
||||||
|
+
|
||||||
|
+# You should have received a copy of the GNU Lesser General Public
|
||||||
|
+# License along with the GNU C Library; if not, see
|
||||||
|
+# <https://www.gnu.org/licenses/>.
|
||||||
|
+
|
||||||
|
+set -e
|
||||||
|
+
|
||||||
|
+common_objpfx=$1
|
||||||
|
+run_program_prefix_before_env=$2
|
||||||
|
+run_program_env=$3
|
||||||
|
+run_program_prefix_after_env=$4
|
||||||
|
+
|
||||||
|
+# Generate data files.
|
||||||
|
+# The locale only defines the LC_CTYPE category, so we expect a failure
|
||||||
|
+# due to warnings.
|
||||||
|
+ret=0
|
||||||
|
+${run_program_prefix_before_env} \
|
||||||
|
+${run_program_env} \
|
||||||
|
+I18NPATH=../localedata \
|
||||||
|
+${run_program_prefix_after_env} ${common_objpfx}locale/localedef \
|
||||||
|
+--quiet -i tst-translit-locale -f UTF-8 ${common_objpfx}iconv/tst-translit || ret=$?
|
||||||
|
+if [ $ret -gt 1 ]; then
|
||||||
|
+ echo "FAIL: Locale compilation for tst-translit-locale failed (error $ret)."
|
||||||
|
+ exit 1
|
||||||
|
+fi
|
||||||
|
+
|
||||||
|
+set -x
|
||||||
|
+
|
||||||
|
+# Run the test.
|
||||||
|
+${run_program_prefix_before_env} \
|
||||||
|
+${run_program_env} \
|
||||||
|
+LOCPATH=${common_objpfx}iconv \
|
||||||
|
+${run_program_prefix_after_env} ${common_objpfx}iconv/tst-translit-mchar
|
||||||
|
+
|
||||||
|
+# Local Variables:
|
||||||
|
+# mode:shell-script
|
||||||
|
+# End:
|
108
glibc-RHEL-71530-10.patch
Normal file
108
glibc-RHEL-71530-10.patch
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
commit 9a4b0eaf726f5404c6683d5c7c5e86f61c3f3fbc
|
||||||
|
Author: Aurelien Jarno <aurelien@aurel32.net>
|
||||||
|
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 <aurelien@aurel32.net>
|
||||||
|
|
||||||
|
diff --git a/iconv/loop.c b/iconv/loop.c
|
||||||
|
index 199fb283266fb9ca..7149cec9b215a918 100644
|
||||||
|
--- a/iconv/loop.c
|
||||||
|
+++ b/iconv/loop.c
|
||||||
|
@@ -141,12 +141,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. */ \
|
||||||
|
@@ -157,6 +158,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 ca4dbd4a3a3318fe..f3a03ac062a70b05 100644
|
||||||
|
--- a/iconv/tst-iconv_prog.sh
|
||||||
|
+++ b/iconv/tst-iconv_prog.sh
|
||||||
|
@@ -211,12 +211,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
|
||||||
|
@@ -264,7 +265,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"
|
||||||
|
@@ -277,11 +278,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
|
218
glibc-RHEL-71530-2.patch
Normal file
218
glibc-RHEL-71530-2.patch
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
commit 422ed8ede312f786369e4850e47b8d32beaae4e4
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Sep 20 13:10:54 2024 +0200
|
||||||
|
|
||||||
|
iconv: Base tests for buffer management
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/Makefile b/iconv/Makefile
|
||||||
|
index 65b4a44ab86cf0dc..b0fa550141db5a06 100644
|
||||||
|
--- a/iconv/Makefile
|
||||||
|
+++ b/iconv/Makefile
|
||||||
|
@@ -76,8 +76,11 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
||||||
|
|
||||||
|
ifeq ($(run-built-tests),yes)
|
||||||
|
xtests-special += $(objpfx)test-iconvconfig.out
|
||||||
|
-tests-special += $(objpfx)tst-iconv_prog.out
|
||||||
|
-tests-special += $(objpfx)tst-translit-mchar.out
|
||||||
|
+tests-special += \
|
||||||
|
+ $(objpfx)tst-iconv_prog-buffer.out \
|
||||||
|
+ $(objpfx)tst-iconv_prog.out \
|
||||||
|
+ $(objpfx)tst-translit-mchar.out \
|
||||||
|
+ # tests-special
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Make a copy of the file because gconv module names are constructed
|
||||||
|
@@ -141,3 +144,8 @@ $(objpfx)tst-translit-mchar.out: tst-translit-mchar.sh \
|
||||||
|
'$(run-program-env)' '$(run-program-prefix-after-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 0000000000000000..a27107f02b95cdc7
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
@@ -0,0 +1,177 @@
|
||||||
|
+#!/bin/bash
|
||||||
|
+# Test for iconv (the program) buffer management.
|
||||||
|
+# Copyright (C) 2024 Free Software Foundation, Inc.
|
||||||
|
+# This file is part of the GNU C Library.
|
||||||
|
+
|
||||||
|
+# The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
+# modify it under the terms of the GNU Lesser General Public
|
||||||
|
+# License as published by the Free Software Foundation; either
|
||||||
|
+# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
+
|
||||||
|
+# The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
+# Lesser General Public License for more details.
|
||||||
|
+
|
||||||
|
+# You should have received a copy of the GNU Lesser General Public
|
||||||
|
+# License along with the GNU C Library; if not, see
|
||||||
|
+# <https://www.gnu.org/licenses/>.
|
||||||
|
+
|
||||||
|
+exec 2>&1
|
||||||
|
+set -e
|
||||||
|
+
|
||||||
|
+exec {logfd}>&1
|
||||||
|
+
|
||||||
|
+codir=$1
|
||||||
|
+test_program_prefix="$2"
|
||||||
|
+
|
||||||
|
+# Use internal converters to avoid issues with module loading.
|
||||||
|
+iconv_args="-f ASCII -t UTF-8"
|
||||||
|
+
|
||||||
|
+failure=false
|
||||||
|
+
|
||||||
|
+tmp=`mktemp -d`
|
||||||
|
+trap 'rm -rf "$tmp"' 0
|
||||||
|
+echo ABC > "$tmp/abc"
|
||||||
|
+echo DEF > "$tmp/def"
|
||||||
|
+echo GGG > "$tmp/ggg"
|
||||||
|
+echo HH > "$tmp/hh"
|
||||||
|
+echo XY > "$tmp/xy"
|
||||||
|
+echo ZT > "$tmp/zt"
|
||||||
|
+echo OUT > "$tmp/out-template"
|
||||||
|
+printf '\xff' > "$tmp/0xff"
|
||||||
|
+cat "$tmp/xy" "$tmp/0xff" "$tmp/zt" > "$tmp/0xff-wrapped"
|
||||||
|
+
|
||||||
|
+run_iconv () {
|
||||||
|
+ local c=0
|
||||||
|
+ if test "${FUNCNAME[2]}" = main; then
|
||||||
|
+ c=1
|
||||||
|
+ fi
|
||||||
|
+ echo "${BASH_SOURCE[$c]}:${BASH_LINENO[$c]}: iconv $iconv_args $@" >&$logfd
|
||||||
|
+ $test_program_prefix $codir/iconv/iconv_prog $iconv_args "$@"
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+check_out_expected () {
|
||||||
|
+ if ! cmp -s "$tmp/out" "$tmp/expected" ; then
|
||||||
|
+ echo "error: iconv output difference" >&$logfd
|
||||||
|
+ echo "*** expected ***" >&$logfd
|
||||||
|
+ cat "$tmp/expected" >&$logfd
|
||||||
|
+ echo "*** actual ***" >&$logfd
|
||||||
|
+ cat "$tmp/out" >&$logfd
|
||||||
|
+ failure=true
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+expect_files () {
|
||||||
|
+ local f
|
||||||
|
+ ! test -z "$1"
|
||||||
|
+ cp "$tmp/$1" "$tmp/expected"
|
||||||
|
+ shift
|
||||||
|
+ for f in "$@" ; do
|
||||||
|
+ cat "$tmp/$f" >> "$tmp/expected"
|
||||||
|
+ done
|
||||||
|
+ check_out_expected
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+check_out () {
|
||||||
|
+ cat > "$tmp/expected"
|
||||||
|
+ check_out_expected
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+expect_exit () {
|
||||||
|
+ local expected=$1
|
||||||
|
+ shift
|
||||||
|
+ # Prevent failure for stopping the script.
|
||||||
|
+ if "$@" ; then
|
||||||
|
+ actual=$?
|
||||||
|
+ else
|
||||||
|
+ actual=$?
|
||||||
|
+ fi
|
||||||
|
+ if test "$actual" -ne "$expected"; then
|
||||||
|
+ echo "error: expected exit status $expected, not $actual" >&$logfd
|
||||||
|
+ exit 1
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+ignore_failure () {
|
||||||
|
+ set +e
|
||||||
|
+ "$@"
|
||||||
|
+ status=$?
|
||||||
|
+ set -e
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+# Concatentation test.
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/def"
|
||||||
|
+expect_files abc def
|
||||||
|
+
|
||||||
|
+# Single-file in-place conversion.
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/out"
|
||||||
|
+expect_files abc def
|
||||||
|
+
|
||||||
|
+# Multiple input files with in-place conversion.
|
||||||
|
+
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/out" "$tmp/abc"
|
||||||
|
+expect_files abc def abc
|
||||||
|
+
|
||||||
|
+# But not if we are writing to standard output.
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv </dev/null >>"$tmp/out"
|
||||||
|
+expect_files out-template
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv - </dev/null >>"$tmp/out"
|
||||||
|
+expect_files out-template
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv /dev/null >>"$tmp/out"
|
||||||
|
+expect_files out-template
|
||||||
|
+
|
||||||
|
+# Conversion errors should avoid clobbering an existing file if
|
||||||
|
+# it is also an input file.
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/out"
|
||||||
|
+expect_files 0xff
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" < "$tmp/out"
|
||||||
|
+expect_files 0xff
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" - < "$tmp/out"
|
||||||
|
+expect_files 0xff
|
||||||
|
+
|
||||||
|
+# If errors are ignored, the file should be overwritten.
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+expect_exit 1 \
|
||||||
|
+ run_iconv -c -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def" 2>"$tmp/err"
|
||||||
|
+! test -s "$tmp/err"
|
||||||
|
+expect_files abc def
|
||||||
|
+
|
||||||
|
+# FIXME: This is not correct, -c should not change the exit status.
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv -c -o "$tmp/out" \
|
||||||
|
+ "$tmp/abc" "$tmp/0xff-wrapped" "$tmp/def" 2>"$tmp/err"
|
||||||
|
+! test -s "$tmp/err"
|
||||||
|
+expect_files abc xy zt def
|
||||||
|
+
|
||||||
|
+# If the file does not exist yet, it should not be created on error.
|
||||||
|
+
|
||||||
|
+rm "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/0xff"
|
||||||
|
+! test -e "$tmp/out"
|
||||||
|
+
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" < "$tmp/0xff"
|
||||||
|
+! test -e "$tmp/out"
|
||||||
|
+
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def"
|
||||||
|
+! test -e "$tmp/out"
|
||||||
|
+
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/0xff" "$tmp/def"
|
||||||
|
+! test -e "$tmp/out"
|
||||||
|
+
|
||||||
|
+if $failure ; then
|
||||||
|
+ exit 1
|
||||||
|
+fi
|
91
glibc-RHEL-71530-3.patch
Normal file
91
glibc-RHEL-71530-3.patch
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
commit 0cb64617a6f691b611406427c8e24b7f04c4983f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Sep 20 13:10:54 2024 +0200
|
||||||
|
|
||||||
|
iconv: Do not use mmap in iconv (the program) (bug 17703)
|
||||||
|
|
||||||
|
On current systems, very large files are needed before
|
||||||
|
mmap becomes beneficial. Simplify the implementation.
|
||||||
|
|
||||||
|
This exposed that inptr was not initialized correctly in
|
||||||
|
process_fd. Handling multiple input files resulted in
|
||||||
|
EFAULT in read because a null pointer was passed. This
|
||||||
|
could be observed previously if an input file was not
|
||||||
|
mappable and was reported as bug 17703.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
|
||||||
|
index a765b1af21d2bde0..88a928557e7afb0a 100644
|
||||||
|
--- a/iconv/iconv_prog.c
|
||||||
|
+++ b/iconv/iconv_prog.c
|
||||||
|
@@ -31,9 +31,6 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libintl.h>
|
||||||
|
-#ifdef _POSIX_MAPPED_FILES
|
||||||
|
-# include <sys/mman.h>
|
||||||
|
-#endif
|
||||||
|
#include <charmap.h>
|
||||||
|
#include <gconv_int.h>
|
||||||
|
#include "iconv_prog.h"
|
||||||
|
@@ -253,10 +250,6 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
else
|
||||||
|
do
|
||||||
|
{
|
||||||
|
-#ifdef _POSIX_MAPPED_FILES
|
||||||
|
- struct stat64 st;
|
||||||
|
- char *addr;
|
||||||
|
-#endif
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
@@ -276,39 +269,6 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifdef _POSIX_MAPPED_FILES
|
||||||
|
- /* We have possibilities for reading the input file. First try
|
||||||
|
- to mmap() it since this will provide the fastest solution. */
|
||||||
|
- if (fstat64 (fd, &st) == 0
|
||||||
|
- && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
|
||||||
|
- fd, 0)) != MAP_FAILED))
|
||||||
|
- {
|
||||||
|
- /* Yes, we can use mmap(). The descriptor is not needed
|
||||||
|
- anymore. */
|
||||||
|
- if (close (fd) != 0)
|
||||||
|
- error (EXIT_FAILURE, errno,
|
||||||
|
- _("error while closing input `%s'"),
|
||||||
|
- argv[remaining]);
|
||||||
|
-
|
||||||
|
- ret = process_block (cd, addr, st.st_size, &output,
|
||||||
|
- output_file);
|
||||||
|
-
|
||||||
|
- /* We don't need the input data anymore. */
|
||||||
|
- munmap ((void *) addr, st.st_size);
|
||||||
|
-
|
||||||
|
- if (ret != 0)
|
||||||
|
- {
|
||||||
|
- status = EXIT_FAILURE;
|
||||||
|
-
|
||||||
|
- if (ret < 0)
|
||||||
|
- /* We cannot go on with producing output since it might
|
||||||
|
- lead to problem because the last output might leave
|
||||||
|
- the output stream in an undefined state. */
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
-#endif /* _POSIX_MAPPED_FILES */
|
||||||
|
{
|
||||||
|
/* Read the file in pieces. */
|
||||||
|
ret = process_fd (cd, fd, &output, output_file);
|
||||||
|
@@ -544,7 +504,7 @@ process_fd (iconv_t cd, int fd, FILE **output, const char *output_file)
|
||||||
|
process it in one step. */
|
||||||
|
static char *inbuf = NULL;
|
||||||
|
static size_t maxlen = 0;
|
||||||
|
- char *inptr = NULL;
|
||||||
|
+ char *inptr = inbuf;
|
||||||
|
size_t actlen = 0;
|
||||||
|
|
||||||
|
while (actlen < maxlen)
|
62
glibc-RHEL-71530-4.patch
Normal file
62
glibc-RHEL-71530-4.patch
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
commit 00ba299787c2ea9e5c4986301e2f4965dffbfded
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Sep 20 13:10:54 2024 +0200
|
||||||
|
|
||||||
|
manual: __is_last is no longer part of iconv internals
|
||||||
|
|
||||||
|
The __is_last field was replaced with a bitmask in
|
||||||
|
commit 85830c4c4688b30d3d76111aa9a26745c7b141d6 in 2000,
|
||||||
|
and multiple bits are in use today.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/charset.texi b/manual/charset.texi
|
||||||
|
index 427db3bc804f6244..3aaa62d088570f76 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.} */
|
1081
glibc-RHEL-71530-5.patch
Normal file
1081
glibc-RHEL-71530-5.patch
Normal file
File diff suppressed because it is too large
Load Diff
713
glibc-RHEL-71530-6.patch
Normal file
713
glibc-RHEL-71530-6.patch
Normal file
@ -0,0 +1,713 @@
|
|||||||
|
commit 8ef3cff9d1ceafe369f982d980678d749fb93bd2
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Sep 20 13:10:54 2024 +0200
|
||||||
|
|
||||||
|
iconv: Support in-place conversions (bug 10460, bug 32033)
|
||||||
|
|
||||||
|
Check if any of the input files overlaps with the output file, and use
|
||||||
|
a temporary file in this case, so that the input is no clobbered
|
||||||
|
before it is read. This fixes bug 10460. It allows to use iconv
|
||||||
|
more easily as a functional replacement for GNU recode.
|
||||||
|
|
||||||
|
The updated output buffer management truncates the output file
|
||||||
|
if there is no input, fixing bug 32033.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/Makefile b/iconv/Makefile
|
||||||
|
index 29e4f280ec4cdcbf..c9af0c4d44cae7fb 100644
|
||||||
|
--- a/iconv/Makefile
|
||||||
|
+++ b/iconv/Makefile
|
||||||
|
@@ -81,6 +81,8 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
||||||
|
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 \
|
||||||
|
$(objpfx)tst-translit-mchar.out \
|
||||||
|
@@ -153,3 +155,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 --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
|
||||||
|
index 5fe4fe7a6c3776f4..3e02db7319185d45 100644
|
||||||
|
--- a/iconv/iconv_prog.c
|
||||||
|
+++ b/iconv/iconv_prog.c
|
||||||
|
@@ -47,7 +47,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. */
|
||||||
|
@@ -63,6 +67,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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -100,13 +108,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);
|
||||||
|
|
||||||
|
|
||||||
|
@@ -114,7 +129,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;
|
||||||
|
@@ -126,7 +140,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)
|
||||||
|
@@ -161,7 +175,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;
|
||||||
|
@@ -235,16 +250,14 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
_("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
|
||||||
|
@@ -253,17 +266,17 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@@ -271,7 +284,7 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Read the file in pieces. */
|
||||||
|
- ret = process_fd (cd, fd, &output, output_file);
|
||||||
|
+ ret = process_fd (cd, fd);
|
||||||
|
|
||||||
|
/* Now close the file. */
|
||||||
|
close (fd);
|
||||||
|
@@ -289,7 +302,7 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- 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. */
|
||||||
|
@@ -297,8 +310,7 @@ conversions from `%s' and to `%s' are not supported"),
|
||||||
|
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;
|
||||||
|
@@ -328,6 +340,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||||
|
/* 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;
|
||||||
|
@@ -374,59 +394,247 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
- /* Determine output file. */
|
||||||
|
- 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
|
||||||
|
+ {
|
||||||
|
+ /* 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;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+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);
|
||||||
|
|
||||||
|
- errno = errno_save;
|
||||||
|
+ /* No longer using a temporary file from now on. */
|
||||||
|
+ output_using_temporary_file = false;
|
||||||
|
+ output_buffer_size = copy_buffer_size;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- return 0;
|
||||||
|
+ 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)
|
||||||
|
{
|
||||||
|
@@ -437,39 +645,34 @@ process_block (iconv_t cd, char *addr, size_t len, FILE **output,
|
||||||
|
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)
|
||||||
|
@@ -500,7 +703,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)
|
||||||
|
+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
|
||||||
|
@@ -574,16 +777,16 @@ process_fd (iconv_t cd, int fd, FILE **output, const char *output_file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 --git a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
index 5ff99a02a30370cb..54ff871d32929997 100644
|
||||||
|
--- a/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
+++ b/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
@@ -17,6 +17,12 @@
|
||||||
|
# License along with the GNU C Library; if not, see
|
||||||
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
+# Arguments:
|
||||||
|
+# root of the build tree ($(objpfx-common))
|
||||||
|
+# test command wrapper (for running on the board/with new ld.so)
|
||||||
|
+# extra flags to pass to iconv
|
||||||
|
+# number of times to double the input files in size (default: 0)
|
||||||
|
+
|
||||||
|
exec 2>&1
|
||||||
|
set -e
|
||||||
|
|
||||||
|
@@ -26,7 +32,9 @@ codir=$1
|
||||||
|
test_program_prefix="$2"
|
||||||
|
|
||||||
|
# Use internal converters to avoid issues with module loading.
|
||||||
|
-iconv_args="-f ASCII -t UTF-8"
|
||||||
|
+iconv_args="-f ASCII -t UTF-8 $3"
|
||||||
|
+
|
||||||
|
+file_size_doublings=${4-0}
|
||||||
|
|
||||||
|
failure=false
|
||||||
|
|
||||||
|
@@ -39,7 +47,19 @@ echo HH > "$tmp/hh"
|
||||||
|
echo XY > "$tmp/xy"
|
||||||
|
echo ZT > "$tmp/zt"
|
||||||
|
echo OUT > "$tmp/out-template"
|
||||||
|
+: > "$tmp/empty"
|
||||||
|
printf '\xff' > "$tmp/0xff"
|
||||||
|
+
|
||||||
|
+# Double all files to produce larger buffers.
|
||||||
|
+for p in "$tmp"/* ; do
|
||||||
|
+ i=0
|
||||||
|
+ while test $i -lt $file_size_doublings; do
|
||||||
|
+ cat "$p" "$p" > "$tmp/scratch"
|
||||||
|
+ mv "$tmp/scratch" "$p"
|
||||||
|
+ i=$(($i + 1))
|
||||||
|
+ done
|
||||||
|
+done
|
||||||
|
+
|
||||||
|
cat "$tmp/xy" "$tmp/0xff" "$tmp/zt" > "$tmp/0xff-wrapped"
|
||||||
|
|
||||||
|
run_iconv () {
|
||||||
|
@@ -113,6 +133,38 @@ expect_files abc def
|
||||||
|
run_iconv -o "$tmp/out" "$tmp/out" "$tmp/abc"
|
||||||
|
expect_files abc def abc
|
||||||
|
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/ggg" "$tmp/out"
|
||||||
|
+expect_files ggg abc def abc
|
||||||
|
+
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/hh" "$tmp/out" "$tmp/hh"
|
||||||
|
+expect_files hh ggg abc def abc hh
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/ggg" "$tmp/out" "$tmp/out" "$tmp/ggg"
|
||||||
|
+expect_files ggg out-template out-template ggg
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv -o "$tmp/out" "$tmp/ggg" "$tmp/out" "$tmp/hh" "$tmp/out" "$tmp/ggg"
|
||||||
|
+expect_files ggg out-template hh out-template ggg
|
||||||
|
+
|
||||||
|
+# Empty output should truncate the output file if exists.
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv -o "$tmp/out" </dev/null
|
||||||
|
+expect_files empty
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv -o "$tmp/out" - </dev/null
|
||||||
|
+expect_files empty
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+run_iconv -o "$tmp/out" /dev/null
|
||||||
|
+expect_files empty
|
||||||
|
+
|
||||||
|
+cp "$tmp/out-template" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/0xff"
|
||||||
|
+expect_files empty
|
||||||
|
+
|
||||||
|
# But not if we are writing to standard output.
|
||||||
|
|
||||||
|
cp "$tmp/out-template" "$tmp/out"
|
||||||
|
@@ -142,8 +194,36 @@ cp "$tmp/0xff" "$tmp/out"
|
||||||
|
expect_exit 1 run_iconv -o "$tmp/out" - < "$tmp/out"
|
||||||
|
expect_files 0xff
|
||||||
|
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/out"
|
||||||
|
+expect_files 0xff-wrapped
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" < "$tmp/out"
|
||||||
|
+expect_files 0xff-wrapped
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" - < "$tmp/out"
|
||||||
|
+expect_files 0xff-wrapped
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" "$tmp/out"
|
||||||
|
+expect_files 0xff-wrapped
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/out"
|
||||||
|
+expect_files 0xff-wrapped
|
||||||
|
+
|
||||||
|
# If errors are ignored, the file should be overwritten.
|
||||||
|
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/out"
|
||||||
|
+expect_files xy zt
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/abc" "$tmp/out" "$tmp/def"
|
||||||
|
+expect_files abc def
|
||||||
|
+
|
||||||
|
cp "$tmp/out-template" "$tmp/out"
|
||||||
|
expect_exit 1 \
|
||||||
|
run_iconv -c -o "$tmp/out" "$tmp/abc" "$tmp/0xff" "$tmp/def" 2>"$tmp/err"
|
||||||
|
@@ -156,6 +236,20 @@ expect_exit 1 run_iconv -c -o "$tmp/out" \
|
||||||
|
! test -s "$tmp/err"
|
||||||
|
expect_files abc xy zt def
|
||||||
|
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -c -o "$tmp/out" "$tmp/out" "$tmp/abc" "$tmp/out" "$tmp/def"
|
||||||
|
+expect_files xy zt abc xy zt def
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" \
|
||||||
|
+ "$tmp/out" "$tmp/abc" "$tmp/out" "$tmp/def"
|
||||||
|
+expect_files 0xff-wrapped
|
||||||
|
+
|
||||||
|
+cp "$tmp/0xff-wrapped" "$tmp/out"
|
||||||
|
+expect_exit 1 run_iconv -c -o "$tmp/out" \
|
||||||
|
+ "$tmp/abc" "$tmp/out" "$tmp/def" "$tmp/out"
|
||||||
|
+expect_files abc xy zt def xy zt
|
||||||
|
+
|
||||||
|
# If the file does not exist yet, it should not be created on error.
|
||||||
|
|
||||||
|
rm "$tmp/out"
|
41
glibc-RHEL-71530-7.patch
Normal file
41
glibc-RHEL-71530-7.patch
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
commit 75819cdd29a193cc2db980878bec305905b22bbc
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Sep 20 13:10:54 2024 +0200
|
||||||
|
|
||||||
|
iconv: Multiple - on command line should not fail (bug 32050)
|
||||||
|
|
||||||
|
Usually, the second and subsequent - return EOF immediately
|
||||||
|
and do not contribute to the output, but this is not an error.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
|
||||||
|
index 3e02db7319185d45..dd4bc3a59a20799a 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 54ff871d32929997..a9c3729d948b4679 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
|
323
glibc-RHEL-71530-8.patch
Normal file
323
glibc-RHEL-71530-8.patch
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
commit fa1b0d5e9f6e0353e16339430770a7a8824c0468
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Sep 20 13:10:54 2024 +0200
|
||||||
|
|
||||||
|
iconv: Input buffering for the iconv program (bug 6050)
|
||||||
|
|
||||||
|
Do not read the entire input file into memory.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
|
||||||
|
index dd4bc3a59a20799a..a2f1d34e4579f80f 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 a9c3729d948b4679..23098ac56a344c48 100644
|
||||||
|
--- a/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
+++ b/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
@@ -50,6 +50,9 @@ echo OUT > "$tmp/out-template"
|
||||||
|
: > "$tmp/empty"
|
||||||
|
printf '\xff' > "$tmp/0xff"
|
||||||
|
|
||||||
|
+# Length should be a prime number, to help with buffer alignment testing.
|
||||||
|
+printf '\xc3\xa4\xe2\x80\x94\xe2\x80\x94\xc3\xa4\n' > "$tmp/utf8-sequence"
|
||||||
|
+
|
||||||
|
# Double all files to produce larger buffers.
|
||||||
|
for p in "$tmp"/* ; do
|
||||||
|
i=0
|
||||||
|
@@ -270,6 +273,34 @@ expect_exit 1 run_iconv -o "$tmp/out" "$tmp/abc" - < "$tmp/0xff" "$tmp/def"
|
||||||
|
run_iconv -o "$tmp/out" "$tmp/xy" - - "$tmp/zt" < "$tmp/abc"
|
||||||
|
expect_files xy abc zt
|
||||||
|
|
||||||
|
+# NB: Extra iconv args are ignored after this point. Actual
|
||||||
|
+# multi-byte conversion does not work with tiny buffers.
|
||||||
|
+iconv_args="-f UTF-8 -t ASCII"
|
||||||
|
+
|
||||||
|
+printf 'x\n\xc3' > "$tmp/incomplete"
|
||||||
|
+expect_exit 1 run_iconv -o "$tmp/out" "$tmp/incomplete"
|
||||||
|
+check_out <<EOF
|
||||||
|
+x
|
||||||
|
+EOF
|
||||||
|
+
|
||||||
|
+# Test buffering behavior if the buffer ends with an incomplete
|
||||||
|
+# multi-byte sequence.
|
||||||
|
+prefix=""
|
||||||
|
+prefix_length=0
|
||||||
|
+while test $prefix_length -lt 12; do
|
||||||
|
+ echo "info: testing prefix length $prefix_length" 2>&$logfd
|
||||||
|
+ printf "%s" "$prefix" > "$tmp/prefix"
|
||||||
|
+ cat "$tmp/prefix" "$tmp/utf8-sequence" > "$tmp/tmp"
|
||||||
|
+ iconv_args="-f UTF-8 -t UCS-4"
|
||||||
|
+ run_iconv -o "$tmp/out1" "$tmp/tmp"
|
||||||
|
+ iconv_args="-f UCS-4 -t UTF-8"
|
||||||
|
+ run_iconv -o "$tmp/out" "$tmp/out1"
|
||||||
|
+ expect_files prefix utf8-sequence
|
||||||
|
+
|
||||||
|
+ prefix="$prefix@"
|
||||||
|
+ prefix_length=$(($prefix_length + 1))
|
||||||
|
+done
|
||||||
|
+
|
||||||
|
if $failure ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
37
glibc-RHEL-71530-9.patch
Normal file
37
glibc-RHEL-71530-9.patch
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
commit 079ebf7624e7fd0ad7fe94a7176a2e132c996d86
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Sep 24 10:41:35 2024 +0200
|
||||||
|
|
||||||
|
iconv: Use $(run-program-prefix) for running iconv (bug 32197)
|
||||||
|
|
||||||
|
With --enable-hardcoded-path-in-tests, $(test-program-prefix)
|
||||||
|
does not redirect to the built glibc, but we need to run
|
||||||
|
iconv (the program) against the built glibc even with
|
||||||
|
--enable-hardcoded-path-in-tests, as it is using the ABI
|
||||||
|
path for the dynamic linker (as an installed program).
|
||||||
|
Use $(run-program-prefix) instead.
|
||||||
|
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/Makefile b/iconv/Makefile
|
||||||
|
index c9af0c4d44cae7fb..de9d964ed3c762bf 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)
|
115
glibc-RHEL-75555.patch
Normal file
115
glibc-RHEL-75555.patch
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
commit abeae3c0061c0599ac2f012b270d6b4c8f59c82f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Thu Jan 16 18:45:25 2025 +0100
|
||||||
|
|
||||||
|
Linux: Fixes for getrandom fork handling
|
||||||
|
|
||||||
|
Careful updates of grnd_alloc.len are required to ensure that
|
||||||
|
after fork, grnd_alloc.states does not contain entries that
|
||||||
|
are also encountered by __getrandom_reset_state in TCBs.
|
||||||
|
For the same reason, it is necessary to overwrite the TCB state
|
||||||
|
pointer with NULL before updating grnd_alloc.states in
|
||||||
|
__getrandom_vdso_release.
|
||||||
|
|
||||||
|
Before this change, different TCBs could share the same getrandom
|
||||||
|
state after multi-threaded fork. This would be a critical security
|
||||||
|
bug (predictable randomness) if not caught during development.
|
||||||
|
|
||||||
|
The additional check in stdlib/tst-arc4random-thread makes it more
|
||||||
|
likely that the test fails due to the bugs mentioned above.
|
||||||
|
|
||||||
|
Both __getrandom_reset_state and __getrandom_vdso_release could
|
||||||
|
put reserved NULL pointers into the states array. This is also
|
||||||
|
fixed with this commit. After these changes, no null pointers were
|
||||||
|
observed in the states array during testing.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/tst-arc4random-thread.c b/stdlib/tst-arc4random-thread.c
|
||||||
|
index d1259626c62af5ad..5e8a4761fc39165a 100644
|
||||||
|
--- a/stdlib/tst-arc4random-thread.c
|
||||||
|
+++ b/stdlib/tst-arc4random-thread.c
|
||||||
|
@@ -49,7 +49,7 @@ static const int sizes[] = { 12, 15, 16, 17, 24, 31, max_size };
|
||||||
|
struct blob
|
||||||
|
{
|
||||||
|
unsigned int size;
|
||||||
|
- int thread_id;
|
||||||
|
+ int thread_id; /* -1 means after fork. */
|
||||||
|
unsigned int index;
|
||||||
|
unsigned char bytes[max_size];
|
||||||
|
};
|
||||||
|
@@ -323,6 +323,20 @@ do_test_func (const char *fname, void (*func)(unsigned char *, size_t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ for (struct blob *p = dynarray_blob_begin (&global_result);
|
||||||
|
+ p < end; ++p)
|
||||||
|
+ {
|
||||||
|
+ unsigned int sum = 0;
|
||||||
|
+ for (unsigned int i = 0; i < p->size; ++i)
|
||||||
|
+ sum += p->bytes[i];
|
||||||
|
+ if (sum == 0)
|
||||||
|
+ {
|
||||||
|
+ support_record_failure ();
|
||||||
|
+ printf ("error: all-zero result of length %u on thread %d\n",
|
||||||
|
+ p->size, p->thread_id);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
dynarray_blob_free (&global_result);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
|
||||||
|
index d3eab66a1af6229e..d93901f6ea5cbc6b 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/getrandom.c
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/getrandom.c
|
||||||
|
@@ -168,6 +168,11 @@ vgetrandom_get_state (void)
|
||||||
|
if (grnd_alloc.len > 0 || vgetrandom_get_state_alloc ())
|
||||||
|
state = grnd_alloc.states[--grnd_alloc.len];
|
||||||
|
|
||||||
|
+ /* Barrier needed by fork: The state must be gone from the array
|
||||||
|
+ through len update before it becomes visible in the TCB. (There
|
||||||
|
+ is also a release barrier implied by the unlock, but issue a
|
||||||
|
+ stronger barrier to help fork.) */
|
||||||
|
+ atomic_thread_fence_seq_cst ();
|
||||||
|
__libc_lock_unlock (grnd_alloc.lock);
|
||||||
|
internal_signal_restore_set (&set);
|
||||||
|
|
||||||
|
@@ -278,7 +283,10 @@ void
|
||||||
|
__getrandom_reset_state (struct pthread *curp)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||||
|
- if (grnd_alloc.states == NULL || curp->getrandom_buf == NULL)
|
||||||
|
+ /* The pointer can be reserved if the fork happened during a
|
||||||
|
+ getrandom call. */
|
||||||
|
+ void *buf = release_ptr (curp->getrandom_buf);
|
||||||
|
+ if (grnd_alloc.states == NULL || buf == NULL)
|
||||||
|
return;
|
||||||
|
assert (grnd_alloc.len < grnd_alloc.cap);
|
||||||
|
grnd_alloc.states[grnd_alloc.len++] = release_ptr (curp->getrandom_buf);
|
||||||
|
@@ -294,11 +302,23 @@ void
|
||||||
|
__getrandom_vdso_release (struct pthread *curp)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||||
|
- if (curp->getrandom_buf == NULL)
|
||||||
|
+ /* The pointer can be reserved if the thread was canceled in a
|
||||||
|
+ signal handler. */
|
||||||
|
+ void *buf = release_ptr (curp->getrandom_buf);
|
||||||
|
+ if (buf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
__libc_lock_lock (grnd_alloc.lock);
|
||||||
|
- grnd_alloc.states[grnd_alloc.len++] = curp->getrandom_buf;
|
||||||
|
+
|
||||||
|
+ size_t len = grnd_alloc.len;
|
||||||
|
+ grnd_alloc.states[len] = curp->getrandom_buf;
|
||||||
|
+ curp->getrandom_buf = NULL;
|
||||||
|
+ /* Barrier needed by fork: The state must vanish from the TCB before
|
||||||
|
+ it becomes visible in the states array. Also avoid exposing the
|
||||||
|
+ previous entry value at the same index in the states array (which
|
||||||
|
+ may be in use by another thread). */
|
||||||
|
+ atomic_thread_fence_seq_cst ();
|
||||||
|
+ grnd_alloc.len = len + 1;
|
||||||
|
__libc_lock_unlock (grnd_alloc.lock);
|
||||||
|
#endif
|
||||||
|
}
|
232
glibc-RHEL-75809-2.patch
Normal file
232
glibc-RHEL-75809-2.patch
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
commit 36fcdfbbc5463e55581fec67141df3493fb81f7e
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
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 <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/csu/init-first.c b/csu/init-first.c
|
||||||
|
index 77b5b4941beb3a73..a2cb456ccf9ac5e6 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 260027c2396e1f52..d784de0f0bdd70c8 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 ada957f9d04d272a..e241603b8131a9e9 100644
|
||||||
|
--- a/include/unistd.h
|
||||||
|
+++ b/include/unistd.h
|
||||||
|
@@ -203,9 +203,6 @@ libc_hidden_proto (__tcsetpgrp)
|
||||||
|
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 217600ba60e3c7d4..ff1418f5bb2ea5c9 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -312,7 +312,6 @@ tests := \
|
||||||
|
tst-setcontext9 \
|
||||||
|
tst-setcontext10 \
|
||||||
|
tst-setcontext11 \
|
||||||
|
- tst-setenv-malloc \
|
||||||
|
tst-stdbit-Wconversion \
|
||||||
|
tst-stdbit-builtins \
|
||||||
|
tst-stdc_bit_ceil \
|
||||||
|
diff --git a/stdlib/setenv.c b/stdlib/setenv.c
|
||||||
|
index 79982aa12ac20078..d12401ca77cee5a7 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
|
||||||
|
- <https://www.gnu.org/licenses/>. */
|
||||||
|
-
|
||||||
|
-/* 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 <stdlib.h>
|
||||||
|
-#include <unistd.h>
|
||||||
|
-#include <support/check.h>
|
||||||
|
-#include <support/support.h>
|
||||||
|
-
|
||||||
|
-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 <support/test-driver.c>
|
299
glibc-RHEL-75809-3.patch
Normal file
299
glibc-RHEL-75809-3.patch
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
commit 12b4a1fc6ecfc278a87159164bdf1d682deb18e2
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
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 <carlos@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index ff1418f5bb2ea5c9..f4dec9be46a573b9 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -275,6 +275,10 @@ tests := \
|
||||||
|
tst-canon-bz26341 \
|
||||||
|
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 d12401ca77cee5a7..20b0e1673c9557de 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -403,6 +400,7 @@ __libc_setenv_freemem (void)
|
||||||
|
/* 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+/* 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 <stdlib.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+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 <support/test-driver.c>
|
245
glibc-RHEL-75809.patch
Normal file
245
glibc-RHEL-75809.patch
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
commit b62759db04b8ed7f829c06f1d7c3b8fb70616493
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
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 <carlos@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/csu/init-first.c b/csu/init-first.c
|
||||||
|
index a2cb456ccf9ac5e6..77b5b4941beb3a73 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 d784de0f0bdd70c8..260027c2396e1f52 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 e241603b8131a9e9..ada957f9d04d272a 100644
|
||||||
|
--- a/include/unistd.h
|
||||||
|
+++ b/include/unistd.h
|
||||||
|
@@ -203,6 +203,9 @@ libc_hidden_proto (__tcsetpgrp)
|
||||||
|
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 ff1418f5bb2ea5c9..217600ba60e3c7d4 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -312,6 +312,7 @@ tests := \
|
||||||
|
tst-setcontext9 \
|
||||||
|
tst-setcontext10 \
|
||||||
|
tst-setcontext11 \
|
||||||
|
+ tst-setenv-malloc \
|
||||||
|
tst-stdbit-Wconversion \
|
||||||
|
tst-stdbit-builtins \
|
||||||
|
tst-stdc_bit_ceil \
|
||||||
|
diff --git a/stdlib/setenv.c b/stdlib/setenv.c
|
||||||
|
index d12401ca77cee5a7..79982aa12ac20078 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+/* 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 <stdlib.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+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 <support/test-driver.c>
|
55
glibc-upstream-2.39-138.patch
Normal file
55
glibc-upstream-2.39-138.patch
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
commit 9a0e174a39a3a65f628c6a55e29fe35f6d67bf42
|
||||||
|
Author: Michael Jeanson <mjeanson@efficios.com>
|
||||||
|
Date: Thu Nov 7 22:23:49 2024 +0100
|
||||||
|
|
||||||
|
nptl: initialize rseq area prior to registration
|
||||||
|
|
||||||
|
Per the rseq syscall documentation, 3 fields are required to be
|
||||||
|
initialized by userspace prior to registration, they are 'cpu_id',
|
||||||
|
'rseq_cs' and 'flags'. Since we have no guarantee that 'struct pthread'
|
||||||
|
is cleared on all architectures, explicitly set those 3 fields prior to
|
||||||
|
registration.
|
||||||
|
|
||||||
|
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
(cherry picked from commit 97f60abd25628425971f07e9b0e7f8eec0741235)
|
||||||
|
|
||||||
|
diff --git a/nptl/descr.h b/nptl/descr.h
|
||||||
|
index 4697f633e16c7359..a83df327e4bcba2e 100644
|
||||||
|
--- a/nptl/descr.h
|
||||||
|
+++ b/nptl/descr.h
|
||||||
|
@@ -417,6 +417,8 @@ struct pthread
|
||||||
|
{
|
||||||
|
uint32_t cpu_id_start;
|
||||||
|
uint32_t cpu_id;
|
||||||
|
+ uint64_t rseq_cs;
|
||||||
|
+ uint32_t flags;
|
||||||
|
};
|
||||||
|
char pad[32]; /* Original rseq area size. */
|
||||||
|
} rseq_area __attribute__ ((aligned (32)));
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h
|
||||||
|
index 7ea935b4adab8c20..37a8f630b6519ff0 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/rseq-internal.h
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/rseq-internal.h
|
||||||
|
@@ -51,11 +51,21 @@ rseq_register_current_thread (struct pthread *self, bool do_rseq)
|
||||||
|
/* The initial implementation used only 20 bytes out of 32,
|
||||||
|
but still expected size 32. */
|
||||||
|
size = RSEQ_AREA_SIZE_INITIAL;
|
||||||
|
+
|
||||||
|
+ /* Initialize the rseq fields that are read by the kernel on
|
||||||
|
+ registration, there is no guarantee that struct pthread is
|
||||||
|
+ cleared on all architectures. */
|
||||||
|
+ THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_UNINITIALIZED);
|
||||||
|
+ THREAD_SETMEM (self, rseq_area.rseq_cs, 0);
|
||||||
|
+ THREAD_SETMEM (self, rseq_area.flags, 0);
|
||||||
|
+
|
||||||
|
int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area,
|
||||||
|
size, 0, RSEQ_SIG);
|
||||||
|
if (!INTERNAL_SYSCALL_ERROR_P (ret))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
+ /* When rseq is disabled by tunables or the registration fails, inform
|
||||||
|
+ userspace by setting 'cpu_id' to RSEQ_CPU_ID_REGISTRATION_FAILED. */
|
||||||
|
THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED);
|
||||||
|
return false;
|
||||||
|
}
|
29
glibc-upstream-2.39-139.patch
Normal file
29
glibc-upstream-2.39-139.patch
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
commit 350db2839387659e1500a54d276e401c9c6b2dee
|
||||||
|
Author: Michael Jeanson <mjeanson@efficios.com>
|
||||||
|
Date: Wed Nov 20 14:15:42 2024 -0500
|
||||||
|
|
||||||
|
nptl: initialize cpu_id_start prior to rseq registration
|
||||||
|
|
||||||
|
When adding explicit initialization of rseq fields prior to
|
||||||
|
registration, I glossed over the fact that 'cpu_id_start' is also
|
||||||
|
documented as initialized by user-space.
|
||||||
|
|
||||||
|
While current kernels don't validate the content of this field on
|
||||||
|
registration, future ones could.
|
||||||
|
|
||||||
|
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
|
||||||
|
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||||||
|
(cherry picked from commit d9f40387d3305d97e30a8cf8724218c42a63680a)
|
||||||
|
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h
|
||||||
|
index 37a8f630b6519ff0..ef3eab1fefd4d90d 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/rseq-internal.h
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/rseq-internal.h
|
||||||
|
@@ -56,6 +56,7 @@ rseq_register_current_thread (struct pthread *self, bool do_rseq)
|
||||||
|
registration, there is no guarantee that struct pthread is
|
||||||
|
cleared on all architectures. */
|
||||||
|
THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_UNINITIALIZED);
|
||||||
|
+ THREAD_SETMEM (self, rseq_area.cpu_id_start, 0);
|
||||||
|
THREAD_SETMEM (self, rseq_area.rseq_cs, 0);
|
||||||
|
THREAD_SETMEM (self, rseq_area.flags, 0);
|
||||||
|
|
28
glibc-upstream-2.39-140.patch
Normal file
28
glibc-upstream-2.39-140.patch
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
commit aa8768999e94fcee1695feb766c69dd8a93b706b
|
||||||
|
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
Date: Fri May 17 20:00:38 2024 -0700
|
||||||
|
|
||||||
|
Pass -nostdlib -nostartfiles together with -r [BZ #31753]
|
||||||
|
|
||||||
|
Since -r in GCC 6/7/8 doesn't imply -nostdlib -nostartfiles, update the
|
||||||
|
link-static-libc.out rule to also pass -nostdlib -nostartfiles. This
|
||||||
|
fixes BZ #31753.
|
||||||
|
|
||||||
|
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
(cherry picked from commit 2be3352f0b1ebaa39596393fffe1062275186669)
|
||||||
|
|
||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index 37bf70aa4ad4403f..ae9bc09327dd2d5b 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -581,7 +581,8 @@ $(objpfx)lint-makefiles.out: scripts/lint-makefiles.sh
|
||||||
|
# definitions of any symbols.
|
||||||
|
tests-special += $(objpfx)link-static-libc.out
|
||||||
|
$(objpfx)link-static-libc.out:
|
||||||
|
- $(LINK.o) $(whole-archive) -r $(objpfx)libc.a -o /dev/null > $@ 2>&1; \
|
||||||
|
+ $(LINK.o) $(whole-archive) -nostdlib -nostartfiles -r \
|
||||||
|
+ $(objpfx)libc.a -o /dev/null > $@ 2>&1; \
|
||||||
|
$(evaluate-test)
|
||||||
|
|
||||||
|
# Print test summary for tests in $1 .sum file;
|
172
glibc-upstream-2.39-141.patch
Normal file
172
glibc-upstream-2.39-141.patch
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
commit 51da74a97e0f024fd89b57304b3ab010a3cfaef1
|
||||||
|
Author: Sam James <sam@gentoo.org>
|
||||||
|
Date: Mon Dec 9 23:11:25 2024 +0000
|
||||||
|
|
||||||
|
malloc: add indirection for malloc(-like) functions in tests [BZ #32366]
|
||||||
|
|
||||||
|
GCC 15 introduces allocation dead code removal (DCE) for PR117370 in
|
||||||
|
r15-5255-g7828dc070510f8. This breaks various glibc tests which want
|
||||||
|
to assert various properties of the allocator without doing anything
|
||||||
|
obviously useful with the allocated memory.
|
||||||
|
|
||||||
|
Alexander Monakov rightly pointed out that we can and should do better
|
||||||
|
than passing -fno-malloc-dce to paper over the problem. Not least because
|
||||||
|
GCC 14 already does such DCE where there's no testing of malloc's return
|
||||||
|
value against NULL, and LLVM has such optimisations too.
|
||||||
|
|
||||||
|
Handle this by providing malloc (and friends) wrappers with a volatile
|
||||||
|
function pointer to obscure that we're calling malloc (et. al) from the
|
||||||
|
compiler.
|
||||||
|
|
||||||
|
Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
(cherry picked from commit a9944a52c967ce76a5894c30d0274b824df43c7a)
|
||||||
|
|
||||||
|
diff --git a/malloc/tst-aligned-alloc.c b/malloc/tst-aligned-alloc.c
|
||||||
|
index 91167d1392c0e626..b0f05a8fec78d5e8 100644
|
||||||
|
--- a/malloc/tst-aligned-alloc.c
|
||||||
|
+++ b/malloc/tst-aligned-alloc.c
|
||||||
|
@@ -25,6 +25,8 @@
|
||||||
|
#include <libc-diag.h>
|
||||||
|
#include <support/check.h>
|
||||||
|
|
||||||
|
+#include "tst-malloc-aux.h"
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
diff --git a/malloc/tst-compathooks-off.c b/malloc/tst-compathooks-off.c
|
||||||
|
index d0106f3fb74ff3b1..4cce6e5a8076f6b6 100644
|
||||||
|
--- a/malloc/tst-compathooks-off.c
|
||||||
|
+++ b/malloc/tst-compathooks-off.c
|
||||||
|
@@ -25,6 +25,8 @@
|
||||||
|
#include <support/check.h>
|
||||||
|
#include <support/support.h>
|
||||||
|
|
||||||
|
+#include "tst-malloc-aux.h"
|
||||||
|
+
|
||||||
|
extern void (*volatile __free_hook) (void *, const void *);
|
||||||
|
extern void *(*volatile __malloc_hook)(size_t, const void *);
|
||||||
|
extern void *(*volatile __realloc_hook)(void *, size_t, const void *);
|
||||||
|
diff --git a/malloc/tst-malloc-aux.h b/malloc/tst-malloc-aux.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..54908b4a2464d510
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/malloc/tst-malloc-aux.h
|
||||||
|
@@ -0,0 +1,41 @@
|
||||||
|
+/* Wrappers for malloc-like functions to allow testing the implementation
|
||||||
|
+ without optimization.
|
||||||
|
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||||
|
+ This file is part of the GNU C Library.
|
||||||
|
+
|
||||||
|
+ The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
+ modify it under the terms of the GNU Lesser General Public License as
|
||||||
|
+ published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
+ License, or (at your option) any later version.
|
||||||
|
+
|
||||||
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
+ Lesser General Public License for more details.
|
||||||
|
+
|
||||||
|
+ You should have received a copy of the GNU Lesser General Public
|
||||||
|
+ License along with the GNU C Library; see the file COPYING.LIB. If
|
||||||
|
+ not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#ifndef TST_MALLOC_AUX_H
|
||||||
|
+#define TST_MALLOC_AUX_H
|
||||||
|
+
|
||||||
|
+#include <stddef.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+
|
||||||
|
+static void *(*volatile aligned_alloc_indirect)(size_t, size_t) = aligned_alloc;
|
||||||
|
+static void *(*volatile calloc_indirect)(size_t, size_t) = calloc;
|
||||||
|
+static void *(*volatile malloc_indirect)(size_t) = malloc;
|
||||||
|
+static void *(*volatile realloc_indirect)(void*, size_t) = realloc;
|
||||||
|
+
|
||||||
|
+#undef aligned_alloc
|
||||||
|
+#undef calloc
|
||||||
|
+#undef malloc
|
||||||
|
+#undef realloc
|
||||||
|
+
|
||||||
|
+#define aligned_alloc aligned_alloc_indirect
|
||||||
|
+#define calloc calloc_indirect
|
||||||
|
+#define malloc malloc_indirect
|
||||||
|
+#define realloc realloc_indirect
|
||||||
|
+
|
||||||
|
+#endif /* TST_MALLOC_AUX_H */
|
||||||
|
diff --git a/malloc/tst-malloc-check.c b/malloc/tst-malloc-check.c
|
||||||
|
index fde8863ad7561a71..cc88bff3b39a421c 100644
|
||||||
|
--- a/malloc/tst-malloc-check.c
|
||||||
|
+++ b/malloc/tst-malloc-check.c
|
||||||
|
@@ -20,6 +20,8 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <libc-diag.h>
|
||||||
|
|
||||||
|
+#include "tst-malloc-aux.h"
|
||||||
|
+
|
||||||
|
static int errors = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
|
||||||
|
index 8e9e0d5fa2b4b907..2b91377e54cdc485 100644
|
||||||
|
--- a/malloc/tst-malloc-too-large.c
|
||||||
|
+++ b/malloc/tst-malloc-too-large.c
|
||||||
|
@@ -43,6 +43,7 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
+#include "tst-malloc-aux.h"
|
||||||
|
|
||||||
|
/* This function prepares for each 'too-large memory allocation' test by
|
||||||
|
performing a small successful malloc/free and resetting errno prior to
|
||||||
|
diff --git a/malloc/tst-malloc.c b/malloc/tst-malloc.c
|
||||||
|
index f7a6e4654c374d01..68af399022543111 100644
|
||||||
|
--- a/malloc/tst-malloc.c
|
||||||
|
+++ b/malloc/tst-malloc.c
|
||||||
|
@@ -22,6 +22,8 @@
|
||||||
|
#include <libc-diag.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
+#include "tst-malloc-aux.h"
|
||||||
|
+
|
||||||
|
static int errors = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
diff --git a/malloc/tst-realloc.c b/malloc/tst-realloc.c
|
||||||
|
index f50499ecb114d574..74a28fb45ed80bf5 100644
|
||||||
|
--- a/malloc/tst-realloc.c
|
||||||
|
+++ b/malloc/tst-realloc.c
|
||||||
|
@@ -23,6 +23,8 @@
|
||||||
|
#include <libc-diag.h>
|
||||||
|
#include <support/check.h>
|
||||||
|
|
||||||
|
+#include "tst-malloc-aux.h"
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
diff --git a/support/support.h b/support/support.h
|
||||||
|
index ba21ec9b5add7c02..1a77f7979330d60c 100644
|
||||||
|
--- a/support/support.h
|
||||||
|
+++ b/support/support.h
|
||||||
|
@@ -113,7 +113,7 @@ void *xposix_memalign (size_t alignment, size_t n)
|
||||||
|
__attribute_malloc__ __attribute_alloc_align__ ((1))
|
||||||
|
__attribute_alloc_size__ ((2)) __attr_dealloc_free __returns_nonnull;
|
||||||
|
char *xasprintf (const char *format, ...)
|
||||||
|
- __attribute__ ((format (printf, 1, 2), malloc)) __attr_dealloc_free
|
||||||
|
+ __attribute__ ((format (printf, 1, 2), __malloc__)) __attr_dealloc_free
|
||||||
|
__returns_nonnull;
|
||||||
|
char *xstrdup (const char *) __attr_dealloc_free __returns_nonnull;
|
||||||
|
char *xstrndup (const char *, size_t) __attr_dealloc_free __returns_nonnull;
|
||||||
|
diff --git a/test-skeleton.c b/test-skeleton.c
|
||||||
|
index ae185a4f2821de00..690f26e7cf229622 100644
|
||||||
|
--- a/test-skeleton.c
|
||||||
|
+++ b/test-skeleton.c
|
||||||
|
@@ -27,7 +27,6 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
-#include <malloc.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <search.h>
|
||||||
|
#include <signal.h>
|
44
glibc-upstream-2.39-142.patch
Normal file
44
glibc-upstream-2.39-142.patch
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
commit 2c882bf9c15d206aaf04766d1b8e3ae5b1002cc2
|
||||||
|
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
Date: Thu Dec 5 08:39:44 2024 +0800
|
||||||
|
|
||||||
|
math: Exclude internal math symbols for tests [BZ #32414]
|
||||||
|
|
||||||
|
Since internal tests don't have access to internal symbols in libm,
|
||||||
|
exclude them for internal tests. Also make tst-strtod5 and tst-strtod5i
|
||||||
|
depend on $(libm) to support older versions of GCC which can't inline
|
||||||
|
copysign family functions. This fixes BZ #32414.
|
||||||
|
|
||||||
|
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
|
||||||
|
(cherry picked from commit 5df09b444835fca6e64b3d4b4a5beb19b3b2ba21)
|
||||||
|
|
||||||
|
diff --git a/include/math.h b/include/math.h
|
||||||
|
index fa11a710a6c152a4..035fd160ffb9e032 100644
|
||||||
|
--- a/include/math.h
|
||||||
|
+++ b/include/math.h
|
||||||
|
@@ -130,7 +130,10 @@ fabsf128 (_Float128 x)
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
-# if !(defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0)
|
||||||
|
+
|
||||||
|
+/* NB: Internal tests don't have access to internal symbols. */
|
||||||
|
+# if !IS_IN (testsuite_internal) \
|
||||||
|
+ && !(defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0)
|
||||||
|
# ifndef NO_MATH_REDIRECT
|
||||||
|
/* Declare some functions for use within GLIBC. Compilers typically
|
||||||
|
inline those functions as a single instruction. Use an asm to
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index 70d7291c6e3454a8..ff1418f5bb2ea5c9 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -607,6 +607,8 @@ $(objpfx)bug-strtod2: $(libm)
|
||||||
|
$(objpfx)tst-strtod-round: $(libm)
|
||||||
|
$(objpfx)tst-tininess: $(libm)
|
||||||
|
$(objpfx)tst-strtod-underflow: $(libm)
|
||||||
|
+$(objpfx)tst-strtod5: $(libm)
|
||||||
|
+$(objpfx)tst-strtod5i: $(libm)
|
||||||
|
$(objpfx)tst-strtod6: $(libm)
|
||||||
|
$(objpfx)tst-strtod-nan-locale: $(libm)
|
||||||
|
$(objpfx)tst-strtod-nan-sign: $(libm)
|
30
glibc-upstream-2.39-143.patch
Normal file
30
glibc-upstream-2.39-143.patch
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
commit 2c8a7f14fac3628b6a06cc76cdfda54a7ac20386
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Dec 17 18:12:03 2024 +0100
|
||||||
|
|
||||||
|
x86: Avoid integer truncation with large cache sizes (bug 32470)
|
||||||
|
|
||||||
|
Some hypervisors report 1 TiB L3 cache size. This results
|
||||||
|
in some variables incorrectly getting zeroed, causing crashes
|
||||||
|
in memcpy/memmove because invariants are violated.
|
||||||
|
|
||||||
|
(cherry picked from commit 61c3450db96dce96ad2b24b4f0b548e6a46d68e5)
|
||||||
|
|
||||||
|
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
|
||||||
|
index 5a98f70364220da4..1f68968a9a457586 100644
|
||||||
|
--- a/sysdeps/x86/dl-cacheinfo.h
|
||||||
|
+++ b/sysdeps/x86/dl-cacheinfo.h
|
||||||
|
@@ -959,11 +959,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
|
||||||
|
non_temporal_threshold = maximum_non_temporal_threshold;
|
||||||
|
|
||||||
|
/* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */
|
||||||
|
- unsigned int minimum_rep_movsb_threshold;
|
||||||
|
+ unsigned long int minimum_rep_movsb_threshold;
|
||||||
|
/* NB: The default REP MOVSB threshold is 4096 * (VEC_SIZE / 16) for
|
||||||
|
VEC_SIZE == 64 or 32. For VEC_SIZE == 16, the default REP MOVSB
|
||||||
|
threshold is 2048 * (VEC_SIZE / 16). */
|
||||||
|
- unsigned int rep_movsb_threshold;
|
||||||
|
+ unsigned long int rep_movsb_threshold;
|
||||||
|
if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
|
||||||
|
&& !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512))
|
||||||
|
{
|
250
glibc-upstream-2.39-144.patch
Normal file
250
glibc-upstream-2.39-144.patch
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
commit 61daaa76390e0ff73eade3a688d3626b7e7e0c20
|
||||||
|
Author: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
Date: Fri May 24 12:38:50 2024 -0500
|
||||||
|
|
||||||
|
x86: Improve large memset perf with non-temporal stores [RHEL-29312]
|
||||||
|
|
||||||
|
Previously we use `rep stosb` for all medium/large memsets. This is
|
||||||
|
notably worse than non-temporal stores for large (above a
|
||||||
|
few MBs) memsets.
|
||||||
|
See:
|
||||||
|
https://docs.google.com/spreadsheets/d/1opzukzvum4n6-RUVHTGddV6RjAEil4P2uMjjQGLbLcU/edit?usp=sharing
|
||||||
|
For data using different stategies for large memset on ICX and SKX.
|
||||||
|
|
||||||
|
Using non-temporal stores can be up to 3x faster on ICX and 2x faster
|
||||||
|
on SKX. Historically, these numbers would not have been so good
|
||||||
|
because of the zero-over-zero writeback optimization that `rep stosb`
|
||||||
|
is able to do. But, the zero-over-zero writeback optimization has been
|
||||||
|
removed as a potential side-channel attack, so there is no longer any
|
||||||
|
good reason to only rely on `rep stosb` for large memsets. On the flip
|
||||||
|
size, non-temporal writes can avoid data in their RFO requests saving
|
||||||
|
memory bandwidth.
|
||||||
|
|
||||||
|
All of the other changes to the file are to re-organize the
|
||||||
|
code-blocks to maintain "good" alignment given the new code added in
|
||||||
|
the `L(stosb_local)` case.
|
||||||
|
|
||||||
|
The results from running the GLIBC memset benchmarks on TGL-client for
|
||||||
|
N=20 runs:
|
||||||
|
|
||||||
|
Geometric Mean across the suite New / Old EXEX256: 0.979
|
||||||
|
Geometric Mean across the suite New / Old EXEX512: 0.979
|
||||||
|
Geometric Mean across the suite New / Old AVX2 : 0.986
|
||||||
|
Geometric Mean across the suite New / Old SSE2 : 0.979
|
||||||
|
|
||||||
|
Most of the cases are essentially unchanged, this is mostly to show
|
||||||
|
that adding the non-temporal case didn't add any regressions to the
|
||||||
|
other cases.
|
||||||
|
|
||||||
|
The results on the memset-large benchmark suite on TGL-client for N=20
|
||||||
|
runs:
|
||||||
|
|
||||||
|
Geometric Mean across the suite New / Old EXEX256: 0.926
|
||||||
|
Geometric Mean across the suite New / Old EXEX512: 0.925
|
||||||
|
Geometric Mean across the suite New / Old AVX2 : 0.928
|
||||||
|
Geometric Mean across the suite New / Old SSE2 : 0.924
|
||||||
|
|
||||||
|
So roughly a 7.5% speedup. This is lower than what we see on servers
|
||||||
|
(likely because clients typically have faster single-core bandwidth so
|
||||||
|
saving bandwidth on RFOs is less impactful), but still advantageous.
|
||||||
|
|
||||||
|
Full test-suite passes on x86_64 w/ and w/o multiarch.
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
(cherry picked from commit 5bf0ab80573d66e4ae5d94b094659094336da90f)
|
||||||
|
|
||||||
|
diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
|
||||||
|
index 97839a22483b0613..637caadb406b2544 100644
|
||||||
|
--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
|
||||||
|
+++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
|
||||||
|
@@ -21,10 +21,13 @@
|
||||||
|
2. If size is less than VEC, use integer register stores.
|
||||||
|
3. If size is from VEC_SIZE to 2 * VEC_SIZE, use 2 VEC stores.
|
||||||
|
4. If size is from 2 * VEC_SIZE to 4 * VEC_SIZE, use 4 VEC stores.
|
||||||
|
- 5. On machines ERMS feature, if size is greater or equal than
|
||||||
|
- __x86_rep_stosb_threshold then REP STOSB will be used.
|
||||||
|
- 6. If size is more to 4 * VEC_SIZE, align to 4 * VEC_SIZE with
|
||||||
|
- 4 VEC stores and store 4 * VEC at a time until done. */
|
||||||
|
+ 5. If size is more to 4 * VEC_SIZE, align to 1 * VEC_SIZE with
|
||||||
|
+ 4 VEC stores and store 4 * VEC at a time until done.
|
||||||
|
+ 6. On machines ERMS feature, if size is range
|
||||||
|
+ [__x86_rep_stosb_threshold, __x86_shared_non_temporal_threshold)
|
||||||
|
+ then REP STOSB will be used.
|
||||||
|
+ 7. If size >= __x86_shared_non_temporal_threshold, use a
|
||||||
|
+ non-temporal stores. */
|
||||||
|
|
||||||
|
#include <sysdep.h>
|
||||||
|
|
||||||
|
@@ -147,6 +150,41 @@ L(entry_from_wmemset):
|
||||||
|
VMOVU %VMM(0), -VEC_SIZE(%rdi,%rdx)
|
||||||
|
VMOVU %VMM(0), (%rdi)
|
||||||
|
VZEROUPPER_RETURN
|
||||||
|
+
|
||||||
|
+ /* If have AVX512 mask instructions put L(less_vec) close to
|
||||||
|
+ entry as it doesn't take much space and is likely a hot target. */
|
||||||
|
+#ifdef USE_LESS_VEC_MASK_STORE
|
||||||
|
+ /* Align to ensure the L(less_vec) logic all fits in 1x cache lines. */
|
||||||
|
+ .p2align 6,, 47
|
||||||
|
+ .p2align 4
|
||||||
|
+L(less_vec):
|
||||||
|
+L(less_vec_from_wmemset):
|
||||||
|
+ /* Less than 1 VEC. */
|
||||||
|
+# if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64
|
||||||
|
+# error Unsupported VEC_SIZE!
|
||||||
|
+# endif
|
||||||
|
+ /* Clear high bits from edi. Only keeping bits relevant to page
|
||||||
|
+ cross check. Note that we are using rax which is set in
|
||||||
|
+ MEMSET_VDUP_TO_VEC0_AND_SET_RETURN as ptr from here on out. */
|
||||||
|
+ andl $(PAGE_SIZE - 1), %edi
|
||||||
|
+ /* Check if VEC_SIZE store cross page. Mask stores suffer
|
||||||
|
+ serious performance degradation when it has to fault suppress. */
|
||||||
|
+ cmpl $(PAGE_SIZE - VEC_SIZE), %edi
|
||||||
|
+ /* This is generally considered a cold target. */
|
||||||
|
+ ja L(cross_page)
|
||||||
|
+# if VEC_SIZE > 32
|
||||||
|
+ movq $-1, %rcx
|
||||||
|
+ bzhiq %rdx, %rcx, %rcx
|
||||||
|
+ kmovq %rcx, %k1
|
||||||
|
+# else
|
||||||
|
+ movl $-1, %ecx
|
||||||
|
+ bzhil %edx, %ecx, %ecx
|
||||||
|
+ kmovd %ecx, %k1
|
||||||
|
+# endif
|
||||||
|
+ vmovdqu8 %VMM(0), (%rax){%k1}
|
||||||
|
+ VZEROUPPER_RETURN
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if defined USE_MULTIARCH && IS_IN (libc)
|
||||||
|
END (MEMSET_SYMBOL (__memset, unaligned))
|
||||||
|
|
||||||
|
@@ -185,54 +223,6 @@ L(last_2x_vec):
|
||||||
|
#endif
|
||||||
|
VZEROUPPER_RETURN
|
||||||
|
|
||||||
|
- /* If have AVX512 mask instructions put L(less_vec) close to
|
||||||
|
- entry as it doesn't take much space and is likely a hot target.
|
||||||
|
- */
|
||||||
|
-#ifdef USE_LESS_VEC_MASK_STORE
|
||||||
|
- .p2align 4,, 10
|
||||||
|
-L(less_vec):
|
||||||
|
-L(less_vec_from_wmemset):
|
||||||
|
- /* Less than 1 VEC. */
|
||||||
|
-# if VEC_SIZE != 16 && VEC_SIZE != 32 && VEC_SIZE != 64
|
||||||
|
-# error Unsupported VEC_SIZE!
|
||||||
|
-# endif
|
||||||
|
- /* Clear high bits from edi. Only keeping bits relevant to page
|
||||||
|
- cross check. Note that we are using rax which is set in
|
||||||
|
- MEMSET_VDUP_TO_VEC0_AND_SET_RETURN as ptr from here on out. */
|
||||||
|
- andl $(PAGE_SIZE - 1), %edi
|
||||||
|
- /* Check if VEC_SIZE store cross page. Mask stores suffer
|
||||||
|
- serious performance degradation when it has to fault suppress.
|
||||||
|
- */
|
||||||
|
- cmpl $(PAGE_SIZE - VEC_SIZE), %edi
|
||||||
|
- /* This is generally considered a cold target. */
|
||||||
|
- ja L(cross_page)
|
||||||
|
-# if VEC_SIZE > 32
|
||||||
|
- movq $-1, %rcx
|
||||||
|
- bzhiq %rdx, %rcx, %rcx
|
||||||
|
- kmovq %rcx, %k1
|
||||||
|
-# else
|
||||||
|
- movl $-1, %ecx
|
||||||
|
- bzhil %edx, %ecx, %ecx
|
||||||
|
- kmovd %ecx, %k1
|
||||||
|
-# endif
|
||||||
|
- vmovdqu8 %VMM(0), (%rax){%k1}
|
||||||
|
- VZEROUPPER_RETURN
|
||||||
|
-
|
||||||
|
-# if defined USE_MULTIARCH && IS_IN (libc)
|
||||||
|
- /* Include L(stosb_local) here if including L(less_vec) between
|
||||||
|
- L(stosb_more_2x_vec) and ENTRY. This is to cache align the
|
||||||
|
- L(stosb_more_2x_vec) target. */
|
||||||
|
- .p2align 4,, 10
|
||||||
|
-L(stosb_local):
|
||||||
|
- movzbl %sil, %eax
|
||||||
|
- mov %RDX_LP, %RCX_LP
|
||||||
|
- mov %RDI_LP, %RDX_LP
|
||||||
|
- rep stosb
|
||||||
|
- mov %RDX_LP, %RAX_LP
|
||||||
|
- VZEROUPPER_RETURN
|
||||||
|
-# endif
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
#if defined USE_MULTIARCH && IS_IN (libc)
|
||||||
|
.p2align 4
|
||||||
|
L(stosb_more_2x_vec):
|
||||||
|
@@ -318,21 +308,33 @@ L(return_vzeroupper):
|
||||||
|
ret
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- .p2align 4,, 10
|
||||||
|
-#ifndef USE_LESS_VEC_MASK_STORE
|
||||||
|
-# if defined USE_MULTIARCH && IS_IN (libc)
|
||||||
|
+#ifdef USE_WITH_AVX2
|
||||||
|
+ .p2align 4
|
||||||
|
+#else
|
||||||
|
+ .p2align 4,, 4
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#if defined USE_MULTIARCH && IS_IN (libc)
|
||||||
|
/* If no USE_LESS_VEC_MASK put L(stosb_local) here. Will be in
|
||||||
|
range for 2-byte jump encoding. */
|
||||||
|
L(stosb_local):
|
||||||
|
+ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP
|
||||||
|
+ jae L(nt_memset)
|
||||||
|
movzbl %sil, %eax
|
||||||
|
mov %RDX_LP, %RCX_LP
|
||||||
|
mov %RDI_LP, %RDX_LP
|
||||||
|
rep stosb
|
||||||
|
+# if (defined USE_WITH_SSE2) || (defined USE_WITH_AVX512)
|
||||||
|
+ /* Use xchg to save 1-byte (this helps align targets below). */
|
||||||
|
+ xchg %RDX_LP, %RAX_LP
|
||||||
|
+# else
|
||||||
|
mov %RDX_LP, %RAX_LP
|
||||||
|
- VZEROUPPER_RETURN
|
||||||
|
# endif
|
||||||
|
+ VZEROUPPER_RETURN
|
||||||
|
+#endif
|
||||||
|
+#ifndef USE_LESS_VEC_MASK_STORE
|
||||||
|
/* Define L(less_vec) only if not otherwise defined. */
|
||||||
|
- .p2align 4
|
||||||
|
+ .p2align 4,, 12
|
||||||
|
L(less_vec):
|
||||||
|
/* Broadcast esi to partial register (i.e VEC_SIZE == 32 broadcast to
|
||||||
|
xmm). This is only does anything for AVX2. */
|
||||||
|
@@ -423,4 +425,35 @@ L(between_2_3):
|
||||||
|
movb %SET_REG8, -1(%LESS_VEC_REG, %rdx)
|
||||||
|
#endif
|
||||||
|
ret
|
||||||
|
-END (MEMSET_SYMBOL (__memset, unaligned_erms))
|
||||||
|
+
|
||||||
|
+#if defined USE_MULTIARCH && IS_IN (libc)
|
||||||
|
+# ifdef USE_WITH_AVX512
|
||||||
|
+ /* Force align so the loop doesn't cross a cache-line. */
|
||||||
|
+ .p2align 4
|
||||||
|
+# endif
|
||||||
|
+ .p2align 4,, 7
|
||||||
|
+ /* Memset using non-temporal stores. */
|
||||||
|
+L(nt_memset):
|
||||||
|
+ VMOVU %VMM(0), (VEC_SIZE * 0)(%rdi)
|
||||||
|
+ leaq (VEC_SIZE * -4)(%rdi, %rdx), %rdx
|
||||||
|
+ /* Align DST. */
|
||||||
|
+ orq $(VEC_SIZE * 1 - 1), %rdi
|
||||||
|
+ incq %rdi
|
||||||
|
+ .p2align 4,, 7
|
||||||
|
+L(nt_loop):
|
||||||
|
+ VMOVNT %VMM(0), (VEC_SIZE * 0)(%rdi)
|
||||||
|
+ VMOVNT %VMM(0), (VEC_SIZE * 1)(%rdi)
|
||||||
|
+ VMOVNT %VMM(0), (VEC_SIZE * 2)(%rdi)
|
||||||
|
+ VMOVNT %VMM(0), (VEC_SIZE * 3)(%rdi)
|
||||||
|
+ subq $(VEC_SIZE * -4), %rdi
|
||||||
|
+ cmpq %rdx, %rdi
|
||||||
|
+ jb L(nt_loop)
|
||||||
|
+ sfence
|
||||||
|
+ VMOVU %VMM(0), (VEC_SIZE * 0)(%rdx)
|
||||||
|
+ VMOVU %VMM(0), (VEC_SIZE * 1)(%rdx)
|
||||||
|
+ VMOVU %VMM(0), (VEC_SIZE * 2)(%rdx)
|
||||||
|
+ VMOVU %VMM(0), (VEC_SIZE * 3)(%rdx)
|
||||||
|
+ VZEROUPPER_RETURN
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+END(MEMSET_SYMBOL(__memset, unaligned_erms))
|
143
glibc-upstream-2.39-145.patch
Normal file
143
glibc-upstream-2.39-145.patch
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
commit 994b129a35ca5218ecddd1add74aea68f1314560
|
||||||
|
Author: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
Date: Fri Sep 27 15:50:10 2024 -0700
|
||||||
|
|
||||||
|
x86/string: Fixup alignment of main loop in str{n}cmp-evex [BZ #32212]
|
||||||
|
|
||||||
|
The loop should be aligned to 32-bytes so that it can ideally run out
|
||||||
|
the DSB. This is particularly important on Skylake-Server where
|
||||||
|
deficiencies in it's DSB implementation make it prone to not being
|
||||||
|
able to run loops out of the DSB.
|
||||||
|
|
||||||
|
For example running strcmp-evex on 200Mb string:
|
||||||
|
|
||||||
|
32-byte aligned loop:
|
||||||
|
- 43,399,578,766 idq.dsb_uops
|
||||||
|
not 32-byte aligned loop:
|
||||||
|
- 6,060,139,704 idq.dsb_uops
|
||||||
|
|
||||||
|
This results in a 25% performance degradation for the non-aligned
|
||||||
|
version.
|
||||||
|
|
||||||
|
The fix is to just ensure the code layout is such that the loop is
|
||||||
|
aligned. (Which was previously the case but was accidentally dropped
|
||||||
|
in 84e7c46df).
|
||||||
|
|
||||||
|
NB: The fix was actually 64-byte alignment. This is because 64-byte
|
||||||
|
alignment generally produces more stable performance than 32-byte
|
||||||
|
aligned code (cache line crosses can affect perf), so if we are going
|
||||||
|
past 16-byte alignmnent, might as well go to 64. 64-byte alignment
|
||||||
|
also matches most other functions we over-align, so it creates a
|
||||||
|
common point of optimization.
|
||||||
|
|
||||||
|
Times are reported as ratio of Time_With_Patch /
|
||||||
|
Time_Without_Patch. Lower is better.
|
||||||
|
|
||||||
|
The values being reported is the geometric mean of the ratio across
|
||||||
|
all tests in bench-strcmp and bench-strncmp.
|
||||||
|
|
||||||
|
Note this patch is only attempting to improve the Skylake-Server
|
||||||
|
strcmp for long strings. The rest of the numbers are only to test for
|
||||||
|
regressions.
|
||||||
|
|
||||||
|
Tigerlake Results Strings <= 512:
|
||||||
|
strcmp : 1.026
|
||||||
|
strncmp: 0.949
|
||||||
|
|
||||||
|
Tigerlake Results Strings > 512:
|
||||||
|
strcmp : 0.994
|
||||||
|
strncmp: 0.998
|
||||||
|
|
||||||
|
Skylake-Server Results Strings <= 512:
|
||||||
|
strcmp : 0.945
|
||||||
|
strncmp: 0.943
|
||||||
|
|
||||||
|
Skylake-Server Results Strings > 512:
|
||||||
|
strcmp : 0.778
|
||||||
|
strncmp: 1.000
|
||||||
|
|
||||||
|
The 2.6% regression on TGL-strcmp is due to slowdowns caused by
|
||||||
|
changes in alignment of code handling small sizes (most on the
|
||||||
|
page-cross logic). These should be safe to ignore because 1) We
|
||||||
|
previously only 16-byte aligned the function so this behavior is not
|
||||||
|
new and was essentially up to chance before this patch and 2) this
|
||||||
|
type of alignment related regression on small sizes really only comes
|
||||||
|
up in tight micro-benchmark loops and is unlikely to have any affect
|
||||||
|
on realworld performance.
|
||||||
|
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
(cherry picked from commit 483443d3211532903d7e790211af5a1d55fdb1f3)
|
||||||
|
|
||||||
|
diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S
|
||||||
|
index 06730ab2a18f72a0..cea034f394ab45e2 100644
|
||||||
|
--- a/sysdeps/x86_64/multiarch/strcmp-evex.S
|
||||||
|
+++ b/sysdeps/x86_64/multiarch/strcmp-evex.S
|
||||||
|
@@ -209,7 +209,9 @@
|
||||||
|
returned. */
|
||||||
|
|
||||||
|
.section SECTION(.text), "ax", @progbits
|
||||||
|
- .align 16
|
||||||
|
+ /* Align 64 bytes here. This is to get the L(loop) block ideally
|
||||||
|
+ aligned for the DSB. */
|
||||||
|
+ .align 64
|
||||||
|
.type STRCMP, @function
|
||||||
|
.globl STRCMP
|
||||||
|
# ifdef USE_AS_STRCASECMP_L
|
||||||
|
@@ -509,9 +511,7 @@ L(ret4):
|
||||||
|
ret
|
||||||
|
# endif
|
||||||
|
|
||||||
|
- /* 32 byte align here ensures the main loop is ideally aligned
|
||||||
|
- for DSB. */
|
||||||
|
- .p2align 5
|
||||||
|
+ .p2align 4,, 4
|
||||||
|
L(more_3x_vec):
|
||||||
|
/* Safe to compare 4x vectors. */
|
||||||
|
VMOVU (VEC_SIZE)(%rdi), %VMM(0)
|
||||||
|
@@ -1426,10 +1426,9 @@ L(less_32_till_page):
|
||||||
|
L(ret_zero_page_cross_slow_case0):
|
||||||
|
xorl %eax, %eax
|
||||||
|
ret
|
||||||
|
-# endif
|
||||||
|
-
|
||||||
|
-
|
||||||
|
+# else
|
||||||
|
.p2align 4,, 10
|
||||||
|
+# endif
|
||||||
|
L(less_16_till_page):
|
||||||
|
cmpl $((VEC_SIZE - 8) / SIZE_OF_CHAR), %eax
|
||||||
|
ja L(less_8_till_page)
|
||||||
|
@@ -1482,8 +1481,12 @@ L(less_16_till_page):
|
||||||
|
# endif
|
||||||
|
jmp L(prepare_loop_aligned)
|
||||||
|
|
||||||
|
-
|
||||||
|
-
|
||||||
|
+# ifndef USE_AS_STRNCMP
|
||||||
|
+ /* Fits in aligning bytes. */
|
||||||
|
+L(ret_zero_4_loop):
|
||||||
|
+ xorl %eax, %eax
|
||||||
|
+ ret
|
||||||
|
+# endif
|
||||||
|
|
||||||
|
.p2align 4,, 10
|
||||||
|
L(less_8_till_page):
|
||||||
|
@@ -1554,6 +1557,7 @@ L(ret_less_8_wcs):
|
||||||
|
|
||||||
|
# ifdef USE_AS_STRNCMP
|
||||||
|
.p2align 4,, 2
|
||||||
|
+L(ret_zero_4_loop):
|
||||||
|
L(ret_zero_page_cross_slow_case1):
|
||||||
|
xorl %eax, %eax
|
||||||
|
ret
|
||||||
|
@@ -1586,10 +1590,6 @@ L(less_4_loop):
|
||||||
|
subq $-(CHAR_PER_VEC * 4), %rdx
|
||||||
|
# endif
|
||||||
|
jmp L(prepare_loop_aligned)
|
||||||
|
-
|
||||||
|
-L(ret_zero_4_loop):
|
||||||
|
- xorl %eax, %eax
|
||||||
|
- ret
|
||||||
|
L(ret_less_4_loop):
|
||||||
|
xorl %r8d, %eax
|
||||||
|
subl %r8d, %eax
|
57
glibc-upstream-2.39-146.patch
Normal file
57
glibc-upstream-2.39-146.patch
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
commit 808a84a8b81468b517a4d721fdc62069cb8c211f
|
||||||
|
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||||
|
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 <siddhesh@sourceware.org>
|
||||||
|
Reviewed: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
(cherry picked from commit 68ee0f704cb81e9ad0a78c644a83e1e9cd2ee578)
|
||||||
|
|
||||||
|
diff --git a/assert/assert.c b/assert/assert.c
|
||||||
|
index c29629f5f68921a0..b6e37d694cf4b779 100644
|
||||||
|
--- a/assert/assert.c
|
||||||
|
+++ b/assert/assert.c
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <atomic.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
+#include <libc-pointer-arith.h>
|
||||||
|
#include <libintl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
@@ -65,7 +66,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
|
||||||
|
(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 --git a/sysdeps/posix/libc_fatal.c b/sysdeps/posix/libc_fatal.c
|
||||||
|
index f9e3425e04496a26..089c47b04b8af049 100644
|
||||||
|
--- a/sysdeps/posix/libc_fatal.c
|
||||||
|
+++ b/sysdeps/posix/libc_fatal.c
|
||||||
|
@@ -20,6 +20,7 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
+#include <libc-pointer-arith.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
@@ -105,7 +106,8 @@ __libc_message_impl (const char *fmt, ...)
|
||||||
|
{
|
||||||
|
WRITEV_FOR_FATAL (fd, iov, iovcnt, 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);
|
58
glibc.spec
58
glibc.spec
@ -145,7 +145,7 @@ Version: %{glibcversion}
|
|||||||
# - It allows using the Release number without the %%dist tag in the dependency
|
# - It allows using the Release number without the %%dist tag in the dependency
|
||||||
# generator to make the generated requires interchangeable between Rawhide
|
# generator to make the generated requires interchangeable between Rawhide
|
||||||
# and ELN (.elnYY < .fcXX).
|
# and ELN (.elnYY < .fcXX).
|
||||||
%global baserelease 32
|
%global baserelease 37
|
||||||
Release: %{baserelease}%{?dist}.alma.1
|
Release: %{baserelease}%{?dist}.alma.1
|
||||||
|
|
||||||
# Licenses:
|
# Licenses:
|
||||||
@ -485,8 +485,31 @@ Patch167: glibc-upstream-2.39-137.patch
|
|||||||
Patch168: glibc-RHEL-12867-2.patch
|
Patch168: glibc-RHEL-12867-2.patch
|
||||||
Patch169: glibc-RHEL-12867-3.patch
|
Patch169: glibc-RHEL-12867-3.patch
|
||||||
Patch170: glibc-RHEL-42410.patch
|
Patch170: glibc-RHEL-42410.patch
|
||||||
|
Patch171: glibc-RHEL-71530-1.patch
|
||||||
|
Patch172: glibc-RHEL-71530-2.patch
|
||||||
|
Patch173: glibc-RHEL-71530-3.patch
|
||||||
|
Patch174: glibc-RHEL-71530-4.patch
|
||||||
|
Patch175: glibc-RHEL-71530-5.patch
|
||||||
|
Patch176: glibc-RHEL-71530-6.patch
|
||||||
|
Patch177: glibc-RHEL-71530-7.patch
|
||||||
|
Patch178: glibc-RHEL-71530-8.patch
|
||||||
|
Patch179: glibc-RHEL-71530-9.patch
|
||||||
|
Patch180: glibc-RHEL-71530-10.patch
|
||||||
|
Patch181: glibc-upstream-2.39-138.patch
|
||||||
|
Patch182: glibc-upstream-2.39-139.patch
|
||||||
|
Patch183: glibc-upstream-2.39-140.patch
|
||||||
|
Patch184: glibc-upstream-2.39-141.patch
|
||||||
|
Patch185: glibc-upstream-2.39-142.patch
|
||||||
|
Patch186: glibc-upstream-2.39-143.patch
|
||||||
|
Patch187: glibc-upstream-2.39-144.patch
|
||||||
|
Patch188: glibc-upstream-2.39-145.patch
|
||||||
|
Patch189: glibc-upstream-2.39-146.patch
|
||||||
|
Patch190: glibc-RHEL-75809.patch
|
||||||
|
Patch191: glibc-RHEL-75555.patch
|
||||||
|
Patch192: glibc-RHEL-75809-2.patch
|
||||||
|
Patch193: glibc-RHEL-75809-3.patch
|
||||||
|
|
||||||
# AlmaLinux backport: https://sourceware.org/bugzilla/show_bug.cgi?id=32470
|
# AlmaLinux Patch
|
||||||
Patch1000: glibc-upstream-2.39-bz-32470.patch
|
Patch1000: glibc-upstream-2.39-bz-32470.patch
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -2486,13 +2509,37 @@ update_gconv_modules_cache ()
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Feb 11 2025 Eduard Abdullin <eabdullin@almalinux.org> - 2.39-37.alma.1
|
||||||
* Wed Jan 08 2025 Eduard Abdullin <eabdullin@almalinux.org> - 2.39-32.alma.1
|
|
||||||
- Overwrite target for x86_64_v2
|
- Overwrite target for x86_64_v2
|
||||||
|
|
||||||
* Mon Dec 23 2024 Koichiro Iwao <meta@almalinux.org> - 2.39-23.alma.2
|
* Tue Feb 11 2025 Koichiro Iwao <meta@almalinux.org> - 2.39-37.alma.1
|
||||||
- Apply patch from upstream BZ #32470
|
- Apply patch from upstream BZ #32470
|
||||||
|
|
||||||
|
* Fri Jan 24 2025 Florian Weimer <fweimer@redhat.com> - 2.39-37
|
||||||
|
- setenv: Rework free(environ) compatibility support (RHEL-75809)
|
||||||
|
|
||||||
|
* Thu Jan 23 2025 Florian Weimer <fweimer@redhat.com> - 2.39-36
|
||||||
|
- CVE-2025-0577: vDSO getrandom predictable randomness after fork (RHEL-75555)
|
||||||
|
|
||||||
|
* Thu Jan 23 2025 Florian Weimer <fweimer@redhat.com> - 2.39-35
|
||||||
|
- Restore compatibility with environ/malloc usage pattern (RHEL-75809)
|
||||||
|
|
||||||
|
* Thu Jan 23 2025 Florian Weimer <fweimer@redhat.com> - 2.39-34
|
||||||
|
- Sync with upstream branch release/2.39/master,
|
||||||
|
commit 808a84a8b81468b517a4d721fdc62069cb8c211f:
|
||||||
|
- Fix underallocation of abort_msg_s struct (CVE-2025-0395)
|
||||||
|
- x86/string: Fixup alignment of main loop in str{n}cmp-evex [BZ #32212]
|
||||||
|
- x86: Improve large memset perf with non-temporal stores [RHEL-29312]
|
||||||
|
- x86: Avoid integer truncation with large cache sizes (bug 32470)
|
||||||
|
- math: Exclude internal math symbols for tests [BZ #32414]
|
||||||
|
- malloc: add indirection for malloc(-like) functions in tests [BZ #32366]
|
||||||
|
- Pass -nostdlib -nostartfiles together with -r [BZ #31753]
|
||||||
|
- nptl: initialize cpu_id_start prior to rseq registration
|
||||||
|
- nptl: initialize rseq area prior to registration
|
||||||
|
|
||||||
|
* Mon Dec 23 2024 Florian Weimer <fweimer@redhat.com> - 2.39-33
|
||||||
|
- Support in-place file conversion in the iconv tool (RHEL-71530)
|
||||||
|
|
||||||
* Mon Dec 16 2024 Florian Weimer <fweimer@redhat.com> - 2.39-32
|
* Mon Dec 16 2024 Florian Weimer <fweimer@redhat.com> - 2.39-32
|
||||||
- Make getenv thread-safe in more cases (RHEL-42410)
|
- Make getenv thread-safe in more cases (RHEL-42410)
|
||||||
|
|
||||||
@ -2564,7 +2611,6 @@ update_gconv_modules_cache ()
|
|||||||
* Mon Nov 4 2024 Florian Weimer <fweimer@redhat.com> - 2.39-24
|
* Mon Nov 4 2024 Florian Weimer <fweimer@redhat.com> - 2.39-24
|
||||||
- Switch to the upstream way of building xtests
|
- Switch to the upstream way of building xtests
|
||||||
|
|
||||||
|
|
||||||
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 2.39-23
|
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 2.39-23
|
||||||
- Bump release for October 2024 mass rebuild:
|
- Bump release for October 2024 mass rebuild:
|
||||||
Resolves: RHEL-64018
|
Resolves: RHEL-64018
|
||||||
|
Loading…
Reference in New Issue
Block a user