import glibc-2.28-189.1.el8

This commit is contained in:
CentOS Sources 2022-05-10 03:16:26 -04:00 committed by Stepan Oksanichenko
parent e3ace7a765
commit 385bc0f199
82 changed files with 14284 additions and 248 deletions

View File

@ -159,6 +159,7 @@ en_SG/ISO-8859-1 \
en_US.UTF-8/UTF-8 \ en_US.UTF-8/UTF-8 \
en_US/ISO-8859-1 \ en_US/ISO-8859-1 \
en_US.ISO-8859-15/ISO-8859-15 \ en_US.ISO-8859-15/ISO-8859-15 \
en_US@ampm.UTF-8/UTF-8 \
en_ZA.UTF-8/UTF-8 \ en_ZA.UTF-8/UTF-8 \
en_ZA/ISO-8859-1 \ en_ZA/ISO-8859-1 \
en_ZM/UTF-8 \ en_ZM/UTF-8 \

View File

@ -0,0 +1,38 @@
This patch is a downstream-only variant of this upstream commit:
commit 45b1e17e9150dbd9ac2d578579063fbfa8e1b327
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Dec 17 10:03:05 2020 +0000
aarch64: use PTR_ARG and SIZE_ARG instead of DELOUSE
DELOUSE was added to asm code to make them compatible with non-LP64
ABIs, but it is an unfortunate name and the code was not compatible
with ABIs where pointer and size_t are different. Glibc currently
only supports the LP64 ABI so these macros are not really needed or
tested, but for now the name is changed to be more meaningful instead
of removing them completely.
Some DELOUSE macros were dropped: clone, strlen and strnlen used it
unnecessarily.
The out of tree ILP32 patches are currently not maintained and will
likely need a rework to rebase them on top of the time64 changes.
Keeping the DELOUSE macro avoids the need to update all string
functions. Lack of BTI markers and architecture variants cause many
conflicts in a full upstream backport.
diff --git a/sysdeps/aarch64/sysdep.h b/sysdeps/aarch64/sysdep.h
index 5b30709436d3acea..1bcf15d4f18586ba 100644
--- a/sysdeps/aarch64/sysdep.h
+++ b/sysdeps/aarch64/sysdep.h
@@ -32,6 +32,8 @@
# define PTR_LOG_SIZE 2
# define DELOUSE(n) mov w##n, w##n
#endif
+#define PTR_ARG(n) DELOUSE(n)
+#define SIZE_ARG(n) DELOUSE(n)
#define PTR_SIZE (1<<PTR_LOG_SIZE)

View File

@ -0,0 +1,88 @@
commit 77d175e14e5f4cf24e9579c03eef5d006a286316
Author: Naohiro Tamura <naohirot@jp.fujitsu.com>
Date: Wed May 12 09:26:40 2021 +0000
config: Added HAVE_AARCH64_SVE_ASM for aarch64
This patch checks if assembler supports '-march=armv8.2-a+sve' to
generate SVE code or not, and then define HAVE_AARCH64_SVE_ASM macro.
Conflicts:
config.h.in
(missing PAC+BTI support downstream, missing other ports)
diff --git a/config.h.in b/config.h.in
index 8520b0fa8d4668fb..94d5ea367e10f849 100644
--- a/config.h.in
+++ b/config.h.in
@@ -112,6 +112,11 @@
/* AArch64 big endian ABI */
#undef HAVE_AARCH64_BE
+/* Assembler support ARMv8.2-A SVE.
+ This macro becomes obsolete when glibc increased the minimum
+ required version of GNU 'binutils' to 2.28 or later. */
+#define HAVE_AARCH64_SVE_ASM 0
+
/* RISC-V integer ABI for ld.so. */
#undef RISCV_ABI_XLEN
diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure
index f78a79338aba1e34..9fb713155d4ee6d8 100644
--- a/sysdeps/aarch64/configure
+++ b/sysdeps/aarch64/configure
@@ -212,3 +212,31 @@ fi
$as_echo "$libc_cv_aarch64_variant_pcs" >&6; }
config_vars="$config_vars
aarch64-variant-pcs = $libc_cv_aarch64_variant_pcs"
+
+# Check if asm support armv8.2-a+sve
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVE support in assembler" >&5
+$as_echo_n "checking for SVE support in assembler... " >&6; }
+if ${libc_cv_asm_sve+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest.s <<\EOF
+ ptrue p0.b
+EOF
+if { ac_try='${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ libc_cv_aarch64_sve_asm=yes
+else
+ libc_cv_aarch64_sve_asm=no
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_sve" >&5
+$as_echo "$libc_cv_asm_sve" >&6; }
+if test $libc_cv_aarch64_sve_asm = yes; then
+ $as_echo "#define HAVE_AARCH64_SVE_ASM 1" >>confdefs.h
+
+fi
diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac
index 7f13bfb93b60bfd7..0236cfcdf3c8d10d 100644
--- a/sysdeps/aarch64/configure.ac
+++ b/sysdeps/aarch64/configure.ac
@@ -42,3 +42,18 @@ EOF
fi
rm -rf conftest.*])
LIBC_CONFIG_VAR([aarch64-variant-pcs], [$libc_cv_aarch64_variant_pcs])
+
+# Check if asm support armv8.2-a+sve
+AC_CACHE_CHECK(for SVE support in assembler, libc_cv_asm_sve, [dnl
+cat > conftest.s <<\EOF
+ ptrue p0.b
+EOF
+if AC_TRY_COMMAND(${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&AS_MESSAGE_LOG_FD); then
+ libc_cv_aarch64_sve_asm=yes
+else
+ libc_cv_aarch64_sve_asm=no
+fi
+rm -f conftest*])
+if test $libc_cv_aarch64_sve_asm = yes; then
+ AC_DEFINE(HAVE_AARCH64_SVE_ASM)
+fi

View File

@ -0,0 +1,140 @@
commit 38560563587ad8eafa700c56800ff844f18fbad1
Author: Naohiro Tamura <naohirot@fujitsu.com>
Date: Thu May 20 07:34:37 2021 +0000
aarch64: Added Vector Length Set test helper script
This patch is a test helper script to change Vector Length for child
process. This script can be used as test-wrapper for 'make check'.
Usage examples:
~/build$ make check subdirs=string \
test-wrapper='~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16'
~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16 \
make test t=string/test-memcpy
~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 32 \
./debugglibc.sh string/test-memmove
~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 64 \
./testrun.sh string/test-memset
diff --git a/INSTALL b/INSTALL
index 065565093bd76d5b..b3a4370f592c5047 100644
--- a/INSTALL
+++ b/INSTALL
@@ -387,6 +387,10 @@ the same syntax as 'test-wrapper-env', the only difference in its
semantics being starting with an empty set of environment variables
rather than the ambient set.
+ For AArch64 with SVE, when testing the GNU C Library, 'test-wrapper'
+may be set to "SRCDIR/sysdeps/unix/sysv/linux/aarch64/vltest.py
+VECTOR-LENGTH" to change Vector Length.
+
Installing the C Library
========================
diff --git a/manual/install.texi b/manual/install.texi
index 7e9f2be150e6f98a..c262fd56d0cef67b 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -425,6 +425,9 @@ use has the same syntax as @samp{test-wrapper-env}, the only
difference in its semantics being starting with an empty set of
environment variables rather than the ambient set.
+For AArch64 with SVE, when testing @theglibc{}, @samp{test-wrapper}
+may be set to "@var{srcdir}/sysdeps/unix/sysv/linux/aarch64/vltest.py
+@var{vector-length}" to change Vector Length.
@node Running make install
@appendixsec Installing the C Library
diff --git a/sysdeps/unix/sysv/linux/aarch64/vltest.py b/sysdeps/unix/sysv/linux/aarch64/vltest.py
new file mode 100755
index 0000000000000000..bed62ad151e06868
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/vltest.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python3
+# Set Scalable Vector Length test helper
+# Copyright (C) 2021 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+"""Set Scalable Vector Length test helper.
+
+Set Scalable Vector Length for child process.
+
+examples:
+
+~/build$ make check subdirs=string \
+test-wrapper='~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16'
+
+~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 16 \
+make test t=string/test-memcpy
+
+~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 32 \
+./debugglibc.sh string/test-memmove
+
+~/build$ ~/glibc/sysdeps/unix/sysv/linux/aarch64/vltest.py 64 \
+./testrun.sh string/test-memset
+"""
+import argparse
+from ctypes import cdll, CDLL
+import os
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+EXIT_UNSUPPORTED = 77
+
+AT_HWCAP = 16
+HWCAP_SVE = (1 << 22)
+
+PR_SVE_GET_VL = 51
+PR_SVE_SET_VL = 50
+PR_SVE_SET_VL_ONEXEC = (1 << 18)
+PR_SVE_VL_INHERIT = (1 << 17)
+PR_SVE_VL_LEN_MASK = 0xffff
+
+def main(args):
+ libc = CDLL("libc.so.6")
+ if not libc.getauxval(AT_HWCAP) & HWCAP_SVE:
+ print("CPU doesn't support SVE")
+ sys.exit(EXIT_UNSUPPORTED)
+
+ libc.prctl(PR_SVE_SET_VL,
+ args.vl[0] | PR_SVE_SET_VL_ONEXEC | PR_SVE_VL_INHERIT)
+ os.execvp(args.args[0], args.args)
+ print("exec system call failure")
+ sys.exit(EXIT_FAILURE)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=
+ "Set Scalable Vector Length test helper",
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ # positional argument
+ parser.add_argument("vl", nargs=1, type=int,
+ choices=range(16, 257, 16),
+ help=('vector length '\
+ 'which is multiples of 16 from 16 to 256'))
+ # remainDer arguments
+ parser.add_argument('args', nargs=argparse.REMAINDER,
+ help=('args '\
+ 'which is passed to child process'))
+ args = parser.parse_args()
+ main(args)

View File

@ -0,0 +1,623 @@
commit fa527f345cbbe852ec085932fbea979956c195b5
Author: Naohiro Tamura <naohirot@jp.fujitsu.com>
Date: Thu May 27 07:42:35 2021 +0000
aarch64: Added optimized memcpy and memmove for A64FX
This patch optimizes the performance of memcpy/memmove for A64FX [1]
which implements ARMv8-A SVE and has L1 64KB cache per core and L2 8MB
cache per NUMA node.
The performance optimization makes use of Scalable Vector Register
with several techniques such as loop unrolling, memory access
alignment, cache zero fill, and software pipelining.
SVE assembler code for memcpy/memmove is implemented as Vector Length
Agnostic code so theoretically it can be run on any SOC which supports
ARMv8-A SVE standard.
We confirmed that all testcases have been passed by running 'make
check' and 'make xcheck' not only on A64FX but also on ThunderX2.
And also we confirmed that the SVE 512 bit vector register performance
is roughly 4 times better than Advanced SIMD 128 bit register and 8
times better than scalar 64 bit register by running 'make bench'.
[1] https://github.com/fujitsu/A64FX
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Reviewed-by: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
Conflicts:
manual/tunables.texi
sysdeps/aarch64/multiarch/Makefile
sysdeps/aarch64/multiarch/ifunc-impl-list.c
sysdeps/aarch64/multiarch/init-arch.h
sysdeps/aarch64/multiarch/memcpy.c
sysdeps/aarch64/multiarch/memmove.c
sysdeps/unix/sysv/linux/aarch64/cpu-features.c
sysdeps/unix/sysv/linux/aarch64/cpu-features.h
(all conflicts due to missing optimizations for other CPUs)
diff --git a/manual/tunables.texi b/manual/tunables.texi
index bd737b5d57080462..07887981748bc44b 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -386,7 +386,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le.
The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to
assume that the CPU is @code{xxx} where xxx may have one of these values:
@code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99},
-@code{thunderx2t99p1}.
+@code{thunderx2t99p1}, @code{a64fx}.
This tunable is specific to aarch64.
@end deftp
diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
index 57ffdf72382c0a44..5a19ba0308e80983 100644
--- a/sysdeps/aarch64/multiarch/Makefile
+++ b/sysdeps/aarch64/multiarch/Makefile
@@ -1,4 +1,5 @@
ifeq ($(subdir),string)
sysdep_routines += memcpy_generic memcpy_thunderx memcpy_thunderx2 \
- memcpy_falkor memmove_falkor memset_generic memset_falkor
+ memcpy_falkor memcpy_a64fx \
+ memmove_falkor memset_generic memset_falkor
endif
diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
index e55be80103b948a2..f53db12acce37877 100644
--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
@@ -25,7 +25,7 @@
#include <stdio.h>
/* Maximum number of IFUNC implementations. */
-#define MAX_IFUNC 4
+#define MAX_IFUNC 7
size_t
__libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
@@ -42,10 +42,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx2)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor)
+#if HAVE_AARCH64_SVE_ASM
+ IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx)
+#endif
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
IFUNC_IMPL (i, name, memmove,
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
+#if HAVE_AARCH64_SVE_ASM
+ IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx)
+#endif
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
IFUNC_IMPL (i, name, memset,
/* Enable this on non-falkor processors too so that other cores
diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h
index d1e5703cb25fdcff..65dc8f82ff23c754 100644
--- a/sysdeps/aarch64/multiarch/init-arch.h
+++ b/sysdeps/aarch64/multiarch/init-arch.h
@@ -22,4 +22,6 @@
uint64_t __attribute__((unused)) midr = \
GLRO(dl_aarch64_cpu_features).midr_el1; \
unsigned __attribute__((unused)) zva_size = \
- GLRO(dl_aarch64_cpu_features).zva_size;
+ GLRO(dl_aarch64_cpu_features).zva_size; \
+ bool __attribute__((unused)) sve = \
+ GLRO(dl_aarch64_cpu_features).sve;
diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
index 4a04a63b0fe0c84b..e0313c42e82a7b86 100644
--- a/sysdeps/aarch64/multiarch/memcpy.c
+++ b/sysdeps/aarch64/multiarch/memcpy.c
@@ -32,6 +32,9 @@ extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
+# if HAVE_AARCH64_SVE_ASM
+extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden;
+# endif
libc_ifunc (__libc_memcpy,
(IS_THUNDERX (midr)
@@ -40,8 +43,13 @@ libc_ifunc (__libc_memcpy,
? __memcpy_falkor
: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
? __memcpy_thunderx2
+# if HAVE_AARCH64_SVE_ASM
+ : (IS_A64FX (midr)
+ ? __memcpy_a64fx
+ : __memcpy_generic)))));
+# else
: __memcpy_generic))));
-
+# endif
# undef memcpy
strong_alias (__libc_memcpy, memcpy);
#endif
diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
new file mode 100644
index 0000000000000000..65528405bb123737
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
@@ -0,0 +1,406 @@
+/* Optimized memcpy for Fujitsu A64FX processor.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* Assumptions:
+ *
+ * ARMv8.2-a, AArch64, unaligned accesses, sve
+ *
+ */
+
+#define L2_SIZE (8*1024*1024)/2 // L2 8MB/2
+#define CACHE_LINE_SIZE 256
+#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance
+#define dest x0
+#define src x1
+#define n x2 // size
+#define tmp1 x3
+#define tmp2 x4
+#define tmp3 x5
+#define rest x6
+#define dest_ptr x7
+#define src_ptr x8
+#define vector_length x9
+#define cl_remainder x10 // CACHE_LINE_SIZE remainder
+
+#if HAVE_AARCH64_SVE_ASM
+# if IS_IN (libc)
+# define MEMCPY __memcpy_a64fx
+# define MEMMOVE __memmove_a64fx
+
+ .arch armv8.2-a+sve
+
+ .macro dc_zva times
+ dc zva, tmp1
+ add tmp1, tmp1, CACHE_LINE_SIZE
+ .if \times-1
+ dc_zva "(\times-1)"
+ .endif
+ .endm
+
+ .macro ld1b_unroll8
+ ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+ ld1b z1.b, p0/z, [src_ptr, #1, mul vl]
+ ld1b z2.b, p0/z, [src_ptr, #2, mul vl]
+ ld1b z3.b, p0/z, [src_ptr, #3, mul vl]
+ ld1b z4.b, p0/z, [src_ptr, #4, mul vl]
+ ld1b z5.b, p0/z, [src_ptr, #5, mul vl]
+ ld1b z6.b, p0/z, [src_ptr, #6, mul vl]
+ ld1b z7.b, p0/z, [src_ptr, #7, mul vl]
+ .endm
+
+ .macro stld1b_unroll4a
+ st1b z0.b, p0, [dest_ptr, #0, mul vl]
+ st1b z1.b, p0, [dest_ptr, #1, mul vl]
+ ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+ ld1b z1.b, p0/z, [src_ptr, #1, mul vl]
+ st1b z2.b, p0, [dest_ptr, #2, mul vl]
+ st1b z3.b, p0, [dest_ptr, #3, mul vl]
+ ld1b z2.b, p0/z, [src_ptr, #2, mul vl]
+ ld1b z3.b, p0/z, [src_ptr, #3, mul vl]
+ .endm
+
+ .macro stld1b_unroll4b
+ st1b z4.b, p0, [dest_ptr, #4, mul vl]
+ st1b z5.b, p0, [dest_ptr, #5, mul vl]
+ ld1b z4.b, p0/z, [src_ptr, #4, mul vl]
+ ld1b z5.b, p0/z, [src_ptr, #5, mul vl]
+ st1b z6.b, p0, [dest_ptr, #6, mul vl]
+ st1b z7.b, p0, [dest_ptr, #7, mul vl]
+ ld1b z6.b, p0/z, [src_ptr, #6, mul vl]
+ ld1b z7.b, p0/z, [src_ptr, #7, mul vl]
+ .endm
+
+ .macro stld1b_unroll8
+ stld1b_unroll4a
+ stld1b_unroll4b
+ .endm
+
+ .macro st1b_unroll8
+ st1b z0.b, p0, [dest_ptr, #0, mul vl]
+ st1b z1.b, p0, [dest_ptr, #1, mul vl]
+ st1b z2.b, p0, [dest_ptr, #2, mul vl]
+ st1b z3.b, p0, [dest_ptr, #3, mul vl]
+ st1b z4.b, p0, [dest_ptr, #4, mul vl]
+ st1b z5.b, p0, [dest_ptr, #5, mul vl]
+ st1b z6.b, p0, [dest_ptr, #6, mul vl]
+ st1b z7.b, p0, [dest_ptr, #7, mul vl]
+ .endm
+
+ .macro shortcut_for_small_size exit
+ // if rest <= vector_length * 2
+ whilelo p0.b, xzr, n
+ whilelo p1.b, vector_length, n
+ b.last 1f
+ ld1b z0.b, p0/z, [src, #0, mul vl]
+ ld1b z1.b, p1/z, [src, #1, mul vl]
+ st1b z0.b, p0, [dest, #0, mul vl]
+ st1b z1.b, p1, [dest, #1, mul vl]
+ ret
+1: // if rest > vector_length * 8
+ cmp n, vector_length, lsl 3 // vector_length * 8
+ b.hi \exit
+ // if rest <= vector_length * 4
+ lsl tmp1, vector_length, 1 // vector_length * 2
+ whilelo p2.b, tmp1, n
+ incb tmp1
+ whilelo p3.b, tmp1, n
+ b.last 1f
+ ld1b z0.b, p0/z, [src, #0, mul vl]
+ ld1b z1.b, p1/z, [src, #1, mul vl]
+ ld1b z2.b, p2/z, [src, #2, mul vl]
+ ld1b z3.b, p3/z, [src, #3, mul vl]
+ st1b z0.b, p0, [dest, #0, mul vl]
+ st1b z1.b, p1, [dest, #1, mul vl]
+ st1b z2.b, p2, [dest, #2, mul vl]
+ st1b z3.b, p3, [dest, #3, mul vl]
+ ret
+1: // if rest <= vector_length * 8
+ lsl tmp1, vector_length, 2 // vector_length * 4
+ whilelo p4.b, tmp1, n
+ incb tmp1
+ whilelo p5.b, tmp1, n
+ b.last 1f
+ ld1b z0.b, p0/z, [src, #0, mul vl]
+ ld1b z1.b, p1/z, [src, #1, mul vl]
+ ld1b z2.b, p2/z, [src, #2, mul vl]
+ ld1b z3.b, p3/z, [src, #3, mul vl]
+ ld1b z4.b, p4/z, [src, #4, mul vl]
+ ld1b z5.b, p5/z, [src, #5, mul vl]
+ st1b z0.b, p0, [dest, #0, mul vl]
+ st1b z1.b, p1, [dest, #1, mul vl]
+ st1b z2.b, p2, [dest, #2, mul vl]
+ st1b z3.b, p3, [dest, #3, mul vl]
+ st1b z4.b, p4, [dest, #4, mul vl]
+ st1b z5.b, p5, [dest, #5, mul vl]
+ ret
+1: lsl tmp1, vector_length, 2 // vector_length * 4
+ incb tmp1 // vector_length * 5
+ incb tmp1 // vector_length * 6
+ whilelo p6.b, tmp1, n
+ incb tmp1
+ whilelo p7.b, tmp1, n
+ ld1b z0.b, p0/z, [src, #0, mul vl]
+ ld1b z1.b, p1/z, [src, #1, mul vl]
+ ld1b z2.b, p2/z, [src, #2, mul vl]
+ ld1b z3.b, p3/z, [src, #3, mul vl]
+ ld1b z4.b, p4/z, [src, #4, mul vl]
+ ld1b z5.b, p5/z, [src, #5, mul vl]
+ ld1b z6.b, p6/z, [src, #6, mul vl]
+ ld1b z7.b, p7/z, [src, #7, mul vl]
+ st1b z0.b, p0, [dest, #0, mul vl]
+ st1b z1.b, p1, [dest, #1, mul vl]
+ st1b z2.b, p2, [dest, #2, mul vl]
+ st1b z3.b, p3, [dest, #3, mul vl]
+ st1b z4.b, p4, [dest, #4, mul vl]
+ st1b z5.b, p5, [dest, #5, mul vl]
+ st1b z6.b, p6, [dest, #6, mul vl]
+ st1b z7.b, p7, [dest, #7, mul vl]
+ ret
+ .endm
+
+ENTRY (MEMCPY)
+
+ PTR_ARG (0)
+ PTR_ARG (1)
+ SIZE_ARG (2)
+
+L(memcpy):
+ cntb vector_length
+ // shortcut for less than vector_length * 8
+ // gives a free ptrue to p0.b for n >= vector_length
+ shortcut_for_small_size L(vl_agnostic)
+ // end of shortcut
+
+L(vl_agnostic): // VL Agnostic
+ mov rest, n
+ mov dest_ptr, dest
+ mov src_ptr, src
+ // if rest >= L2_SIZE && vector_length == 64 then L(L2)
+ mov tmp1, 64
+ cmp rest, L2_SIZE
+ ccmp vector_length, tmp1, 0, cs
+ b.eq L(L2)
+
+L(unroll8): // unrolling and software pipeline
+ lsl tmp1, vector_length, 3 // vector_length * 8
+ .p2align 3
+ cmp rest, tmp1
+ b.cc L(last)
+ ld1b_unroll8
+ add src_ptr, src_ptr, tmp1
+ sub rest, rest, tmp1
+ cmp rest, tmp1
+ b.cc 2f
+ .p2align 3
+1: stld1b_unroll8
+ add dest_ptr, dest_ptr, tmp1
+ add src_ptr, src_ptr, tmp1
+ sub rest, rest, tmp1
+ cmp rest, tmp1
+ b.ge 1b
+2: st1b_unroll8
+ add dest_ptr, dest_ptr, tmp1
+
+ .p2align 3
+L(last):
+ whilelo p0.b, xzr, rest
+ whilelo p1.b, vector_length, rest
+ b.last 1f
+ ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+ ld1b z1.b, p1/z, [src_ptr, #1, mul vl]
+ st1b z0.b, p0, [dest_ptr, #0, mul vl]
+ st1b z1.b, p1, [dest_ptr, #1, mul vl]
+ ret
+1: lsl tmp1, vector_length, 1 // vector_length * 2
+ whilelo p2.b, tmp1, rest
+ incb tmp1
+ whilelo p3.b, tmp1, rest
+ b.last 1f
+ ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+ ld1b z1.b, p1/z, [src_ptr, #1, mul vl]
+ ld1b z2.b, p2/z, [src_ptr, #2, mul vl]
+ ld1b z3.b, p3/z, [src_ptr, #3, mul vl]
+ st1b z0.b, p0, [dest_ptr, #0, mul vl]
+ st1b z1.b, p1, [dest_ptr, #1, mul vl]
+ st1b z2.b, p2, [dest_ptr, #2, mul vl]
+ st1b z3.b, p3, [dest_ptr, #3, mul vl]
+ ret
+1: lsl tmp1, vector_length, 2 // vector_length * 4
+ whilelo p4.b, tmp1, rest
+ incb tmp1
+ whilelo p5.b, tmp1, rest
+ incb tmp1
+ whilelo p6.b, tmp1, rest
+ incb tmp1
+ whilelo p7.b, tmp1, rest
+ ld1b z0.b, p0/z, [src_ptr, #0, mul vl]
+ ld1b z1.b, p1/z, [src_ptr, #1, mul vl]
+ ld1b z2.b, p2/z, [src_ptr, #2, mul vl]
+ ld1b z3.b, p3/z, [src_ptr, #3, mul vl]
+ ld1b z4.b, p4/z, [src_ptr, #4, mul vl]
+ ld1b z5.b, p5/z, [src_ptr, #5, mul vl]
+ ld1b z6.b, p6/z, [src_ptr, #6, mul vl]
+ ld1b z7.b, p7/z, [src_ptr, #7, mul vl]
+ st1b z0.b, p0, [dest_ptr, #0, mul vl]
+ st1b z1.b, p1, [dest_ptr, #1, mul vl]
+ st1b z2.b, p2, [dest_ptr, #2, mul vl]
+ st1b z3.b, p3, [dest_ptr, #3, mul vl]
+ st1b z4.b, p4, [dest_ptr, #4, mul vl]
+ st1b z5.b, p5, [dest_ptr, #5, mul vl]
+ st1b z6.b, p6, [dest_ptr, #6, mul vl]
+ st1b z7.b, p7, [dest_ptr, #7, mul vl]
+ ret
+
+L(L2):
+ // align dest address at CACHE_LINE_SIZE byte boundary
+ mov tmp1, CACHE_LINE_SIZE
+ ands tmp2, dest_ptr, CACHE_LINE_SIZE - 1
+ // if cl_remainder == 0
+ b.eq L(L2_dc_zva)
+ sub cl_remainder, tmp1, tmp2
+ // process remainder until the first CACHE_LINE_SIZE boundary
+ whilelo p1.b, xzr, cl_remainder // keep p0.b all true
+ whilelo p2.b, vector_length, cl_remainder
+ b.last 1f
+ ld1b z1.b, p1/z, [src_ptr, #0, mul vl]
+ ld1b z2.b, p2/z, [src_ptr, #1, mul vl]
+ st1b z1.b, p1, [dest_ptr, #0, mul vl]
+ st1b z2.b, p2, [dest_ptr, #1, mul vl]
+ b 2f
+1: lsl tmp1, vector_length, 1 // vector_length * 2
+ whilelo p3.b, tmp1, cl_remainder
+ incb tmp1
+ whilelo p4.b, tmp1, cl_remainder
+ ld1b z1.b, p1/z, [src_ptr, #0, mul vl]
+ ld1b z2.b, p2/z, [src_ptr, #1, mul vl]
+ ld1b z3.b, p3/z, [src_ptr, #2, mul vl]
+ ld1b z4.b, p4/z, [src_ptr, #3, mul vl]
+ st1b z1.b, p1, [dest_ptr, #0, mul vl]
+ st1b z2.b, p2, [dest_ptr, #1, mul vl]
+ st1b z3.b, p3, [dest_ptr, #2, mul vl]
+ st1b z4.b, p4, [dest_ptr, #3, mul vl]
+2: add dest_ptr, dest_ptr, cl_remainder
+ add src_ptr, src_ptr, cl_remainder
+ sub rest, rest, cl_remainder
+
+L(L2_dc_zva):
+ // zero fill
+ and tmp1, dest, 0xffffffffffffff
+ and tmp2, src, 0xffffffffffffff
+ subs tmp1, tmp1, tmp2 // diff
+ b.ge 1f
+ neg tmp1, tmp1
+1: mov tmp3, ZF_DIST + CACHE_LINE_SIZE * 2
+ cmp tmp1, tmp3
+ b.lo L(unroll8)
+ mov tmp1, dest_ptr
+ dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1
+ // unroll
+ ld1b_unroll8 // this line has to be after "b.lo L(unroll8)"
+ add src_ptr, src_ptr, CACHE_LINE_SIZE * 2
+ sub rest, rest, CACHE_LINE_SIZE * 2
+ mov tmp1, ZF_DIST
+ .p2align 3
+1: stld1b_unroll4a
+ add tmp2, dest_ptr, tmp1 // dest_ptr + ZF_DIST
+ dc zva, tmp2
+ stld1b_unroll4b
+ add tmp2, tmp2, CACHE_LINE_SIZE
+ dc zva, tmp2
+ add dest_ptr, dest_ptr, CACHE_LINE_SIZE * 2
+ add src_ptr, src_ptr, CACHE_LINE_SIZE * 2
+ sub rest, rest, CACHE_LINE_SIZE * 2
+ cmp rest, tmp3 // ZF_DIST + CACHE_LINE_SIZE * 2
+ b.ge 1b
+ st1b_unroll8
+ add dest_ptr, dest_ptr, CACHE_LINE_SIZE * 2
+ b L(unroll8)
+
+END (MEMCPY)
+libc_hidden_builtin_def (MEMCPY)
+
+
+ENTRY (MEMMOVE)
+
+ PTR_ARG (0)
+ PTR_ARG (1)
+ SIZE_ARG (2)
+
+ // remove tag address
+ // dest has to be immutable because it is the return value
+ // src has to be immutable because it is used in L(bwd_last)
+ and tmp2, dest, 0xffffffffffffff // save dest_notag into tmp2
+ and tmp3, src, 0xffffffffffffff // save src_notag intp tmp3
+ cmp n, 0
+ ccmp tmp2, tmp3, 4, ne
+ b.ne 1f
+ ret
+1: cntb vector_length
+ // shortcut for less than vector_length * 8
+ // gives a free ptrue to p0.b for n >= vector_length
+ // tmp2 and tmp3 should not be used in this macro to keep
+ // notag addresses
+ shortcut_for_small_size L(dispatch)
+ // end of shortcut
+
+L(dispatch):
+ // tmp2 = dest_notag, tmp3 = src_notag
+ // diff = dest_notag - src_notag
+ sub tmp1, tmp2, tmp3
+ // if diff <= 0 || diff >= n then memcpy
+ cmp tmp1, 0
+ ccmp tmp1, n, 2, gt
+ b.cs L(vl_agnostic)
+
+L(bwd_start):
+ mov rest, n
+ add dest_ptr, dest, n // dest_end
+ add src_ptr, src, n // src_end
+
+L(bwd_unroll8): // unrolling and software pipeline
+ lsl tmp1, vector_length, 3 // vector_length * 8
+ .p2align 3
+ cmp rest, tmp1
+ b.cc L(bwd_last)
+ sub src_ptr, src_ptr, tmp1
+ ld1b_unroll8
+ sub rest, rest, tmp1
+ cmp rest, tmp1
+ b.cc 2f
+ .p2align 3
+1: sub src_ptr, src_ptr, tmp1
+ sub dest_ptr, dest_ptr, tmp1
+ stld1b_unroll8
+ sub rest, rest, tmp1
+ cmp rest, tmp1
+ b.ge 1b
+2: sub dest_ptr, dest_ptr, tmp1
+ st1b_unroll8
+
+L(bwd_last):
+ mov dest_ptr, dest
+ mov src_ptr, src
+ b L(last)
+
+END (MEMMOVE)
+libc_hidden_builtin_def (MEMMOVE)
+# endif /* IS_IN (libc) */
+#endif /* HAVE_AARCH64_SVE_ASM */
diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c
index e69d8162910b938e..d96612b9cf7c3a4e 100644
--- a/sysdeps/aarch64/multiarch/memmove.c
+++ b/sysdeps/aarch64/multiarch/memmove.c
@@ -31,14 +31,22 @@ extern __typeof (__redirect_memmove) __libc_memmove;
extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
+# if HAVE_AARCH64_SVE_ASM
+extern __typeof (__redirect_memmove) __memmove_a64fx attribute_hidden;
+# endif
libc_ifunc (__libc_memmove,
(IS_THUNDERX (midr)
? __memmove_thunderx
: (IS_FALKOR (midr) || IS_PHECDA (midr)
? __memmove_falkor
+# if HAVE_AARCH64_SVE_ASM
+ : (IS_A64FX (midr)
+ ? __memmove_a64fx
+ : __memmove_generic))));
+# else
: __memmove_generic)));
-
+# endif
# undef memmove
strong_alias (__libc_memmove, memmove);
#endif
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index b4f348509eb1c6b3..71e4355c972f1ffb 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -36,6 +36,7 @@ static struct cpu_list cpu_list[] = {
{"thunderx2t99", 0x431F0AF0},
{"thunderx2t99p1", 0x420F5160},
{"phecda", 0x680F0000},
+ {"a64fx", 0x460F0010},
{"generic", 0x0}
};
@@ -80,4 +81,7 @@ init_cpu_features (struct cpu_features *cpu_features)
if ((dczid & DCZID_DZP_MASK) == 0)
cpu_features->zva_size = 4 << (dczid & DCZID_BS_MASK);
+
+ /* Check if SVE is supported. */
+ cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE;
}
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
index eb35adfbe9d429d5..5691aea6de3cb7f4 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
@@ -20,6 +20,7 @@
#define _CPU_FEATURES_AARCH64_H
#include <stdint.h>
+#include <stdbool.h>
#define MIDR_PARTNUM_SHIFT 4
#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT)
@@ -52,10 +53,14 @@
#define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h' \
&& MIDR_PARTNUM(midr) == 0x000)
+#define IS_A64FX(midr) (MIDR_IMPLEMENTOR(midr) == 'F' \
+ && MIDR_PARTNUM(midr) == 0x001)
+
struct cpu_features
{
uint64_t midr_el1;
unsigned zva_size;
+ bool sve;
};
#endif /* _CPU_FEATURES_AARCH64_H */

View File

@ -0,0 +1,371 @@
commit 4f26956d5ba394eb3ade6c1c20b5c16864a00766
Author: Naohiro Tamura <naohirot@jp.fujitsu.com>
Date: Thu May 27 07:44:12 2021 +0000
aarch64: Added optimized memset for A64FX
This patch optimizes the performance of memset for A64FX [1] which
implements ARMv8-A SVE and has L1 64KB cache per core and L2 8MB cache
per NUMA node.
The performance optimization makes use of Scalable Vector Register
with several techniques such as loop unrolling, memory access
alignment, cache zero fill and prefetch.
SVE assembler code for memset is implemented as Vector Length Agnostic
code so theoretically it can be run on any SOC which supports ARMv8-A
SVE standard.
We confirmed that all testcases have been passed by running 'make
check' and 'make xcheck' not only on A64FX but also on ThunderX2.
And also we confirmed that the SVE 512 bit vector register performance
is roughly 4 times better than Advanced SIMD 128 bit register and 8
times better than scalar 64 bit register by running 'make bench'.
[1] https://github.com/fujitsu/A64FX
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Reviewed-by: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
Conflicts:
sysdeps/aarch64/multiarch/Makefile
sysdeps/aarch64/multiarch/ifunc-impl-list.c
sysdeps/aarch64/multiarch/memset.c
(all conflicts due to missing other CPU implementations downstream)
diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
index 5a19ba0308e80983..5ff883a8ad8e3067 100644
--- a/sysdeps/aarch64/multiarch/Makefile
+++ b/sysdeps/aarch64/multiarch/Makefile
@@ -1,5 +1,6 @@
ifeq ($(subdir),string)
sysdep_routines += memcpy_generic memcpy_thunderx memcpy_thunderx2 \
memcpy_falkor memcpy_a64fx \
- memmove_falkor memset_generic memset_falkor
+ memmove_falkor memset_generic memset_falkor \
+ memset_a64fx
endif
diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
index f53db12acce37877..53e3e162a1025e40 100644
--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
@@ -37,7 +37,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
INIT_ARCH ();
- /* Support sysdeps/aarch64/multiarch/memcpy.c and memmove.c. */
+ /* Support sysdeps/aarch64/multiarch/memcpy.c, memmove.c and memset.c. */
IFUNC_IMPL (i, name, memcpy,
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx2)
@@ -57,6 +57,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
/* Enable this on non-falkor processors too so that other cores
can do a comparative analysis with __memset_generic. */
IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_falkor)
+#if HAVE_AARCH64_SVE_ASM
+ IFUNC_IMPL_ADD (array, i, memset, sve, __memset_a64fx)
+#endif
IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic))
return i;
diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c
index d74ed3a549a54b10..2c8cc72bb0b18474 100644
--- a/sysdeps/aarch64/multiarch/memset.c
+++ b/sysdeps/aarch64/multiarch/memset.c
@@ -29,12 +29,21 @@
extern __typeof (__redirect_memset) __libc_memset;
extern __typeof (__redirect_memset) __memset_falkor attribute_hidden;
+# if HAVE_AARCH64_SVE_ASM
+extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden;
+# endif
extern __typeof (__redirect_memset) __memset_generic attribute_hidden;
libc_ifunc (__libc_memset,
((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64
? __memset_falkor
+# if HAVE_AARCH64_SVE_ASM
+ : (IS_A64FX (midr)
+ ? __memset_a64fx
+ : __memset_generic)));
+# else
: __memset_generic));
+# endif
# undef memset
strong_alias (__libc_memset, memset);
diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
new file mode 100644
index 0000000000000000..ce54e5418b08c8bc
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
@@ -0,0 +1,268 @@
+/* Optimized memset for Fujitsu A64FX processor.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <sysdeps/aarch64/memset-reg.h>
+
+/* Assumptions:
+ *
+ * ARMv8.2-a, AArch64, unaligned accesses, sve
+ *
+ */
+
+#define L1_SIZE (64*1024) // L1 64KB
+#define L2_SIZE (8*1024*1024) // L2 8MB - 1MB
+#define CACHE_LINE_SIZE 256
+#define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1
+#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance
+#define rest x8
+#define vector_length x9
+#define vl_remainder x10 // vector_length remainder
+#define cl_remainder x11 // CACHE_LINE_SIZE remainder
+
+#if HAVE_AARCH64_SVE_ASM
+# if IS_IN (libc)
+# define MEMSET __memset_a64fx
+
+ .arch armv8.2-a+sve
+
+ .macro dc_zva times
+ dc zva, tmp1
+ add tmp1, tmp1, CACHE_LINE_SIZE
+ .if \times-1
+ dc_zva "(\times-1)"
+ .endif
+ .endm
+
+ .macro st1b_unroll first=0, last=7
+ st1b z0.b, p0, [dst, #\first, mul vl]
+ .if \last-\first
+ st1b_unroll "(\first+1)", \last
+ .endif
+ .endm
+
+ .macro shortcut_for_small_size exit
+ // if rest <= vector_length * 2
+ whilelo p0.b, xzr, count
+ whilelo p1.b, vector_length, count
+ b.last 1f
+ st1b z0.b, p0, [dstin, #0, mul vl]
+ st1b z0.b, p1, [dstin, #1, mul vl]
+ ret
+1: // if rest > vector_length * 8
+ cmp count, vector_length, lsl 3 // vector_length * 8
+ b.hi \exit
+ // if rest <= vector_length * 4
+ lsl tmp1, vector_length, 1 // vector_length * 2
+ whilelo p2.b, tmp1, count
+ incb tmp1
+ whilelo p3.b, tmp1, count
+ b.last 1f
+ st1b z0.b, p0, [dstin, #0, mul vl]
+ st1b z0.b, p1, [dstin, #1, mul vl]
+ st1b z0.b, p2, [dstin, #2, mul vl]
+ st1b z0.b, p3, [dstin, #3, mul vl]
+ ret
+1: // if rest <= vector_length * 8
+ lsl tmp1, vector_length, 2 // vector_length * 4
+ whilelo p4.b, tmp1, count
+ incb tmp1
+ whilelo p5.b, tmp1, count
+ b.last 1f
+ st1b z0.b, p0, [dstin, #0, mul vl]
+ st1b z0.b, p1, [dstin, #1, mul vl]
+ st1b z0.b, p2, [dstin, #2, mul vl]
+ st1b z0.b, p3, [dstin, #3, mul vl]
+ st1b z0.b, p4, [dstin, #4, mul vl]
+ st1b z0.b, p5, [dstin, #5, mul vl]
+ ret
+1: lsl tmp1, vector_length, 2 // vector_length * 4
+ incb tmp1 // vector_length * 5
+ incb tmp1 // vector_length * 6
+ whilelo p6.b, tmp1, count
+ incb tmp1
+ whilelo p7.b, tmp1, count
+ st1b z0.b, p0, [dstin, #0, mul vl]
+ st1b z0.b, p1, [dstin, #1, mul vl]
+ st1b z0.b, p2, [dstin, #2, mul vl]
+ st1b z0.b, p3, [dstin, #3, mul vl]
+ st1b z0.b, p4, [dstin, #4, mul vl]
+ st1b z0.b, p5, [dstin, #5, mul vl]
+ st1b z0.b, p6, [dstin, #6, mul vl]
+ st1b z0.b, p7, [dstin, #7, mul vl]
+ ret
+ .endm
+
+ENTRY (MEMSET)
+
+ PTR_ARG (0)
+ SIZE_ARG (2)
+
+ cbnz count, 1f
+ ret
+1: dup z0.b, valw
+ cntb vector_length
+ // shortcut for less than vector_length * 8
+ // gives a free ptrue to p0.b for n >= vector_length
+ shortcut_for_small_size L(vl_agnostic)
+ // end of shortcut
+
+L(vl_agnostic): // VL Agnostic
+ mov rest, count
+ mov dst, dstin
+ add dstend, dstin, count
+ // if rest >= L2_SIZE && vector_length == 64 then L(L2)
+ mov tmp1, 64
+ cmp rest, L2_SIZE
+ ccmp vector_length, tmp1, 0, cs
+ b.eq L(L2)
+ // if rest >= L1_SIZE && vector_length == 64 then L(L1_prefetch)
+ cmp rest, L1_SIZE
+ ccmp vector_length, tmp1, 0, cs
+ b.eq L(L1_prefetch)
+
+L(unroll32):
+ lsl tmp1, vector_length, 3 // vector_length * 8
+ lsl tmp2, vector_length, 5 // vector_length * 32
+ .p2align 3
+1: cmp rest, tmp2
+ b.cc L(unroll8)
+ st1b_unroll
+ add dst, dst, tmp1
+ st1b_unroll
+ add dst, dst, tmp1
+ st1b_unroll
+ add dst, dst, tmp1
+ st1b_unroll
+ add dst, dst, tmp1
+ sub rest, rest, tmp2
+ b 1b
+
+L(unroll8):
+ lsl tmp1, vector_length, 3
+ .p2align 3
+1: cmp rest, tmp1
+ b.cc L(last)
+ st1b_unroll
+ add dst, dst, tmp1
+ sub rest, rest, tmp1
+ b 1b
+
+L(last):
+ whilelo p0.b, xzr, rest
+ whilelo p1.b, vector_length, rest
+ b.last 1f
+ st1b z0.b, p0, [dst, #0, mul vl]
+ st1b z0.b, p1, [dst, #1, mul vl]
+ ret
+1: lsl tmp1, vector_length, 1 // vector_length * 2
+ whilelo p2.b, tmp1, rest
+ incb tmp1
+ whilelo p3.b, tmp1, rest
+ b.last 1f
+ st1b z0.b, p0, [dst, #0, mul vl]
+ st1b z0.b, p1, [dst, #1, mul vl]
+ st1b z0.b, p2, [dst, #2, mul vl]
+ st1b z0.b, p3, [dst, #3, mul vl]
+ ret
+1: lsl tmp1, vector_length, 2 // vector_length * 4
+ whilelo p4.b, tmp1, rest
+ incb tmp1
+ whilelo p5.b, tmp1, rest
+ incb tmp1
+ whilelo p6.b, tmp1, rest
+ incb tmp1
+ whilelo p7.b, tmp1, rest
+ st1b z0.b, p0, [dst, #0, mul vl]
+ st1b z0.b, p1, [dst, #1, mul vl]
+ st1b z0.b, p2, [dst, #2, mul vl]
+ st1b z0.b, p3, [dst, #3, mul vl]
+ st1b z0.b, p4, [dst, #4, mul vl]
+ st1b z0.b, p5, [dst, #5, mul vl]
+ st1b z0.b, p6, [dst, #6, mul vl]
+ st1b z0.b, p7, [dst, #7, mul vl]
+ ret
+
+L(L1_prefetch): // if rest >= L1_SIZE
+ .p2align 3
+1: st1b_unroll 0, 3
+ prfm pstl1keep, [dst, PF_DIST_L1]
+ st1b_unroll 4, 7
+ prfm pstl1keep, [dst, PF_DIST_L1 + CACHE_LINE_SIZE]
+ add dst, dst, CACHE_LINE_SIZE * 2
+ sub rest, rest, CACHE_LINE_SIZE * 2
+ cmp rest, L1_SIZE
+ b.ge 1b
+ cbnz rest, L(unroll32)
+ ret
+
+L(L2):
+ // align dst address at vector_length byte boundary
+ sub tmp1, vector_length, 1
+ ands tmp2, dst, tmp1
+ // if vl_remainder == 0
+ b.eq 1f
+ sub vl_remainder, vector_length, tmp2
+ // process remainder until the first vector_length boundary
+ whilelt p2.b, xzr, vl_remainder
+ st1b z0.b, p2, [dst]
+ add dst, dst, vl_remainder
+ sub rest, rest, vl_remainder
+ // align dstin address at CACHE_LINE_SIZE byte boundary
+1: mov tmp1, CACHE_LINE_SIZE
+ ands tmp2, dst, CACHE_LINE_SIZE - 1
+ // if cl_remainder == 0
+ b.eq L(L2_dc_zva)
+ sub cl_remainder, tmp1, tmp2
+ // process remainder until the first CACHE_LINE_SIZE boundary
+ mov tmp1, xzr // index
+2: whilelt p2.b, tmp1, cl_remainder
+ st1b z0.b, p2, [dst, tmp1]
+ incb tmp1
+ cmp tmp1, cl_remainder
+ b.lo 2b
+ add dst, dst, cl_remainder
+ sub rest, rest, cl_remainder
+
+L(L2_dc_zva):
+ // zero fill
+ mov tmp1, dst
+ dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1
+ mov zva_len, ZF_DIST
+ add tmp1, zva_len, CACHE_LINE_SIZE * 2
+ // unroll
+ .p2align 3
+1: st1b_unroll 0, 3
+ add tmp2, dst, zva_len
+ dc zva, tmp2
+ st1b_unroll 4, 7
+ add tmp2, tmp2, CACHE_LINE_SIZE
+ dc zva, tmp2
+ add dst, dst, CACHE_LINE_SIZE * 2
+ sub rest, rest, CACHE_LINE_SIZE * 2
+ cmp rest, tmp1 // ZF_DIST + CACHE_LINE_SIZE * 2
+ b.ge 1b
+ cbnz rest, L(unroll8)
+ ret
+
+END (MEMSET)
+libc_hidden_builtin_def (MEMSET)
+
+#endif /* IS_IN (libc) */
+#endif /* HAVE_AARCH64_SVE_ASM */

View File

@ -0,0 +1,159 @@
From 332421312576bd7095e70589154af99b124dd2d1 Mon Sep 17 00:00:00 2001
From: Carlos O'Donell <carlos@redhat.com>
Date: Fri, 12 Mar 2021 16:44:47 +0100
Subject: elf: Always set l in _dl_init_paths (bug 23462)
After d1d5471579eb0426671bf94f2d71e61dfb204c30 ("Remove dead
DL_DST_REQ_STATIC code.") we always setup the link map l to make the
static and shared cases the same. The bug is that in elf/dl-load.c
(_dl_init_paths) we conditionally set l only in the #ifdef SHARED
case, but unconditionally use it later. The simple solution is to
remove the #ifdef SHARED conditional, because it's no longer needed,
and unconditionally setup l for both the static and shared cases. A
regression test is added to run a static binary with
LD_LIBRARY_PATH='$ORIGIN' which crashes before the fix and runs after
the fix.
Co-Authored-By: Florian Weimer <fweimer@redhat.com>
diff --git a/elf/Makefile b/elf/Makefile
--- a/elf/Makefile 2021-11-02 16:28:14.720143774 -0400
+++ b/elf/Makefile 2021-11-02 18:42:38.763843571 -0400
@@ -151,7 +151,8 @@ endif
tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \
tst-dl-iter-static \
tst-tlsalign-static tst-tlsalign-extern-static \
- tst-linkall-static tst-env-setuid tst-env-setuid-tunables
+ tst-linkall-static tst-env-setuid tst-env-setuid-tunables \
+ tst-dst-static
tests-static-internal := tst-tls1-static tst-tls2-static \
tst-ptrguard1-static tst-stackguard1-static \
tst-tls1-static-non-pie tst-libc_dlvsym-static
@@ -1811,3 +1812,5 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \
# Generic dependency for sysdeps implementation of
# tst-glibc-hwcaps-cache.
$(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps
+
+tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN'
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 9e2089cfaa..376a2e64d6 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -758,50 +758,45 @@ _dl_init_paths (const char *llp, const char *source,
max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
*aelem = NULL;
-#ifdef SHARED
/* This points to the map of the main object. */
l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
- if (l != NULL)
+ assert (l->l_type != lt_loaded);
+
+ if (l->l_info[DT_RUNPATH])
+ {
+ /* Allocate room for the search path and fill in information
+ from RUNPATH. */
+ decompose_rpath (&l->l_runpath_dirs,
+ (const void *) (D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_RUNPATH]->d_un.d_val),
+ l, "RUNPATH");
+ /* During rtld init the memory is allocated by the stub malloc,
+ prevent any attempt to free it by the normal malloc. */
+ l->l_runpath_dirs.malloced = 0;
+
+ /* The RPATH is ignored. */
+ l->l_rpath_dirs.dirs = (void *) -1;
+ }
+ else
{
- assert (l->l_type != lt_loaded);
+ l->l_runpath_dirs.dirs = (void *) -1;
- if (l->l_info[DT_RUNPATH])
+ if (l->l_info[DT_RPATH])
{
/* Allocate room for the search path and fill in information
- from RUNPATH. */
- decompose_rpath (&l->l_runpath_dirs,
+ from RPATH. */
+ decompose_rpath (&l->l_rpath_dirs,
(const void *) (D_PTR (l, l_info[DT_STRTAB])
- + l->l_info[DT_RUNPATH]->d_un.d_val),
- l, "RUNPATH");
- /* During rtld init the memory is allocated by the stub malloc,
- prevent any attempt to free it by the normal malloc. */
- l->l_runpath_dirs.malloced = 0;
-
- /* The RPATH is ignored. */
- l->l_rpath_dirs.dirs = (void *) -1;
+ + l->l_info[DT_RPATH]->d_un.d_val),
+ l, "RPATH");
+ /* During rtld init the memory is allocated by the stub
+ malloc, prevent any attempt to free it by the normal
+ malloc. */
+ l->l_rpath_dirs.malloced = 0;
}
else
- {
- l->l_runpath_dirs.dirs = (void *) -1;
-
- if (l->l_info[DT_RPATH])
- {
- /* Allocate room for the search path and fill in information
- from RPATH. */
- decompose_rpath (&l->l_rpath_dirs,
- (const void *) (D_PTR (l, l_info[DT_STRTAB])
- + l->l_info[DT_RPATH]->d_un.d_val),
- l, "RPATH");
- /* During rtld init the memory is allocated by the stub
- malloc, prevent any attempt to free it by the normal
- malloc. */
- l->l_rpath_dirs.malloced = 0;
- }
- else
- l->l_rpath_dirs.dirs = (void *) -1;
- }
+ l->l_rpath_dirs.dirs = (void *) -1;
}
-#endif /* SHARED */
if (llp != NULL && *llp != '\0')
{
diff --git a/elf/tst-dst-static.c b/elf/tst-dst-static.c
new file mode 100644
index 0000000000..56eb371c96
--- /dev/null
+++ b/elf/tst-dst-static.c
@@ -0,0 +1,32 @@
+/* Test DST expansion for static binaries doesn't carsh. Bug 23462.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* The purpose of this test is to exercise the code in elf/dl-loac.c
+ (_dl_init_paths) or thereabout and ensure that static binaries
+ don't crash when expanding DSTs.
+
+ If the dynamic loader code linked into the static binary cannot
+ handle expanding the DSTs e.g. null-deref on an incomplete link
+ map, then it will crash before reaching main, so the test harness
+ is unnecessary. */
+
+int
+main (void)
+{
+ return 0;
+}

View File

@ -0,0 +1,74 @@
From 4e6db99c665d3b82a70a3e218860ef087b1555b4 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Mon, 15 Mar 2021 10:33:43 +0100
Subject: elf: ld.so --help calls _dl_init_paths without a main map [BZ #27577]
In this case, use the link map of the dynamic loader itself as
a replacement. This is more than just a hack: if we ever support
DT_RUNPATH/DT_RPATH for the dynamic loader, reporting it for
ld.so --help (without further command line arguments) would be the
right thing to do.
Fixes commit 332421312576bd7095e70589154af99b124dd2d1 ("elf: Always
set l in _dl_init_paths (bug 23462)").
diff --git a/elf/Makefile b/elf/Makefile
index 4c9e63dac9..ba4689a7fa 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -231,7 +231,7 @@ tests += $(tests-execstack-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-leaks1-mem.out \
$(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
- $(objpfx)tst-ldconfig-X.out
+ $(objpfx)tst-ldconfig-X.out $(objpfx)tst-rtld-help.out
endif
tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
@@ -409,7 +409,8 @@ endif
ifeq (yes,$(build-shared))
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \
- $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out
+ $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out \
+ $(objpfx)tst-rtld-help.out
endif
tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
$(objpfx)check-wx-segment.out \
@@ -1814,3 +1815,16 @@ $(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so
$(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps
tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN'
+
+$(objpfx)tst-rtld-help.out: $(objpfx)ld.so
+ $(test-wrapper) $(rtld-prefix) --help > $@; \
+ status=$$?; \
+ echo "info: ld.so exit status: $$status" >> $@; \
+ if ! grep -q 'Legacy HWCAP subdirectories under library search path directories' $@; then \
+ echo "error: missing subdirectory pattern" >> $@; \
+ if test $$status -eq 0; then \
+ status=1; \
+ fi; \
+ fi; \
+ (exit $$status); \
+ $(evaluate-test)
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 376a2e64d6..2f760503c5 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -758,8 +758,14 @@ _dl_init_paths (const char *llp, const char *source,
max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
*aelem = NULL;
- /* This points to the map of the main object. */
+ /* This points to the map of the main object. If there is no main
+ object (e.g., under --help, use the dynamic loader itself as a
+ stand-in. */
l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+#ifdef SHARED
+ if (l == NULL)
+ l = &GL (dl_rtld_map);
+#endif
assert (l->l_type != lt_loaded);
if (l->l_info[DT_RUNPATH])

View File

@ -0,0 +1,90 @@
Based on the following commit, adjusted for glibc-2.28 in RHEL-8:
commit 27f74636752d0c4438cf8346cf2a76b6fcf3be16
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Fri Mar 19 06:15:37 2021 -0700
x86: Properly disable XSAVE related features [BZ #27605]
1. Support GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVE.
2. Disable all features which depend on XSAVE:
a. If OSXSAVE is disabled by glibc tunables. Or
b. If both XSAVE and XSAVEC aren't usable.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 805d00a43309fc23..910425053d9e226f 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -654,6 +654,60 @@ no_cpuid:
= TUNABLE_GET (x86_data_cache_size, long int, NULL);
cpu_features->shared_cache_size
= TUNABLE_GET (x86_shared_cache_size, long int, NULL);
+
+ bool disable_xsave_features = false;
+
+ if (!CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE))
+ {
+ /* These features are usable only if OSXSAVE is usable. */
+ CPU_FEATURE_UNSET (cpu_features, XSAVE);
+ CPU_FEATURE_UNSET (cpu_features, XSAVEOPT);
+ CPU_FEATURE_UNSET (cpu_features, XSAVEC);
+ CPU_FEATURE_UNSET (cpu_features, XGETBV_ECX_1);
+ CPU_FEATURE_UNSET (cpu_features, XFD);
+
+ disable_xsave_features = true;
+ }
+
+ if (disable_xsave_features
+ || (!CPU_FEATURE_USABLE_P (cpu_features, XSAVE)
+ && !CPU_FEATURE_USABLE_P (cpu_features, XSAVEC)))
+ {
+ /* Clear xsave_state_size if both XSAVE and XSAVEC aren't usable. */
+ cpu_features->xsave_state_size = 0;
+
+ CPU_FEATURE_UNSET (cpu_features, AVX);
+ CPU_FEATURE_UNSET (cpu_features, AVX2);
+ CPU_FEATURE_UNSET (cpu_features, AVX_VNNI);
+ CPU_FEATURE_UNSET (cpu_features, FMA);
+ CPU_FEATURE_UNSET (cpu_features, VAES);
+ CPU_FEATURE_UNSET (cpu_features, VPCLMULQDQ);
+ CPU_FEATURE_UNSET (cpu_features, XOP);
+ CPU_FEATURE_UNSET (cpu_features, F16C);
+ CPU_FEATURE_UNSET (cpu_features, AVX512F);
+ CPU_FEATURE_UNSET (cpu_features, AVX512CD);
+ CPU_FEATURE_UNSET (cpu_features, AVX512ER);
+ CPU_FEATURE_UNSET (cpu_features, AVX512PF);
+ CPU_FEATURE_UNSET (cpu_features, AVX512VL);
+ CPU_FEATURE_UNSET (cpu_features, AVX512DQ);
+ CPU_FEATURE_UNSET (cpu_features, AVX512BW);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_4FMAPS);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_4VNNIW);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_BITALG);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_IFMA);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_VBMI2);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_VNNI);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_VPOPCNTDQ);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_VP2INTERSECT);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_BF16);
+ CPU_FEATURE_UNSET (cpu_features, AVX512_FP16);
+ CPU_FEATURE_UNSET (cpu_features, AMX_BF16);
+ CPU_FEATURE_UNSET (cpu_features, AMX_TILE);
+ CPU_FEATURE_UNSET (cpu_features, AMX_INT8);
+
+ CPU_FEATURE_UNSET (cpu_features, FMA4);
+ }
#endif
/* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index 0728023007a0f423..3173b2b959ca88f9 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -168,6 +168,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, MOVBE, 5);
CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SHSTK, 5);
CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSSE3, 5);
+ CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, XSAVE, 5);
}
break;
case 6:

View File

@ -0,0 +1,102 @@
commit 0c78b0bb78d87a7de18726a033d88904f158f0fe
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Jun 7 14:22:17 2021 +0530
iconvconfig: Make file handling more general purpose
Split out configuration file handling code from handle_dir into its
own function so that it can be reused for multiple configuration
files.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index b6fef1553cbbdd3d..2b3c587bc77cfdcd 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -644,37 +644,17 @@ add_module (char *rp, const char *directory)
cost, need_ext);
}
-
-/* Read the config file and add the data for this directory to that. */
-static int
-handle_dir (const char *dir)
+/* Read a gconv-modules configuration file. */
+static bool
+handle_file (const char *dir, const char *infile)
{
- char *cp;
FILE *fp;
char *line = NULL;
size_t linelen = 0;
- size_t dirlen = strlen (dir);
-
- if (dir[dirlen - 1] != '/')
- {
- char *newp = (char *) xmalloc (dirlen + 2);
- dir = memcpy (newp, dir, dirlen);
- newp[dirlen++] = '/';
- newp[dirlen] = '\0';
- }
-
- char infile[prefix_len + dirlen + sizeof "gconv-modules"];
- cp = infile;
- if (dir[0] == '/')
- cp = mempcpy (cp, prefix, prefix_len);
- strcpy (mempcpy (cp, dir, dirlen), "gconv-modules");
fp = fopen (infile, "r");
if (fp == NULL)
- {
- error (0, errno, "cannot open `%s'", infile);
- return 1;
- }
+ return false;
/* No threads present. */
__fsetlocking (fp, FSETLOCKING_BYCALLER);
@@ -723,7 +703,42 @@ handle_dir (const char *dir)
fclose (fp);
- return 0;
+ return true;
+}
+
+/* Read config files and add the data for this directory to cache. */
+static int
+handle_dir (const char *dir)
+{
+ char *cp;
+ size_t dirlen = strlen (dir);
+ bool found = false;
+
+ if (dir[dirlen - 1] != '/')
+ {
+ char *newp = (char *) xmalloc (dirlen + 2);
+ dir = memcpy (newp, dir, dirlen);
+ newp[dirlen++] = '/';
+ newp[dirlen] = '\0';
+ }
+
+ char infile[prefix_len + dirlen + sizeof "gconv-modules"];
+ cp = infile;
+ if (dir[0] == '/')
+ cp = mempcpy (cp, prefix, prefix_len);
+ strcpy (mempcpy (cp, dir, dirlen), "gconv-modules");
+
+ found |= handle_file (dir, infile);
+
+ if (!found)
+ {
+ error (0, errno, "failed to open gconv configuration file in `%s'",
+ dir);
+ error (0, 0,
+ "ensure that the directory contains a valid gconv-modules file.");
+ }
+
+ return found ? 0 : 1;
}

View File

@ -0,0 +1,188 @@
commit eeac390eecf7de24a110dc84e77e1190f42c5305
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Jun 10 14:31:57 2021 +0530
iconvconfig: Use common gconv module parsing function
Drop local copy of gconv file parsing and use the one in
gconv_parseconfdir.h instead. Now there is a single implementation of
configuration file parsing.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index 2f9d5f45ad3a8159..01ecf6f67d55dbbf 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -18,7 +18,6 @@
#include <argp.h>
#include <assert.h>
-#include <dirent.h>
#include <error.h>
#include <errno.h>
#include <fcntl.h>
@@ -34,10 +33,10 @@
#include <string.h>
#include <unistd.h>
#include <sys/cdefs.h>
-#include <sys/types.h>
#include <sys/uio.h>
#include "iconvconfig.h"
+#include <gconv_parseconfdir.h>
/* Get libc version number. */
#include "../version.h"
@@ -568,7 +567,9 @@ new_module (const char *fromname, size_t fromlen, const char *toname,
/* Add new module. */
static void
-add_module (char *rp, const char *directory)
+add_module (char *rp, const char *directory,
+ size_t dirlen __attribute__ ((__unused__)),
+ int modcount __attribute__ ((__unused__)))
{
/* We expect now
1. `from' name
@@ -646,131 +647,28 @@ add_module (char *rp, const char *directory)
cost, need_ext);
}
-/* Read a gconv-modules configuration file. */
-static bool
-handle_file (const char *dir, const char *infile)
-{
- FILE *fp;
- char *line = NULL;
- size_t linelen = 0;
-
- fp = fopen (infile, "r");
- if (fp == NULL)
- return false;
-
- /* No threads present. */
- __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
- while (!feof_unlocked (fp))
- {
- char *rp, *endp, *word;
- ssize_t n = __getdelim (&line, &linelen, '\n', fp);
-
- if (n < 0)
- /* An error occurred. */
- break;
-
- rp = line;
- /* Terminate the line (excluding comments or newline) with a NUL
- byte to simplify the following code. */
- endp = strchr (rp, '#');
- if (endp != NULL)
- *endp = '\0';
- else
- if (rp[n - 1] == '\n')
- rp[n - 1] = '\0';
-
- while (isspace (*rp))
- ++rp;
-
- /* If this is an empty line go on with the next one. */
- if (rp == endp)
- continue;
-
- word = rp;
- while (*rp != '\0' && !isspace (*rp))
- ++rp;
-
- if (rp - word == sizeof ("alias") - 1
- && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
- add_alias (rp);
- else if (rp - word == sizeof ("module") - 1
- && memcmp (word, "module", sizeof ("module") - 1) == 0)
- add_module (rp, dir);
- /* else */
- /* Otherwise ignore the line. */
- }
-
- free (line);
-
- fclose (fp);
-
- return true;
-}
-
/* Read config files and add the data for this directory to cache. */
static int
handle_dir (const char *dir)
{
- char *cp;
size_t dirlen = strlen (dir);
bool found = false;
+ /* Add the prefix before sending it off to the parser. */
+ char *fulldir = xmalloc (prefix_len + dirlen + 2);
+ char *cp = mempcpy (mempcpy (fulldir, prefix, prefix_len), dir, dirlen);
+
if (dir[dirlen - 1] != '/')
{
- char *newp = (char *) xmalloc (dirlen + 2);
- dir = memcpy (newp, dir, dirlen);
- newp[dirlen++] = '/';
- newp[dirlen] = '\0';
+ *cp++ = '/';
+ *cp = '\0';
+ dirlen++;
}
- /* First, look for a gconv-modules file. */
- char *buf = malloc (prefix_len + dirlen + sizeof "gconv-modules.d");
- if (buf == NULL)
- goto out;
-
- cp = buf;
- if (dir[0] == '/')
- cp = mempcpy (cp, prefix, prefix_len);
- cp = mempcpy (cp, dir, dirlen);
- cp = stpcpy (cp, "gconv-modules");
-
- found |= handle_file (dir, buf);
-
- /* Next, see if there is a gconv-modules.d directory containing configuration
- files and if it is non-empty. */
- cp[0] = '.';
- cp[1] = 'd';
- cp[2] = '\0';
-
- DIR *confdir = opendir (buf);
- if (confdir != NULL)
- {
- struct dirent *ent;
- while ((ent = readdir (confdir)) != NULL)
- {
- if (ent->d_type != DT_REG)
- continue;
-
- size_t len = strlen (ent->d_name);
- const char *suffix = ".conf";
-
- if (len > strlen (suffix)
- && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
- {
- char *conf;
- if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
- continue;
- found |= handle_file (dir, conf);
- free (conf);
- }
- }
- closedir (confdir);
- }
+ found = gconv_parseconfdir (fulldir, dirlen + prefix_len);
- free (buf);
+ free (fulldir);
-out:
if (!found)
{
error (0, errno, "failed to open gconv configuration files in `%s'",

View File

@ -0,0 +1,53 @@
Changes specific to RHEL-8:
- lstat64 is a macro, so undefine it first
commit f3629a4be82a393ff56646c388da2fda0101f557
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Jun 10 14:56:37 2021 +0530
Handle DT_UNKNOWN in gconv-modules.d
On filesystems that do not support dt_type, a regular file shows up as
DT_UNKNOWN. Fall back to using lstat64 to read file properties in
such cases.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index 3d4d58d4be10a250..ba9b3fd36d9e30f9 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -32,6 +32,8 @@
# define readdir __readdir
# define closedir __closedir
# define mempcpy __mempcpy
+# undef lstat64
+# define lstat64 __lstat64
#endif
/* Name of the file containing the module information in the directories
@@ -138,7 +140,7 @@ gconv_parseconfdir (const char *dir, size_t dir_len)
struct dirent *ent;
while ((ent = readdir (confdir)) != NULL)
{
- if (ent->d_type != DT_REG)
+ if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
continue;
size_t len = strlen (ent->d_name);
@@ -148,8 +150,14 @@ gconv_parseconfdir (const char *dir, size_t dir_len)
&& strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
{
char *conf;
+ struct stat64 st;
if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
continue;
+ if (ent->d_type == DT_UNKNOWN
+ && (lstat64 (conf, &st) == -1
+ || !S_ISREG (st.st_mode)))
+ continue;
+
found |= read_conf_file (conf, dir, dir_len);
free (conf);
}

View File

@ -0,0 +1,98 @@
commit 9429049c178b3af3d6afeb3717ff1f2214dc9572
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Jun 28 09:15:55 2021 +0530
iconvconfig: Fix multiple issues
It was noticed on big-endian systems that msgfmt would fail with the
following error:
msgfmt: gconv_builtin.c:70: __gconv_get_builtin_trans: Assertion `cnt < sizeof (map) / sizeof (map[0])' failed.
Aborted (core dumped)
This is only seen on installed systems because it was due to a
corrupted gconv-modules.cache. iconvconfig had the following issues
(it was specifically freeing fulldir that caused this issue, but other
cleanups are also needed) that this patch fixes.
- Add prefix only if dir starts with '/'
- Use asprintf instead of mempcpy so that the directory string is NULL
terminated
- Make a copy of the directory reference in new_module so that fulldir
can be freed within the same scope in handle_dir.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/iconv/Makefile b/iconv/Makefile
index d09b8ac842731780..6df9862e748ae588 100644
--- a/iconv/Makefile
+++ b/iconv/Makefile
@@ -33,7 +33,7 @@ vpath %.c ../locale/programs ../intl
iconv_prog-modules = iconv_charmap charmap charmap-dir linereader \
dummy-repertoire simple-hash xstrdup xmalloc \
record-status
-iconvconfig-modules = strtab xmalloc hash-string
+iconvconfig-modules = strtab xmalloc xasprintf xstrdup hash-string
extra-objs = $(iconv_prog-modules:=.o) $(iconvconfig-modules:=.o)
CFLAGS-iconv_prog.c += -I../locale/programs
CFLAGS-iconv_charmap.c += -I../locale/programs
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index 01ecf6f67d55dbbf..777da870d2f8e99a 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -250,6 +250,7 @@ static const char gconv_module_ext[] = MODULE_EXT;
#include <programs/xmalloc.h>
+#include <programs/xasprintf.h>
/* C string table handling. */
@@ -519,11 +520,12 @@ module_compare (const void *p1, const void *p2)
/* Create new module record. */
static void
new_module (const char *fromname, size_t fromlen, const char *toname,
- size_t tolen, const char *directory,
+ size_t tolen, const char *dir_in,
const char *filename, size_t filelen, int cost, size_t need_ext)
{
struct module *new_module;
- size_t dirlen = strlen (directory) + 1;
+ size_t dirlen = strlen (dir_in) + 1;
+ const char *directory = xstrdup (dir_in);
char *tmp;
void **inserted;
@@ -654,20 +656,10 @@ handle_dir (const char *dir)
size_t dirlen = strlen (dir);
bool found = false;
- /* Add the prefix before sending it off to the parser. */
- char *fulldir = xmalloc (prefix_len + dirlen + 2);
- char *cp = mempcpy (mempcpy (fulldir, prefix, prefix_len), dir, dirlen);
+ char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
+ dir, dir[dirlen - 1] != '/' ? "/" : "");
- if (dir[dirlen - 1] != '/')
- {
- *cp++ = '/';
- *cp = '\0';
- dirlen++;
- }
-
- found = gconv_parseconfdir (fulldir, dirlen + prefix_len);
-
- free (fulldir);
+ found = gconv_parseconfdir (fulldir, strlen (fulldir));
if (!found)
{
@@ -679,6 +671,8 @@ handle_dir (const char *dir)
"configuration files with names ending in .conf.");
}
+ free (fulldir);
+
return found ? 0 : 1;
}

View File

@ -0,0 +1,34 @@
commit 7f784fabcb186ffaa082ed0aeed52a56b7d96cee
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Fri Jul 2 16:53:25 2021 +0530
iconvconfig: Use the public feof_unlocked
Build of iconvconfig failed with CFLAGS=-Os since __feof_unlocked is
not a public symbol. Replace with feof_unlocked (defined to
__feof_unlocked when IS_IN (libc)) to fix this.
Reported-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index ba9b3fd36d9e30f9..234b85a586f1d79a 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -34,6 +34,7 @@
# define mempcpy __mempcpy
# undef lstat64
# define lstat64 __lstat64
+# define feof_unlocked __feof_unlocked
#endif
/* Name of the file containing the module information in the directories
@@ -65,7 +66,7 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len)
/* Process the known entries of the file. Comments start with `#' and
end with the end of the line. Empty lines are ignored. */
- while (!__feof_unlocked (fp))
+ while (!feof_unlocked (fp))
{
char *rp, *endp, *word;
ssize_t n = __getdelim (&line, &line_len, '\n', fp);

View File

@ -0,0 +1,32 @@
commit 5f9b78fe35d08739b6da1e5b356786d41116c108
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue Aug 3 21:10:20 2021 +0530
gconv_parseconfdir: Fix memory leak
The allocated `conf` would leak if we have to skip over the file due
to the underlying filesystem not supporting dt_type.
Reviewed-by: Arjun Shankar <arjun@redhat.com>
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index 915b60845ca11c03..e4c3c16d1f96ce0c 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -153,12 +153,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len)
struct stat64 st;
if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
continue;
- if (ent->d_type == DT_UNKNOWN
- && (lstat64 (conf, &st) == -1
- || !S_ISREG (st.st_mode)))
- continue;
- found |= read_conf_file (conf, dir, dir_len);
+ if (ent->d_type != DT_UNKNOWN
+ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
+ found |= read_conf_file (conf, dir, dir_len);
+
free (conf);
}
}

View File

@ -0,0 +1,116 @@
commit 43cea6d5652b6b9e61ac6ecc69419c909b504f47
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Sep 13 20:48:35 2021 +0530
iconvconfig: Fix behaviour with --prefix [BZ #28199]
The consolidation of configuration parsing broke behaviour with
--prefix, where the prefix bled into the modules cache. Accept a
prefix which, when non-NULL, is prepended to the path when looking for
configuration files but only the original directory is added to the
modules cache.
This has no effect on the codegen of gconv_conf since it passes NULL.
Reported-by: Patrick McCarty <patrick.mccarty@intel.com>
Reported-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
Reviewed-by: Andreas Schwab <schwab@linux-m68k.org>
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index ce64faa928dc1c52..3f5a692f1510157c 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -476,7 +476,7 @@ __gconv_read_conf (void)
__gconv_get_path ();
for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
- gconv_parseconfdir (__gconv_path_elem[cnt].name,
+ gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name,
__gconv_path_elem[cnt].len);
#endif
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index e4c3c16d1f96ce0c..433aa18bab5083b0 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -39,7 +39,6 @@
/* Name of the file containing the module information in the directories
along the path. */
static const char gconv_conf_filename[] = "gconv-modules";
-static const char gconv_conf_dirname[] = "gconv-modules.d";
static void add_alias (char *);
static void add_module (char *, const char *, size_t, int);
@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len)
return true;
}
+/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and
+ parse configuration in it. */
+
static __always_inline bool
-gconv_parseconfdir (const char *dir, size_t dir_len)
+gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
{
- /* No slash needs to be inserted between dir and gconv_conf_filename;
- dir already ends in a slash. */
- char *buf = malloc (dir_len + sizeof (gconv_conf_dirname));
+ /* No slash needs to be inserted between dir and gconv_conf_filename; dir
+ already ends in a slash. The additional 2 is to accommodate the ".d"
+ when looking for configuration files in gconv-modules.d. */
+ size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2;
+ char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0));
+ char *cp = buf;
bool found = false;
if (buf == NULL)
return false;
- char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename,
- sizeof (gconv_conf_filename));
+ if (prefix != NULL)
+ cp = stpcpy (cp, prefix);
+
+ cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename,
+ sizeof (gconv_conf_filename));
/* Read the gconv-modules configuration file first. */
found = read_conf_file (buf, dir, dir_len);
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index 777da870d2f8e99a..b1fd4100b5cbc9d2 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory,
static int
handle_dir (const char *dir)
{
+ char *newp = NULL;
size_t dirlen = strlen (dir);
bool found = false;
- char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
- dir, dir[dirlen - 1] != '/' ? "/" : "");
+ /* End directory path with a '/' if it doesn't already. */
+ if (dir[dirlen - 1] != '/')
+ {
+ newp = xmalloc (dirlen + 2);
+ memcpy (newp, dir, dirlen);
+ newp[dirlen++] = '/';
+ newp[dirlen] = '\0';
+ dir = newp;
+ }
- found = gconv_parseconfdir (fulldir, strlen (fulldir));
+ found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen);
if (!found)
{
@@ -671,7 +679,7 @@ handle_dir (const char *dir)
"configuration files with names ending in .conf.");
}
- free (fulldir);
+ free (newp);
return found ? 0 : 1;
}

View File

@ -0,0 +1,109 @@
commit 3979c3e1bae20459d9b6d424bdb49927d9cd6fec
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Jun 7 14:22:18 2021 +0530
iconvconfig: Read configuration from gconv-modules.d subdirectory
In addition to GCONV_PATH/gconv-modules, also read module
configuration from *.conf files in GCONV_PATH/gconv-modules.d. This
allows a single gconv directory to have multiple sets of gconv modules
but at the same time, a single modules cache.
With this feature, one could separate the glibc supported gconv
modules into a minimal essential set (ISO-8859-*, UTF, etc.) from the
remaining modules. In future, these could be further segregated into
langpack-associated sets with their own
gconv-modules.d/someconfig.conf.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index 2b3c587bc77cfdcd..fafc686ae25fb5c1 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -18,6 +18,7 @@
#include <argp.h>
#include <assert.h>
+#include <dirent.h>
#include <error.h>
#include <errno.h>
#include <fcntl.h>
@@ -33,6 +34,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/cdefs.h>
+#include <sys/types.h>
#include <sys/uio.h>
#include "iconvconfig.h"
@@ -710,6 +712,7 @@ handle_file (const char *dir, const char *infile)
static int
handle_dir (const char *dir)
{
+#define BUF_LEN prefix_len + dirlen + sizeof "gconv-modules.d"
char *cp;
size_t dirlen = strlen (dir);
bool found = false;
@@ -722,20 +725,55 @@ handle_dir (const char *dir)
newp[dirlen] = '\0';
}
- char infile[prefix_len + dirlen + sizeof "gconv-modules"];
- cp = infile;
+ /* First, look for a gconv-modules file. */
+ char buf[BUF_LEN];
+ cp = buf;
if (dir[0] == '/')
cp = mempcpy (cp, prefix, prefix_len);
- strcpy (mempcpy (cp, dir, dirlen), "gconv-modules");
+ cp = mempcpy (cp, dir, dirlen);
+ cp = stpcpy (cp, "gconv-modules");
- found |= handle_file (dir, infile);
+ found |= handle_file (dir, buf);
+
+ /* Next, see if there is a gconv-modules.d directory containing configuration
+ files and if it is non-empty. */
+ cp[0] = '.';
+ cp[1] = 'd';
+ cp[2] = '\0';
+
+ DIR *confdir = opendir (buf);
+ if (confdir != NULL)
+ {
+ struct dirent *ent;
+ while ((ent = readdir (confdir)) != NULL)
+ {
+ if (ent->d_type != DT_REG)
+ continue;
+
+ size_t len = strlen (ent->d_name);
+ const char *suffix = ".conf";
+
+ if (len > strlen (suffix)
+ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
+ {
+ /* LEN <= PATH_MAX so this alloca is not unbounded. */
+ char *conf = alloca (BUF_LEN + len + 1);
+ cp = stpcpy (conf, buf);
+ sprintf (cp, "/%s", ent->d_name);
+ found |= handle_file (dir, conf);
+ }
+ }
+ closedir (confdir);
+ }
if (!found)
{
- error (0, errno, "failed to open gconv configuration file in `%s'",
+ error (0, errno, "failed to open gconv configuration files in `%s'",
dir);
error (0, 0,
- "ensure that the directory contains a valid gconv-modules file.");
+ "ensure that the directory contains either a valid "
+ "gconv-modules file or a gconv-modules.d directory with "
+ "configuration files with names ending in .conf.");
}
return found ? 0 : 1;

View File

@ -0,0 +1,99 @@
commit b17d29b390154df9dfad9d21f1e6605422521fd2
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Jun 7 14:22:19 2021 +0530
gconv_conf: Read configuration files in gconv-modules.d
Read configuration files with names ending in .conf in
GCONV_PATH/gconv-modules.d to mirror configuration flexibility in
iconvconfig into the iconv program and function.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index f173cde71b2a61d7..8eb981fca7cee36a 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
@@ -30,6 +31,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
+#include <sys/types.h>
#include <libc-lock.h>
#include <gconv_int.h>
@@ -50,6 +52,7 @@ static const struct path_elem empty_path_elem = { NULL, 0 };
/* Name of the file containing the module information in the directories
along the path. */
static const char gconv_conf_filename[] = "gconv-modules";
+static const char gconv_conf_dirname[] = "gconv-modules.d";
/* Filename extension for the modules. */
#ifndef MODULE_EXT
@@ -554,18 +557,52 @@ __gconv_read_conf (void)
for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
{
+#define BUF_LEN elem_len + sizeof (gconv_conf_dirname)
+
const char *elem = __gconv_path_elem[cnt].name;
size_t elem_len = __gconv_path_elem[cnt].len;
- char *filename;
+ char *buf;
/* No slash needs to be inserted between elem and gconv_conf_filename;
elem already ends in a slash. */
- filename = alloca (elem_len + sizeof (gconv_conf_filename));
- __mempcpy (__mempcpy (filename, elem, elem_len),
- gconv_conf_filename, sizeof (gconv_conf_filename));
+ buf = alloca (BUF_LEN);
+ char *cp = __mempcpy (__mempcpy (buf, elem, elem_len),
+ gconv_conf_filename, sizeof (gconv_conf_filename));
+
+ /* Read the gconv-modules configuration file first. */
+ read_conf_file (buf, elem, elem_len, &modules, &nmodules);
+
+ /* Next, see if there is a gconv-modules.d directory containing
+ configuration files and if it is non-empty. */
+ cp--;
+ cp[0] = '.';
+ cp[1] = 'd';
+ cp[2] = '\0';
+
+ DIR *confdir = __opendir (buf);
+ if (confdir != NULL)
+ {
+ struct dirent *ent;
+ while ((ent = __readdir (confdir)) != NULL)
+ {
+ if (ent->d_type != DT_REG)
+ continue;
+
+ size_t len = strlen (ent->d_name);
+ const char *suffix = ".conf";
- /* Read the next configuration file. */
- read_conf_file (filename, elem, elem_len, &modules, &nmodules);
+ if (len > strlen (suffix)
+ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
+ {
+ /* LEN <= PATH_MAX so this alloca is not unbounded. */
+ char *conf = alloca (BUF_LEN + len + 1);
+ cp = stpcpy (conf, buf);
+ sprintf (cp, "/%s", ent->d_name);
+ read_conf_file (conf, elem, elem_len, &modules, &nmodules);
+ }
+ }
+ __closedir (confdir);
+ }
}
#endif

View File

@ -0,0 +1,179 @@
commit fc5bfade69ca12d034967dc6b929dbe3dd715172
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Jun 7 14:22:20 2021 +0530
iconvdata: Move gconv-modules configuration to gconv-modules.conf
Move all gconv-modules configuration files to gconv-modules.conf.
That is, the S390 extensions now become gconv-modules-s390.conf. Move
both configuration files into gconv-modules.d.
Now GCONV_PATH/gconv-modules is read only for backward compatibility
for third-party gconv modules directories.
Reviewed-by: DJ Delorie <dj@redhat.com>
# Conflicts:
# iconvdata/Makefile
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 32656ad31d9b434b..fc403e8abe3cc11f 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -136,10 +136,13 @@ charmaps = ../localedata/charmaps
extra-modules-left := $(modules)
include extra-module.mk
+gconv-modules = gconv-modules.conf
+modpfx = $(objpfx)gconv-modules.d/
extra-objs += $(modules.so)
install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \
- $(inst_gconvdir)/gconv-modules
+ $(addprefix $(inst_gconvdir)/gconv-modules.d/, \
+ $(gconv-modules))
# We can build the conversion tables for numerous charsets automatically.
@@ -181,7 +184,7 @@ generated += $(generated-modules:=.h) $(generated-modules:=.stmp) \
iconv-test.out iconv-rules tst-loading.mtrace \
mtrace-tst-loading.out tst-tables.out iconv-test.xxx
ifdef objpfx
-generated += gconv-modules
+generated += $(addprefix gconv-modules.d/,$(gconv-modules))
endif
# Rules to generate the headers.
@@ -249,7 +252,8 @@ headers: $(addprefix $(objpfx), $(generated-modules:=.h))
$(addprefix $(inst_gconvdir)/, $(modules.so)): \
$(inst_gconvdir)/%: $(objpfx)% $(+force)
$(do-install-program)
-$(inst_gconvdir)/gconv-modules: $(objpfx)gconv-modules $(+force)
+$(addprefix $(inst_gconvdir)/gconv-modules.d/, $(gconv-modules)): \
+ $(inst_gconvdir)/gconv-modules.d/%: $(modpfx)% $(+force)
$(do-install)
ifeq (no,$(cross-compiling))
# Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary
@@ -297,29 +301,30 @@ $(objpfx)mtrace-tst-loading.out: $(objpfx)tst-loading.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-loading.mtrace > $@; \
$(evaluate-test)
-$(objpfx)bug-iconv1.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv1.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv2.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv2.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv3: $(libdl)
-$(objpfx)bug-iconv3.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv3.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv5.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv5.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)tst-loading.out: $(objpfx)gconv-modules \
+$(objpfx)tst-loading.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)tst-iconv4.out: $(objpfx)gconv-modules \
+$(objpfx)tst-iconv4.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)tst-iconv7.out: $(objpfx)gconv-modules \
+$(objpfx)tst-iconv7.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv10.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv12.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
+$(objpfx)bug-iconv14.out: $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
+$(objpfx)iconv-test.out: run-iconv-test.sh \
+ $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so)) \
$(common-objdir)/iconv/iconv_prog TESTS
iconv_modules="$(modules)" \
@@ -327,7 +332,8 @@ $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
'$(run-program-env)' > $@; \
$(evaluate-test)
-$(objpfx)tst-tables.out: tst-tables.sh $(objpfx)gconv-modules \
+$(objpfx)tst-tables.out: tst-tables.sh \
+ $(addprefix $(modpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so)) \
$(objpfx)tst-table-from $(objpfx)tst-table-to
$(SHELL) $< $(common-objpfx) $(common-objpfx)iconvdata/ \
@@ -340,5 +346,8 @@ do-tests-clean common-mostlyclean: tst-tables-clean
tst-tables-clean:
-rm -f $(objpfx)tst-*.table $(objpfx)tst-EUC-TW.irreversible
-$(objpfx)gconv-modules: gconv-modules
- cat $(sysdeps-gconv-modules) $^ > $@
+$(modpfx):
+ mkdir -p $@
+
+$(modpfx)%: % $(modpfx)
+ cp $< $@
diff --git a/iconvdata/gconv-modules b/iconvdata/gconv-modules.conf
similarity index 100%
rename from iconvdata/gconv-modules
rename to iconvdata/gconv-modules.conf
diff --git a/localedata/Makefile b/localedata/Makefile
index 14fcc37fed21e740..a5ca7a31f43d50c3 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -179,7 +179,7 @@ install-others := $(addprefix $(inst_i18ndir)/, \
$(locales))
endif
-tests: $(objdir)/iconvdata/gconv-modules
+tests: $(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf
tests-static += tst-langinfo-newlocale-static tst-langinfo-setlocale-static
@@ -442,5 +442,5 @@ $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
bug-setlocale1-ENV-only = LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8
bug-setlocale1-static-ENV-only = $(bug-setlocale1-ENV-only)
-$(objdir)/iconvdata/gconv-modules:
+$(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf:
$(MAKE) -C ../iconvdata subdir=iconvdata $@
diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile
index 8bc82e523f9049db..5c8e1170b4d799ba 100644
--- a/sysdeps/s390/Makefile
+++ b/sysdeps/s390/Makefile
@@ -21,13 +21,25 @@ lib := iconvdata
include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
extra-objs += $(addsuffix .so, $(s390x-iconv-modules))
-install-others += $(patsubst %, $(inst_gconvdir)/%.so, $(s390x-iconv-modules))
+install-others += $(patsubst %, $(inst_gconvdir)/%.so, \
+ $(s390x-iconv-modules)) \
+ $(inst_gconvdir)/gconv-modules.d/gconv-modules-s390.conf
$(patsubst %, $(inst_gconvdir)/%.so, $(s390x-iconv-modules)) : \
$(inst_gconvdir)/%.so: $(objpfx)%.so $(+force)
$(do-install-program)
-sysdeps-gconv-modules = ../sysdeps/s390/gconv-modules
+ifdef objpfx
+generated += gconv-modules.d/gconv-modules-s390.conf
+endif
+
+$(inst_gconvdir)/gconv-modules.d/gconv-modules-s390.conf: \
+ $(modpfx)gconv-modules-s390.conf $(+force)
+ $(do-install)
+
+$(modpfx)gconv-modules-s390.conf: ../sysdeps/s390/gconv-modules-s390.conf \
+ $(modpfx)
+ cp $< $@
endif
ifeq ($(subdir),string)
diff --git a/sysdeps/s390/gconv-modules b/sysdeps/s390/gconv-modules-s390.conf
similarity index 100%
rename from sysdeps/s390/gconv-modules
rename to sysdeps/s390/gconv-modules-s390.conf

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,137 @@
commit 06a1b794073c4d6adbfb2e4b11339985a14d7a00
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Jun 14 11:09:56 2021 +0530
Reinstate gconv-modules as the default configuration file
Reinstate gconv-modules as the main file so that the configuration
files in gconv-modules.d/ become add-on configuration. With this, the
effective user visible change is that GCONV_PATH can now have
supplementary configuration in GCONV_PATH/gconv-modules.d/ in addition
to the main GCONV_PATH/gconv-modules file.
# Conflicts:
# iconvdata/Makefile
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index d682a98b5c4a8003..95e5fb8f722a513b 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -136,13 +136,12 @@ charmaps = ../localedata/charmaps
extra-modules-left := $(modules)
include extra-module.mk
-gconv-modules = gconv-modules.conf gconv-modules-extra.conf
+gconv-modules = gconv-modules gconv-modules.d/gconv-modules-extra.conf
modpfx = $(objpfx)gconv-modules.d/
extra-objs += $(modules.so)
install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \
- $(addprefix $(inst_gconvdir)/gconv-modules.d/, \
- $(gconv-modules))
+ $(addprefix $(inst_gconvdir)/, $(gconv-modules))
# We can build the conversion tables for numerous charsets automatically.
@@ -184,7 +183,7 @@ generated += $(generated-modules:=.h) $(generated-modules:=.stmp) \
iconv-test.out iconv-rules tst-loading.mtrace \
mtrace-tst-loading.out tst-tables.out iconv-test.xxx
ifdef objpfx
-generated += $(addprefix gconv-modules.d/,$(gconv-modules))
+generated += $(gconv-modules)
endif
# Rules to generate the headers.
@@ -252,8 +251,8 @@ headers: $(addprefix $(objpfx), $(generated-modules:=.h))
$(addprefix $(inst_gconvdir)/, $(modules.so)): \
$(inst_gconvdir)/%: $(objpfx)% $(+force)
$(do-install-program)
-$(addprefix $(inst_gconvdir)/gconv-modules.d/, $(gconv-modules)): \
- $(inst_gconvdir)/gconv-modules.d/%: $(modpfx)% $(+force)
+$(addprefix $(inst_gconvdir)/, $(gconv-modules)): \
+ $(inst_gconvdir)/%: $(objpfx)% $(+force)
$(do-install)
ifeq (no,$(cross-compiling))
# Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary
@@ -301,30 +300,30 @@ $(objpfx)mtrace-tst-loading.out: $(objpfx)tst-loading.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-loading.mtrace > $@; \
$(evaluate-test)
-$(objpfx)bug-iconv1.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv1.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv2.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv2.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv3: $(libdl)
-$(objpfx)bug-iconv3.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv3.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv5.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv5.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)tst-loading.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)tst-loading.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)tst-iconv4.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)tst-iconv4.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)tst-iconv7.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)tst-iconv7.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv10.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv10.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv12.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
-$(objpfx)bug-iconv14.out: $(addprefix $(modpfx), $(gconv-modules)) \
+$(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh \
- $(addprefix $(modpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so)) \
$(common-objdir)/iconv/iconv_prog TESTS
iconv_modules="$(modules)" \
@@ -333,7 +332,7 @@ $(objpfx)iconv-test.out: run-iconv-test.sh \
$(evaluate-test)
$(objpfx)tst-tables.out: tst-tables.sh \
- $(addprefix $(modpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so)) \
$(objpfx)tst-table-from $(objpfx)tst-table-to
$(SHELL) $< $(common-objpfx) $(common-objpfx)iconvdata/ \
@@ -351,3 +350,6 @@ $(modpfx):
$(modpfx)%: % $(modpfx)
cp $< $@
+
+$(objpfx)gconv-modules: gconv-modules
+ cp $^ $@
diff --git a/iconvdata/gconv-modules.conf b/iconvdata/gconv-modules
similarity index 100%
rename from iconvdata/gconv-modules.conf
rename to iconvdata/gconv-modules
diff --git a/localedata/Makefile b/localedata/Makefile
index a5ca7a31f43d50c3..14fcc37fed21e740 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -179,7 +179,7 @@ install-others := $(addprefix $(inst_i18ndir)/, \
$(locales))
endif
-tests: $(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf
+tests: $(objdir)/iconvdata/gconv-modules
tests-static += tst-langinfo-newlocale-static tst-langinfo-setlocale-static
@@ -442,5 +442,5 @@ $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
bug-setlocale1-ENV-only = LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8
bug-setlocale1-static-ENV-only = $(bug-setlocale1-ENV-only)
-$(objdir)/iconvdata/gconv-modules.d/gconv-modules.conf:
+$(objdir)/iconvdata/gconv-modules:
$(MAKE) -C ../iconvdata subdir=iconvdata $@

View File

@ -0,0 +1,107 @@
commit e3217c7fd9e67aa2d53700bb1da9a966e73b9684
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Jun 10 00:41:35 2021 +0530
iconv: Remove alloca use in gconv-modules configuration parsing
The alloca sizes ought to be constrained to PATH_MAX, but replace them
with dynamic allocation to be safe. A static PATH_MAX array would
have worked too but Hurd does not have PATH_MAX and the code path is
not hot enough to micro-optimise this allocation. Revisit if any of
those realities change.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index 8eb981fca7cee36a..3099bf192adce711 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -557,15 +557,15 @@ __gconv_read_conf (void)
for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
{
-#define BUF_LEN elem_len + sizeof (gconv_conf_dirname)
-
const char *elem = __gconv_path_elem[cnt].name;
size_t elem_len = __gconv_path_elem[cnt].len;
- char *buf;
/* No slash needs to be inserted between elem and gconv_conf_filename;
elem already ends in a slash. */
- buf = alloca (BUF_LEN);
+ char *buf = malloc (elem_len + sizeof (gconv_conf_dirname));
+ if (buf == NULL)
+ continue;
+
char *cp = __mempcpy (__mempcpy (buf, elem, elem_len),
gconv_conf_filename, sizeof (gconv_conf_filename));
@@ -594,15 +594,16 @@ __gconv_read_conf (void)
if (len > strlen (suffix)
&& strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
{
- /* LEN <= PATH_MAX so this alloca is not unbounded. */
- char *conf = alloca (BUF_LEN + len + 1);
- cp = stpcpy (conf, buf);
- sprintf (cp, "/%s", ent->d_name);
+ char *conf;
+ if (__asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
+ continue;
read_conf_file (conf, elem, elem_len, &modules, &nmodules);
+ free (conf);
}
}
__closedir (confdir);
}
+ free (buf);
}
#endif
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index fafc686ae25fb5c1..2f9d5f45ad3a8159 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -712,7 +712,6 @@ handle_file (const char *dir, const char *infile)
static int
handle_dir (const char *dir)
{
-#define BUF_LEN prefix_len + dirlen + sizeof "gconv-modules.d"
char *cp;
size_t dirlen = strlen (dir);
bool found = false;
@@ -726,7 +725,10 @@ handle_dir (const char *dir)
}
/* First, look for a gconv-modules file. */
- char buf[BUF_LEN];
+ char *buf = malloc (prefix_len + dirlen + sizeof "gconv-modules.d");
+ if (buf == NULL)
+ goto out;
+
cp = buf;
if (dir[0] == '/')
cp = mempcpy (cp, prefix, prefix_len);
@@ -756,16 +758,19 @@ handle_dir (const char *dir)
if (len > strlen (suffix)
&& strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
{
- /* LEN <= PATH_MAX so this alloca is not unbounded. */
- char *conf = alloca (BUF_LEN + len + 1);
- cp = stpcpy (conf, buf);
- sprintf (cp, "/%s", ent->d_name);
+ char *conf;
+ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
+ continue;
found |= handle_file (dir, conf);
+ free (conf);
}
}
closedir (confdir);
}
+ free (buf);
+
+out:
if (!found)
{
error (0, errno, "failed to open gconv configuration files in `%s'",

View File

@ -0,0 +1,113 @@
commit 23e15ea1ae80ec2120afdf643691359644cf2873
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Jun 10 09:51:50 2021 +0530
gconv_conf: Remove unused variables
The modules and nmodules parameters passed to add_modules, add_alias,
etc. are not used and are hence unnecessary. Remove them so that
their signatures match the functions in iconvconfig.
Reviewed-by: DJ Delorie <dj@redhat.com>
Reviewed-by: Andreas Schwab <schwab@linux-m68k.org>
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index 3099bf192adce711..dc12ce24844474cc 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -125,7 +125,7 @@ detect_conflict (const char *alias)
/* The actual code to add aliases. */
static void
-add_alias2 (const char *from, const char *to, const char *wp, void *modules)
+add_alias2 (const char *from, const char *to, const char *wp)
{
/* Test whether this alias conflicts with any available module. */
if (detect_conflict (from))
@@ -154,7 +154,7 @@ add_alias2 (const char *from, const char *to, const char *wp, void *modules)
/* Add new alias. */
static void
-add_alias (char *rp, void *modules)
+add_alias (char *rp)
{
/* We now expect two more string. The strings are normalized
(converted to UPPER case) and strored in the alias database. */
@@ -179,7 +179,7 @@ add_alias (char *rp, void *modules)
return;
*wp++ = '\0';
- add_alias2 (from, to, wp, modules);
+ add_alias2 (from, to, wp);
}
@@ -243,8 +243,7 @@ insert_module (struct gconv_module *newp, int tobefreed)
/* Add new module. */
static void
-add_module (char *rp, const char *directory, size_t dir_len, void **modules,
- size_t *nmodules, int modcounter)
+add_module (char *rp, const char *directory, size_t dir_len, int modcounter)
{
/* We expect now
1. `from' name
@@ -357,8 +356,7 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules,
/* Read the next configuration file. */
static void
-read_conf_file (const char *filename, const char *directory, size_t dir_len,
- void **modules, size_t *nmodules)
+read_conf_file (const char *filename, const char *directory, size_t dir_len)
{
/* Note the file is opened with cancellation in the I/O functions
disabled. */
@@ -408,10 +406,10 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len,
if (rp - word == sizeof ("alias") - 1
&& memcmp (word, "alias", sizeof ("alias") - 1) == 0)
- add_alias (rp, *modules);
+ add_alias (rp);
else if (rp - word == sizeof ("module") - 1
&& memcmp (word, "module", sizeof ("module") - 1) == 0)
- add_module (rp, directory, dir_len, modules, nmodules, modcounter++);
+ add_module (rp, directory, dir_len, modcounter++);
/* else */
/* Otherwise ignore the line. */
}
@@ -537,8 +535,6 @@ void
attribute_hidden
__gconv_read_conf (void)
{
- void *modules = NULL;
- size_t nmodules = 0;
int save_errno = errno;
size_t cnt;
@@ -570,7 +566,7 @@ __gconv_read_conf (void)
gconv_conf_filename, sizeof (gconv_conf_filename));
/* Read the gconv-modules configuration file first. */
- read_conf_file (buf, elem, elem_len, &modules, &nmodules);
+ read_conf_file (buf, elem, elem_len);
/* Next, see if there is a gconv-modules.d directory containing
configuration files and if it is non-empty. */
@@ -597,7 +593,7 @@ __gconv_read_conf (void)
char *conf;
if (__asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
continue;
- read_conf_file (conf, elem, elem_len, &modules, &nmodules);
+ read_conf_file (conf, elem, elem_len);
free (conf);
}
}
@@ -631,7 +627,7 @@ __gconv_read_conf (void)
const char *to = __rawmemchr (from, '\0') + 1;
cp = __rawmemchr (to, '\0') + 1;
- add_alias2 (from, to, cp, modules);
+ add_alias2 (from, to, cp);
}
while (*cp != '\0');

View File

@ -0,0 +1,360 @@
commit d8e8097f3be5b3c49fc741fa19e1da0b0431384c
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Jun 10 14:07:27 2021 +0530
gconv_conf: Split out configuration file processing
Split configuration file processing into a separate header file and
include it. Macroize all calls that need to go through internal
interfaces so that iconvconfig can also use them.
Reviewed-by: DJ Delorie <dj@redhat.com>
# Conflicts:
# iconv/gconv_conf.c
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index dc12ce24844474cc..ce64faa928dc1c52 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -19,7 +19,6 @@
#include <assert.h>
#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
@@ -31,11 +30,10 @@
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
-#include <sys/types.h>
#include <libc-lock.h>
#include <gconv_int.h>
-
+#include <gconv_parseconfdir.h>
/* This is the default path where we look for module lists. */
static const char default_gconv_path[] = GCONV_PATH;
@@ -49,11 +47,6 @@ size_t __gconv_max_path_elem_len;
/* We use the following struct if we couldn't allocate memory. */
static const struct path_elem empty_path_elem = { NULL, 0 };
-/* Name of the file containing the module information in the directories
- along the path. */
-static const char gconv_conf_filename[] = "gconv-modules";
-static const char gconv_conf_dirname[] = "gconv-modules.d";
-
/* Filename extension for the modules. */
#ifndef MODULE_EXT
# define MODULE_EXT ".so"
@@ -92,9 +85,6 @@ static const char builtin_aliases[] =
#undef BUILTIN_ALIAS
};
-#include <libio/libioP.h>
-#define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp)
-
/* Value of the GCONV_PATH environment variable. */
const char *__gconv_path_envvar;
@@ -354,72 +344,6 @@ add_module (char *rp, const char *directory, size_t dir_len, int modcounter)
}
-/* Read the next configuration file. */
-static void
-read_conf_file (const char *filename, const char *directory, size_t dir_len)
-{
- /* Note the file is opened with cancellation in the I/O functions
- disabled. */
- FILE *fp = fopen (filename, "rce");
- char *line = NULL;
- size_t line_len = 0;
- static int modcounter;
-
- /* Don't complain if a file is not present or readable, simply silently
- ignore it. */
- if (fp == NULL)
- return;
-
- /* No threads reading from this stream. */
- __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
- /* Process the known entries of the file. Comments start with `#' and
- end with the end of the line. Empty lines are ignored. */
- while (!__feof_unlocked (fp))
- {
- char *rp, *endp, *word;
- ssize_t n = __getdelim (&line, &line_len, '\n', fp);
- if (n < 0)
- /* An error occurred. */
- break;
-
- rp = line;
- /* Terminate the line (excluding comments or newline) by an NUL byte
- to simplify the following code. */
- endp = strchr (rp, '#');
- if (endp != NULL)
- *endp = '\0';
- else
- if (rp[n - 1] == '\n')
- rp[n - 1] = '\0';
-
- while (__isspace_l (*rp, _nl_C_locobj_ptr))
- ++rp;
-
- /* If this is an empty line go on with the next one. */
- if (rp == endp)
- continue;
-
- word = rp;
- while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
- ++rp;
-
- if (rp - word == sizeof ("alias") - 1
- && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
- add_alias (rp);
- else if (rp - word == sizeof ("module") - 1
- && memcmp (word, "module", sizeof ("module") - 1) == 0)
- add_module (rp, directory, dir_len, modcounter++);
- /* else */
- /* Otherwise ignore the line. */
- }
-
- free (line);
-
- fclose (fp);
-}
-
-
/* Determine the directories we are looking for data in. */
void
__gconv_get_path (void)
@@ -552,55 +476,8 @@ __gconv_read_conf (void)
__gconv_get_path ();
for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
- {
- const char *elem = __gconv_path_elem[cnt].name;
- size_t elem_len = __gconv_path_elem[cnt].len;
-
- /* No slash needs to be inserted between elem and gconv_conf_filename;
- elem already ends in a slash. */
- char *buf = malloc (elem_len + sizeof (gconv_conf_dirname));
- if (buf == NULL)
- continue;
-
- char *cp = __mempcpy (__mempcpy (buf, elem, elem_len),
- gconv_conf_filename, sizeof (gconv_conf_filename));
-
- /* Read the gconv-modules configuration file first. */
- read_conf_file (buf, elem, elem_len);
-
- /* Next, see if there is a gconv-modules.d directory containing
- configuration files and if it is non-empty. */
- cp--;
- cp[0] = '.';
- cp[1] = 'd';
- cp[2] = '\0';
-
- DIR *confdir = __opendir (buf);
- if (confdir != NULL)
- {
- struct dirent *ent;
- while ((ent = __readdir (confdir)) != NULL)
- {
- if (ent->d_type != DT_REG)
- continue;
-
- size_t len = strlen (ent->d_name);
- const char *suffix = ".conf";
-
- if (len > strlen (suffix)
- && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
- {
- char *conf;
- if (__asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
- continue;
- read_conf_file (conf, elem, elem_len);
- free (conf);
- }
- }
- __closedir (confdir);
- }
- free (buf);
- }
+ gconv_parseconfdir (__gconv_path_elem[cnt].name,
+ __gconv_path_elem[cnt].len);
#endif
/* Add the internal modules. */
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
new file mode 100644
index 0000000000000000..3d4d58d4be10a250
--- /dev/null
+++ b/iconv/gconv_parseconfdir.h
@@ -0,0 +1,161 @@
+/* Handle configuration data.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dirent.h>
+#include <libc-symbols.h>
+#include <locale.h>
+#include <sys/types.h>
+
+#if IS_IN (libc)
+# include <libio/libioP.h>
+# define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp)
+
+# undef isspace
+# define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
+# define asprintf __asprintf
+# define opendir __opendir
+# define readdir __readdir
+# define closedir __closedir
+# define mempcpy __mempcpy
+#endif
+
+/* Name of the file containing the module information in the directories
+ along the path. */
+static const char gconv_conf_filename[] = "gconv-modules";
+static const char gconv_conf_dirname[] = "gconv-modules.d";
+
+static void add_alias (char *);
+static void add_module (char *, const char *, size_t, int);
+
+/* Read the next configuration file. */
+static bool
+read_conf_file (const char *filename, const char *directory, size_t dir_len)
+{
+ /* Note the file is opened with cancellation in the I/O functions
+ disabled. */
+ FILE *fp = fopen (filename, "rce");
+ char *line = NULL;
+ size_t line_len = 0;
+ static int modcounter;
+
+ /* Don't complain if a file is not present or readable, simply silently
+ ignore it. */
+ if (fp == NULL)
+ return false;
+
+ /* No threads reading from this stream. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+ /* Process the known entries of the file. Comments start with `#' and
+ end with the end of the line. Empty lines are ignored. */
+ while (!__feof_unlocked (fp))
+ {
+ char *rp, *endp, *word;
+ ssize_t n = __getdelim (&line, &line_len, '\n', fp);
+ if (n < 0)
+ /* An error occurred. */
+ break;
+
+ rp = line;
+ /* Terminate the line (excluding comments or newline) by an NUL byte
+ to simplify the following code. */
+ endp = strchr (rp, '#');
+ if (endp != NULL)
+ *endp = '\0';
+ else
+ if (rp[n - 1] == '\n')
+ rp[n - 1] = '\0';
+
+ while (isspace (*rp))
+ ++rp;
+
+ /* If this is an empty line go on with the next one. */
+ if (rp == endp)
+ continue;
+
+ word = rp;
+ while (*rp != '\0' && !isspace (*rp))
+ ++rp;
+
+ if (rp - word == sizeof ("alias") - 1
+ && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
+ add_alias (rp);
+ else if (rp - word == sizeof ("module") - 1
+ && memcmp (word, "module", sizeof ("module") - 1) == 0)
+ add_module (rp, directory, dir_len, modcounter++);
+ /* else */
+ /* Otherwise ignore the line. */
+ }
+
+ free (line);
+
+ fclose (fp);
+ return true;
+}
+
+static __always_inline bool
+gconv_parseconfdir (const char *dir, size_t dir_len)
+{
+ /* No slash needs to be inserted between dir and gconv_conf_filename;
+ dir already ends in a slash. */
+ char *buf = malloc (dir_len + sizeof (gconv_conf_dirname));
+ bool found = false;
+
+ if (buf == NULL)
+ return false;
+
+ char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename,
+ sizeof (gconv_conf_filename));
+
+ /* Read the gconv-modules configuration file first. */
+ found = read_conf_file (buf, dir, dir_len);
+
+ /* Next, see if there is a gconv-modules.d directory containing
+ configuration files and if it is non-empty. */
+ cp--;
+ cp[0] = '.';
+ cp[1] = 'd';
+ cp[2] = '\0';
+
+ DIR *confdir = opendir (buf);
+ if (confdir != NULL)
+ {
+ struct dirent *ent;
+ while ((ent = readdir (confdir)) != NULL)
+ {
+ if (ent->d_type != DT_REG)
+ continue;
+
+ size_t len = strlen (ent->d_name);
+ const char *suffix = ".conf";
+
+ if (len > strlen (suffix)
+ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
+ {
+ char *conf;
+ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
+ continue;
+ found |= read_conf_file (conf, dir, dir_len);
+ free (conf);
+ }
+ }
+ closedir (confdir);
+ }
+ free (buf);
+ return found;
+}

View File

@ -0,0 +1,33 @@
commit dfec225ee1972488bb48a8b67a2c4a13010c334a
Author: JeffyChen <jeffy.chen@rock-chips.com>
Date: Fri Jul 2 17:39:24 2021 +0200
malloc: Initiate tcache shutdown even without allocations [BZ #28028]
After commit 1e26d35193efbb29239c710a4c46a64708643320 ("malloc: Fix
tcache leak after thread destruction [BZ #22111]"),
tcache_shutting_down is still not early enough. When we detach a
thread with no tcache allocated, tcache_shutting_down would still be
false.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 00a37f218c0ab3b2..61f7bdc76064c340 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2960,12 +2960,13 @@ tcache_thread_shutdown (void)
int i;
tcache_perthread_struct *tcache_tmp = tcache;
+ tcache_shutting_down = true;
+
if (!tcache)
return;
/* Disable the tcache and prevent it from being reinitialized. */
tcache = NULL;
- tcache_shutting_down = true;
/* Free all of the entries and the tcache itself back to the arena
heap for coalescing. */

View File

@ -0,0 +1,306 @@
commit a55e2da2702e235fa0ae66a116d304d1bffc060a
Author: Lucas A. M. Magalhaes <lamm@linux.ibm.com>
Date: Thu May 6 17:01:52 2021 -0300
powerpc: Optimized memcmp for power10
This patch was based on the __memcmp_power8 and the recent
__strlen_power10.
Improvements from __memcmp_power8:
1. Don't need alignment code.
On POWER10 lxvp and lxvl do not generate alignment interrupts, so
they are safe for use on caching-inhibited memory. Notice that the
comparison on the main loop will wait for both VSR to be ready.
Therefore aligning one of the input address does not improve
performance. In order to align both registers a vperm is necessary
which add too much overhead.
2. Uses new POWER10 instructions
This code uses lxvp to decrease contention on load by loading 32 bytes
per instruction.
The vextractbm is used to have a smaller tail code for calculating the
return value.
3. Performance improvement
This version has around 35% better performance on average. I saw no
performance regressions for any length or alignment.
Thanks Matheus for helping me out with some details.
Co-authored-by: Matheus Castanho <msc@linux.ibm.com>
Reviewed-by: Raphael M Zinsly <rzinsly@linux.ibm.com>
diff --git a/sysdeps/powerpc/powerpc64/le/power10/memcmp.S b/sysdeps/powerpc/powerpc64/le/power10/memcmp.S
new file mode 100644
index 0000000000000000..52f244e7e77cbdf9
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/power10/memcmp.S
@@ -0,0 +1,179 @@
+/* Optimized memcmp implementation for POWER10.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* TODO: Replace macros by the actual instructions when minimum binutils becomes
+ >= 2.35. This is used to keep compatibility with older versions. */
+#define VEXTRACTBM(rt,vrb) \
+ .long(((4)<<(32-6)) \
+ | ((rt)<<(32-11)) \
+ | ((8)<<(32-16)) \
+ | ((vrb)<<(32-21)) \
+ | 1602)
+
+#define LXVP(xtp,dq,ra) \
+ .long(((6)<<(32-6)) \
+ | ((((xtp)-32)>>1)<<(32-10)) \
+ | ((1)<<(32-11)) \
+ | ((ra)<<(32-16)) \
+ | dq)
+
+/* Compare 32 bytes. */
+#define COMPARE_32(vr1,vr2,offset,tail_1,tail_2)\
+ LXVP(32+vr1,offset,r3); \
+ LXVP(32+vr2,offset,r4); \
+ vcmpneb. v5,vr1+1,vr2+1; \
+ bne cr6,L(tail_2); \
+ vcmpneb. v4,vr1,vr2; \
+ bne cr6,L(tail_1); \
+
+#define TAIL(v_res,s1,s2) \
+ vctzlsbb r7,v_res; \
+ vextubrx r8,r7,s1; \
+ vextubrx r9,r7,s2; \
+ subf r3,r9,r8; \
+ blr; \
+
+/* int [r3] memcmp (const char *s1 [r3], const char *s2 [r4],
+ size_t size [r5]) */
+
+#ifndef MEMCMP
+# define MEMCMP memcmp
+#endif
+ .machine power9
+ENTRY_TOCLESS (MEMCMP, 4)
+ CALL_MCOUNT 3
+
+ cmpldi cr6,r5,64
+ bgt cr6,L(loop_head)
+
+/* Compare 64 bytes. This section is used for lengths <= 64 and for the last
+ bytes for larger lengths. */
+L(last_compare):
+ li r8,16
+
+ sldi r9,r5,56
+ sldi r8,r8,56
+ addi r6,r3,16
+ addi r7,r4,16
+
+ /* Align up to 16 bytes. */
+ lxvl 32+v0,r3,r9
+ lxvl 32+v2,r4,r9
+
+ /* The sub. and vcmpneb. results are concatenated by the crnand in order
+ to do a single branch. It's doing a NOT(CR0.GT AND CR6.EQ) then
+ loading to CR0.LT. That means r9 is not bigger than 0 and v4 is not
+ all equal to 0. */
+ sub. r9,r9,r8
+ vcmpneb. v4,v0,v2
+ crnand 4*cr0+lt,4*cr0+gt,4*cr6+eq
+ bt 4*cr0+lt,L(tail1)
+
+ addi r3,r3,32
+ addi r4,r4,32
+
+ lxvl 32+v1,r6,r9
+ lxvl 32+v3,r7,r9
+ sub. r9,r9,r8
+ vcmpneb. v5,v1,v3
+ crnand 4*cr0+lt,4*cr0+gt,4*cr6+eq
+ bt 4*cr0+lt,L(tail2)
+
+ addi r6,r3,16
+ addi r7,r4,16
+
+ lxvl 32+v6,r3,r9
+ lxvl 32+v8,r4,r9
+ sub. r9,r9,r8
+ vcmpneb. v4,v6,v8
+ crnand 4*cr0+lt,4*cr0+gt,4*cr6+eq
+ bt 4*cr0+lt,L(tail3)
+
+ lxvl 32+v7,r6,r9
+ lxvl 32+v9,r7,r9
+ vcmpneb. v5,v7,v9
+ bne cr6,L(tail4)
+
+L(finish):
+ /* The contents are equal. */
+ li r3,0
+ blr
+
+L(loop_head):
+ /* Calculate how many loops to run. */
+ srdi. r8,r5,7
+ beq L(loop_tail)
+ mtctr r8
+
+/* Main loop. Compares 128 bytes each loop. */
+ .p2align 5
+L(loop_128):
+ COMPARE_32(v0,v2,0,tail1,tail2)
+ COMPARE_32(v6,v8,32,tail3,tail4)
+ COMPARE_32(v10,v12,64,tail5,tail6)
+ COMPARE_32(v14,v16,96,tail7,tail8)
+
+ addi r3,r3,128
+ addi r4,r4,128
+ bdnz L(loop_128)
+
+ /* Account loop comparisons. */
+ clrldi. r5,r5,57
+ beq L(finish)
+
+/* Compares 64 bytes if length is still bigger than 64 bytes. */
+ .p2align 5
+L(loop_tail):
+ cmpldi r5,64
+ ble L(last_compare)
+ COMPARE_32(v0,v2,0,tail1,tail2)
+ COMPARE_32(v6,v8,32,tail3,tail4)
+ addi r3,r3,64
+ addi r4,r4,64
+ subi r5,r5,64
+ b L(last_compare)
+
+L(tail1):
+ TAIL(v4,v0,v2)
+
+L(tail2):
+ TAIL(v5,v1,v3)
+
+L(tail3):
+ TAIL(v4,v6,v8)
+
+L(tail4):
+ TAIL(v5,v7,v9)
+
+L(tail5):
+ TAIL(v4,v10,v12)
+
+L(tail6):
+ TAIL(v5,v11,v13)
+
+L(tail7):
+ TAIL(v4,v14,v16)
+
+L(tail8):
+ TAIL(v5,v15,v17)
+
+END (MEMCMP)
+libc_hidden_builtin_def (memcmp)
+weak_alias (memcmp, bcmp)
diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
index ac2446aca62cc4ab..ee98417f4a383356 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
+++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
strncase-power8
ifneq (,$(filter %le,$(config-machine)))
-sysdep_routines += memcpy-power10 memmove-power10 memset-power10 \
+sysdep_routines += memcmp-power10 memcpy-power10 memmove-power10 memset-power10 \
rawmemchr-power9 rawmemchr-power10 \
strcmp-power9 strncmp-power9 strcpy-power9 stpcpy-power9 \
strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
index 127af84b32a8196f..5213abdf87c79c88 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
@@ -184,6 +184,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
/* Support sysdeps/powerpc/powerpc64/multiarch/memcmp.c. */
IFUNC_IMPL (i, name, memcmp,
+#ifdef __LITTLE_ENDIAN__
+ IFUNC_IMPL_ADD (array, i, memcmp,
+ hwcap2 & PPC_FEATURE2_ARCH_3_1
+ && hwcap & PPC_FEATURE_HAS_VSX,
+ __memcmp_power10)
+#endif
IFUNC_IMPL_ADD (array, i, memcmp, hwcap2 & PPC_FEATURE2_ARCH_2_07,
__memcmp_power8)
IFUNC_IMPL_ADD (array, i, memcmp, hwcap & PPC_FEATURE_HAS_VSX,
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S
new file mode 100644
index 0000000000000000..73a0debd4a811d8e
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S
@@ -0,0 +1,26 @@
+/* Optimized memcmp implementation for POWER10.
+ Copyright (C) 2017-2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#define MEMCMP __memcmp_power10
+
+#undef libc_hidden_builtin_def
+#define libc_hidden_builtin_def(name)
+#undef weak_alias
+#define weak_alias(name,alias)
+
+#include <sysdeps/powerpc/powerpc64/le/power10/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c
index 2c7a083a6560f920..0b8c0c1d8aa3f90a 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c
@@ -27,11 +27,17 @@ extern __typeof (memcmp) __memcmp_ppc attribute_hidden;
extern __typeof (memcmp) __memcmp_power4 attribute_hidden;
extern __typeof (memcmp) __memcmp_power7 attribute_hidden;
extern __typeof (memcmp) __memcmp_power8 attribute_hidden;
+extern __typeof (memcmp) __memcmp_power10 attribute_hidden;
# undef memcmp
/* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
ifunc symbol properly. */
libc_ifunc_redirected (__redirect_memcmp, memcmp,
+#ifdef __LITTLE_ENDIAN__
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1
+ && hwcap & PPC_FEATURE_HAS_VSX)
+ ? __memcmp_power10 :
+#endif
(hwcap2 & PPC_FEATURE2_ARCH_2_07)
? __memcmp_power8 :
(hwcap & PPC_FEATURE_HAS_VSX)

View File

@ -0,0 +1,278 @@
commit 813c6ec808556553be9d39e900a3fc97ceb32330
Author: Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
Date: Wed Jun 30 12:36:07 2021 -0300
powerpc: optimize strcpy/stpcpy for POWER9/10
This patch modifies the current POWER9 implementation of strcpy and
stpcpy to optimize it for POWER9/10.
Since no new POWER10 instructions are used, the original POWER9 strcpy is
modified instead of creating a new implementation for POWER10. This
implementation is based on both the original POWER9 implementation of
strcpy and the preamble of the new POWER10 implementation of strlen.
The changes also affect stpcpy, which uses the same implementation with
some additional code before returning.
On POWER9, averaging improvements across the benchmark
inputs (length/source alignment/destination alignment), for an
experiment that ran the benchmark five times, bench-strcpy showed an
improvement of 5.23%, and bench-stpcpy showed an improvement of 6.59%.
On POWER10, bench-strcpy showed 13.16%, and bench-stpcpy showed 13.59%.
The changes are:
1. Removed the null string optimization.
Although this results in a few extra cycles for the null string, in
combination with the second change, this resulted in improvements for
for other cases.
2. Adapted the preamble from strlen for POWER10.
This is the part of the function that handles up to the first 16 bytes
of the string.
3. Increased number of unrolled iterations in the main loop to 6.
Reviewed-by: Matheus Castanho <msc@linux.ibm.com>
Tested-by: Matheus Castanho <msc@linux.ibm.com>
diff --git a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S
index ce8f50329177fd06..9845a1d4cf0e1e5d 100644
--- a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S
+++ b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S
@@ -45,91 +45,78 @@
The implementation can load bytes past a null terminator, but only
up to the next 16B boundary, so it never crosses a page. */
+/* Load quadword at addr+offset to vreg, check for null bytes,
+ and branch to label if any are found. */
+#define CHECK16(vreg,offset,addr,label) \
+ lxv vreg+32,offset(addr); \
+ vcmpequb. v6,vreg,v18; \
+ bne cr6,L(label);
+
.machine power9
ENTRY_TOCLESS (FUNC_NAME, 4)
CALL_MCOUNT 2
- /* NULL string optimisation */
- lbz r0,0(r4)
- stb r0,0(r3)
- cmpwi r0,0
- beqlr
-
- addi r4,r4,1
- addi r11,r3,1
-
vspltisb v18,0 /* Zeroes in v18 */
+ vspltisb v19,-1 /* 0xFF bytes in v19 */
- neg r5,r4
- rldicl r9,r5,0,60 /* How many bytes to get source 16B aligned? */
+ /* Next 16B-aligned address. Prepare address for L(loop). */
+ addi r5,r4,16
+ clrrdi r5,r5,4
+ subf r8,r4,r5
+ add r11,r3,r8
- /* Get source 16B aligned */
+ /* Align data and fill bytes not loaded with non matching char. */
lvx v0,0,r4
lvsr v1,0,r4
- vperm v0,v18,v0,v1
-
- vcmpequb v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */
- vctzlsbb r7,v6 /* Number of trailing zeroes */
- addi r8,r7,1 /* Add null terminator */
+ vperm v0,v19,v0,v1
- /* r8 = bytes including null
- r9 = bytes to get source 16B aligned
- if r8 > r9
- no null, copy r9 bytes
- else
- there is a null, copy r8 bytes and return. */
- cmpd r8,r9
- bgt L(no_null)
+ vcmpequb. v6,v0,v18 /* 0xff if byte is NULL, 0x00 otherwise */
+ beq cr6,L(no_null)
- sldi r10,r8,56 /* stxvl wants size in top 8 bits */
- stxvl 32+v0,r11,r10 /* Partial store */
+ /* There's a null byte. */
+ vctzlsbb r8,v6 /* Number of trailing zeroes */
+ addi r9,r8,1 /* Add null byte. */
+ sldi r10,r9,56 /* stxvl wants size in top 8 bits. */
+ stxvl 32+v0,r3,r10 /* Partial store */
#ifdef USE_AS_STPCPY
/* stpcpy returns the dest address plus the size not counting the
final '\0'. */
- add r3,r11,r7
+ add r3,r3,r8
#endif
blr
L(no_null):
- sldi r10,r9,56 /* stxvl wants size in top 8 bits */
- stxvl 32+v0,r11,r10 /* Partial store */
-
- add r4,r4,r9
- add r11,r11,r9
+ sldi r10,r8,56 /* stxvl wants size in top 8 bits */
+ stxvl 32+v0,r3,r10 /* Partial store */
+ .p2align 4
L(loop):
- lxv 32+v0,0(r4)
- vcmpequb. v6,v0,v18 /* Any zero bytes? */
- bne cr6,L(tail1)
-
- lxv 32+v1,16(r4)
- vcmpequb. v6,v1,v18 /* Any zero bytes? */
- bne cr6,L(tail2)
-
- lxv 32+v2,32(r4)
- vcmpequb. v6,v2,v18 /* Any zero bytes? */
- bne cr6,L(tail3)
-
- lxv 32+v3,48(r4)
- vcmpequb. v6,v3,v18 /* Any zero bytes? */
- bne cr6,L(tail4)
+ CHECK16(v0,0,r5,tail1)
+ CHECK16(v1,16,r5,tail2)
+ CHECK16(v2,32,r5,tail3)
+ CHECK16(v3,48,r5,tail4)
+ CHECK16(v4,64,r5,tail5)
+ CHECK16(v5,80,r5,tail6)
stxv 32+v0,0(r11)
stxv 32+v1,16(r11)
stxv 32+v2,32(r11)
stxv 32+v3,48(r11)
+ stxv 32+v4,64(r11)
+ stxv 32+v5,80(r11)
- addi r4,r4,64
- addi r11,r11,64
+ addi r5,r5,96
+ addi r11,r11,96
b L(loop)
+ .p2align 4
L(tail1):
- vctzlsbb r8,v6
- addi r9,r8,1
+ vctzlsbb r8,v6 /* Number of trailing zeroes */
+ addi r9,r8,1 /* Add null terminator */
sldi r9,r9,56 /* stxvl wants size in top 8 bits */
- stxvl 32+v0,r11,r9
+ stxvl 32+v0,r11,r9 /* Partial store */
#ifdef USE_AS_STPCPY
/* stpcpy returns the dest address plus the size not counting the
final '\0'. */
@@ -137,50 +124,81 @@ L(tail1):
#endif
blr
+ .p2align 4
L(tail2):
stxv 32+v0,0(r11)
- vctzlsbb r8,v6 /* Number of trailing zeroes */
- addi r9,r8,1 /* Add null terminator */
- sldi r10,r9,56 /* stxvl wants size in top 8 bits */
+ vctzlsbb r8,v6
+ addi r9,r8,1
+ sldi r9,r9,56
addi r11,r11,16
- stxvl 32+v1,r11,r10 /* Partial store */
+ stxvl 32+v1,r11,r9
#ifdef USE_AS_STPCPY
- /* stpcpy returns the dest address plus the size not counting the
- final '\0'. */
add r3,r11,r8
#endif
blr
+ .p2align 4
L(tail3):
stxv 32+v0,0(r11)
stxv 32+v1,16(r11)
- vctzlsbb r8,v6 /* Number of trailing zeroes */
- addi r9,r8,1 /* Add null terminator */
- sldi r10,r9,56 /* stxvl wants size in top 8 bits */
+ vctzlsbb r8,v6
+ addi r9,r8,1
+ sldi r9,r9,56
addi r11,r11,32
- stxvl 32+v2,r11,r10 /* Partial store */
+ stxvl 32+v2,r11,r9
#ifdef USE_AS_STPCPY
- /* stpcpy returns the dest address plus the size not counting the
- final '\0'. */
add r3,r11,r8
#endif
blr
+ .p2align 4
L(tail4):
stxv 32+v0,0(r11)
stxv 32+v1,16(r11)
stxv 32+v2,32(r11)
- vctzlsbb r8,v6 /* Number of trailing zeroes */
- addi r9,r8,1 /* Add null terminator */
- sldi r10,r9,56 /* stxvl wants size in top 8 bits */
+ vctzlsbb r8,v6
+ addi r9,r8,1
+ sldi r9,r9,56
addi r11,r11,48
- stxvl 32+v3,r11,r10 /* Partial store */
+ stxvl 32+v3,r11,r9
#ifdef USE_AS_STPCPY
- /* stpcpy returns the dest address plus the size not counting the
- final '\0'. */
add r3,r11,r8
#endif
blr
+
+ .p2align 4
+L(tail5):
+ stxv 32+v0,0(r11)
+ stxv 32+v1,16(r11)
+ stxv 32+v2,32(r11)
+ stxv 32+v3,48(r11)
+ vctzlsbb r8,v6
+ addi r9,r8,1
+ sldi r9,r9,56
+ addi r11,r11,64
+ stxvl 32+v4,r11,r9
+#ifdef USE_AS_STPCPY
+ add r3,r11,r8
+#endif
+ blr
+
+ .p2align 4
+L(tail6):
+ stxv 32+v0,0(r11)
+ stxv 32+v1,16(r11)
+ stxv 32+v2,32(r11)
+ stxv 32+v3,48(r11)
+ stxv 32+v4,64(r11)
+ vctzlsbb r8,v6
+ addi r9,r8,1
+ sldi r9,r9,56
+ addi r11,r11,80
+ stxvl 32+v5,r11,r9
+#ifdef USE_AS_STPCPY
+ add r3,r11,r8
+#endif
+ blr
+
END (FUNC_NAME)
#ifndef USE_AS_STPCPY
libc_hidden_builtin_def (strcpy)

View File

@ -0,0 +1,50 @@
From 756c306502498f999fdd494477b9cea1b45e4faf Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Fri, 21 Aug 2020 11:23:17 +0200
Subject: [PATCH] S390: Sync HWCAP names with kernel by adding aliases [BZ
#25971]
Unfortunately some HWCAP names like HWCAP_S390_VX differs between
kernel (see <kernel>/arch/s390/include/asm/elf.h) and glibc.
Therefore, those HWCAP names from kernel are now introduced as alias
---
sysdeps/s390/dl-procinfo.h | 3 +++
sysdeps/unix/sysv/linux/s390/bits/hwcap.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
index 0db4bc39c7..08eee109f7 100644
--- a/sysdeps/s390/dl-procinfo.h
+++ b/sysdeps/s390/dl-procinfo.h
@@ -51,8 +51,11 @@ enum
HWCAP_S390_HIGH_GPRS = 1 << 9,
HWCAP_S390_TE = 1 << 10,
HWCAP_S390_VX = 1 << 11,
+ HWCAP_S390_VXRS = HWCAP_S390_VX,
HWCAP_S390_VXD = 1 << 12,
+ HWCAP_S390_VXRS_BCD = HWCAP_S390_VXD,
HWCAP_S390_VXE = 1 << 13,
+ HWCAP_S390_VXRS_EXT = HWCAP_S390_VXE,
HWCAP_S390_GS = 1 << 14,
HWCAP_S390_VXRS_EXT2 = 1 << 15,
HWCAP_S390_VXRS_PDE = 1 << 16,
diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
index 6adbec018b..f2998ff131 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
@@ -36,8 +36,11 @@
#define HWCAP_S390_HIGH_GPRS 512
#define HWCAP_S390_TE 1024
#define HWCAP_S390_VX 2048
+#define HWCAP_S390_VXRS HWCAP_S390_VX
#define HWCAP_S390_VXD 4096
+#define HWCAP_S390_VXRS_BCD HWCAP_S390_VXD
#define HWCAP_S390_VXE 8192
+#define HWCAP_S390_VXRS_EXT HWCAP_S390_VXE
#define HWCAP_S390_GS 16384
#define HWCAP_S390_VXRS_EXT2 32768
#define HWCAP_S390_VXRS_PDE 65536
--
2.31.1

View File

@ -0,0 +1,67 @@
From 25251c0707fe34f30a27381a5fabc35435a96621 Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Tue, 16 Feb 2021 16:18:56 +0100
Subject: [PATCH] S390: Add new hwcap values.
The new hwcap values indicate support for arch14 architecture.
---
sysdeps/s390/dl-procinfo.c | 5 +++--
sysdeps/s390/dl-procinfo.h | 4 +++-
sysdeps/unix/sysv/linux/s390/bits/hwcap.h | 2 ++
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c
index 0c334a2551..c174e27b35 100644
--- a/sysdeps/s390/dl-procinfo.c
+++ b/sysdeps/s390/dl-procinfo.c
@@ -46,12 +46,13 @@
#if !defined PROCINFO_DECL && defined SHARED
._dl_s390_cap_flags
#else
-PROCINFO_CLASS const char _dl_s390_cap_flags[19][9]
+PROCINFO_CLASS const char _dl_s390_cap_flags[21][9]
#endif
#ifndef PROCINFO_DECL
= {
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh",
- "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt"
+ "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt",
+ "vxp2", "nnpa"
}
#endif
#if !defined SHARED || defined PROCINFO_DECL
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
index 9e1a8c7ba9..2d9c305808 100644
--- a/sysdeps/s390/dl-procinfo.h
+++ b/sysdeps/s390/dl-procinfo.h
@@ -21,7 +21,7 @@
#define _DL_PROCINFO_H 1
#include <ldsodefs.h>
-#define _DL_HWCAP_COUNT 19
+#define _DL_HWCAP_COUNT 21
#define _DL_PLATFORMS_COUNT 10
@@ -61,6 +61,8 @@ enum
HWCAP_S390_VXRS_PDE = 1 << 16,
HWCAP_S390_SORT = 1 << 17,
HWCAP_S390_DFLT = 1 << 18,
+ HWCAP_S390_VXRS_PDE2 = 1 << 19,
+ HWCAP_S390_NNPA = 1 << 20,
};
#define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
index 696616e779..e9bd3684db 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
@@ -46,3 +46,5 @@
#define HWCAP_S390_VXRS_PDE 65536
#define HWCAP_S390_SORT 131072
#define HWCAP_S390_DFLT 262144
+#define HWCAP_S390_VXRS_PDE2 524288
+#define HWCAP_S390_NNPA 1048576
--
2.31.1

View File

@ -0,0 +1,88 @@
From f2e06656d04a9fcb0603802a4f8ce7aa3a1f055e Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Tue, 5 Oct 2021 16:14:10 +0200
Subject: [PATCH] S390: Add PCI_MIO and SIE HWCAPs
Both new HWCAPs were introduced in these kernel commits:
- 7e8403ecaf884f307b627f3c371475913dd29292
"s390: add HWCAP_S390_PCI_MIO to ELF hwcaps"
- 7e82523f2583e9813e4109df3656707162541297
"s390/hwcaps: make sie capability regular hwcap"
Also note that the kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e
"s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros
from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not
change the prefix in public glibc header file.
---
sysdeps/s390/dl-procinfo.c | 4 ++--
sysdeps/s390/dl-procinfo.h | 4 +++-
sysdeps/unix/sysv/linux/s390/bits/hwcap.h | 7 +++++++
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c
index 7314c31b15..97be34fe9d 100644
--- a/sysdeps/s390/dl-procinfo.c
+++ b/sysdeps/s390/dl-procinfo.c
@@ -45,13 +45,13 @@
#if !defined PROCINFO_DECL && defined SHARED
._dl_s390_cap_flags
#else
-PROCINFO_CLASS const char _dl_s390_cap_flags[21][9]
+PROCINFO_CLASS const char _dl_s390_cap_flags[23][9]
#endif
#ifndef PROCINFO_DECL
= {
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh",
"highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt",
- "vxp2", "nnpa"
+ "vxp2", "nnpa", "pcimio", "sie"
}
#endif
#if !defined SHARED || defined PROCINFO_DECL
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
index 2502dd2604..d9a3b264ff 100644
--- a/sysdeps/s390/dl-procinfo.h
+++ b/sysdeps/s390/dl-procinfo.h
@@ -20,7 +20,7 @@
#define _DL_PROCINFO_H 1
#include <ldsodefs.h>
-#define _DL_HWCAP_COUNT 21
+#define _DL_HWCAP_COUNT 23
#define _DL_PLATFORMS_COUNT 10
@@ -62,6 +62,8 @@ enum
HWCAP_S390_DFLT = 1 << 18,
HWCAP_S390_VXRS_PDE2 = 1 << 19,
HWCAP_S390_NNPA = 1 << 20,
+ HWCAP_S390_PCI_MIO = 1 << 21,
+ HWCAP_S390_SIE = 1 << 22,
};
#define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
index e9bd3684db..00e73a3e3b 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
@@ -22,6 +22,11 @@
/*
* The following must match the kernels asm/elf.h.
+ * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e
+ * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros
+ * from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not
+ * change the prefix in public glibc header file.
+ *
* Note that these are *not* the same as the STORE FACILITY LIST bits.
*/
#define HWCAP_S390_ESAN3 1
@@ -48,3 +53,5 @@
#define HWCAP_S390_DFLT 262144
#define HWCAP_S390_VXRS_PDE2 524288
#define HWCAP_S390_NNPA 1048576
+#define HWCAP_S390_PCI_MIO 2097152
+#define HWCAP_S390_SIE 4194304
--
2.31.1

View File

@ -0,0 +1,30 @@
commit ad78d702757a189b1fa552d607e8aaa22252a45f
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue May 12 19:06:18 2020 +0200
elf: Remove redundant add_to_global_resize_failure call from dl_open_args
The second call does not do anything because the data structures have
already been resized by the call that comes before the demarcation
point. Fixes commit a509eb117fac1d764b15eba64993f4bdb63d7f3c
("Avoid late dlopen failure due to scope, TLS slotinfo updates
[BZ #25112]").
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 3d49a84596e99bf6..b052bb0bc2cd17aa 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -769,11 +769,6 @@ dl_open_worker (void *a)
DL_STATIC_INIT (new);
#endif
- /* Perform the necessary allocations for adding new global objects
- to the global scope below, via add_to_global_update. */
- if (mode & RTLD_GLOBAL)
- add_to_global_resize (new);
-
/* Run the initializer functions of new objects. Temporarily
disable the exception handler, so that lazy binding failures are
fatal. */

View File

@ -0,0 +1,23 @@
commit 52290d8c04569615fb011ee286d52dc5147afbd7
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Apr 15 09:57:10 2021 +0100
elf: Fix missing include in test case [BZ #27136]
Broken test was introduced in
commit 8f85075a2e9c26ff7486d4bbaf358999807d215c
elf: Add a DTV setup test [BZ #27136]
diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c
index ac5f8c8d39b66dd6..9977ec803208b9c8 100644
--- a/elf/tst-tls20.c
+++ b/elf/tst-tls20.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <support/check.h>
+#include <support/support.h>
#include <support/xdlfcn.h>
#include <support/xthread.h>

View File

@ -0,0 +1,160 @@
commit 2208066603a136f95cfb815ca9281262e6465784
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Feb 11 13:24:47 2021 +0000
elf: Remove lazy tlsdesc relocation related code
Remove generic tlsdesc code related to lazy tlsdesc processing since
lazy tlsdesc relocation is no longer supported. This includes removing
GL(dl_load_lock) from _dl_make_tlsdesc_dynamic which is only called at
load time when that lock is already held.
Added a documentation comment too.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/tlsdeschtab.h b/elf/tlsdeschtab.h
index fea9eefe72edcd6b..c20857e5b4264f00 100644
--- a/elf/tlsdeschtab.h
+++ b/elf/tlsdeschtab.h
@@ -78,6 +78,10 @@ map_generation (struct link_map *map)
return GL(dl_tls_generation) + 1;
}
+/* Returns the data pointer for a given map and tls offset that is used
+ to fill in one of the GOT entries referenced by a TLSDESC relocation
+ when using dynamic TLS. This requires allocation, returns NULL on
+ allocation failure. */
void *
_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
{
@@ -85,18 +89,12 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
void **entry;
struct tlsdesc_dynamic_arg *td, test;
- /* FIXME: We could use a per-map lock here, but is it worth it? */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
-
ht = map->l_mach.tlsdesc_table;
if (! ht)
{
ht = htab_create ();
if (! ht)
- {
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
- return 0;
- }
+ return 0;
map->l_mach.tlsdesc_table = ht;
}
@@ -104,15 +102,11 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
test.tlsinfo.ti_offset = ti_offset;
entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
if (! entry)
- {
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
- return 0;
- }
+ return 0;
if (*entry)
{
td = *entry;
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
return td;
}
@@ -122,44 +116,9 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
thread. */
td->gen_count = map_generation (map);
td->tlsinfo = test.tlsinfo;
-
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
return td;
}
# endif /* SHARED */
-/* The idea of the following two functions is to stop multiple threads
- from attempting to resolve the same TLS descriptor without busy
- waiting. Ideally, we should be able to release the lock right
- after changing td->entry, and then using say a condition variable
- or a futex wake to wake up any waiting threads, but let's try to
- avoid introducing such dependencies. */
-
-static int
-__attribute__ ((unused))
-_dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller)
-{
- if (caller != atomic_load_relaxed (&td->entry))
- return 1;
-
- __rtld_lock_lock_recursive (GL(dl_load_lock));
- if (caller != atomic_load_relaxed (&td->entry))
- {
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
- return 1;
- }
-
- atomic_store_relaxed (&td->entry, _dl_tlsdesc_resolve_hold);
-
- return 0;
-}
-
-static void
-__attribute__ ((unused))
-_dl_tlsdesc_wake_up_held_fixups (void)
-{
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
-}
-
#endif
diff --git a/sysdeps/aarch64/tlsdesc.c b/sysdeps/aarch64/tlsdesc.c
index 357465f23d76e2bd..1ead73ab8250e29c 100644
--- a/sysdeps/aarch64/tlsdesc.c
+++ b/sysdeps/aarch64/tlsdesc.c
@@ -22,7 +22,6 @@
#include <tls.h>
#include <dl-tlsdesc.h>
#include <dl-unmap-segments.h>
-#define _dl_tlsdesc_resolve_hold 0
#include <tlsdeschtab.h>
/* Unmap the dynamic object, but also release its TLS descriptor table
diff --git a/sysdeps/arm/tlsdesc.c b/sysdeps/arm/tlsdesc.c
index d142d7a2c91e9adb..b78e3f65785bf587 100644
--- a/sysdeps/arm/tlsdesc.c
+++ b/sysdeps/arm/tlsdesc.c
@@ -20,7 +20,6 @@
#include <tls.h>
#include <dl-tlsdesc.h>
#include <dl-unmap-segments.h>
-#define _dl_tlsdesc_resolve_hold 0
#include <tlsdeschtab.h>
/* Unmap the dynamic object, but also release its TLS descriptor table
diff --git a/sysdeps/i386/tlsdesc.c b/sysdeps/i386/tlsdesc.c
index 1b4227c8381e1b3d..c242ffce726d50e4 100644
--- a/sysdeps/i386/tlsdesc.c
+++ b/sysdeps/i386/tlsdesc.c
@@ -20,7 +20,6 @@
#include <tls.h>
#include <dl-tlsdesc.h>
#include <dl-unmap-segments.h>
-#define _dl_tlsdesc_resolve_hold 0
#include <tlsdeschtab.h>
/* Unmap the dynamic object, but also release its TLS descriptor table
diff --git a/sysdeps/x86_64/tlsdesc.c b/sysdeps/x86_64/tlsdesc.c
index 61a19ae26944c84f..a9325827d0e5e31b 100644
--- a/sysdeps/x86_64/tlsdesc.c
+++ b/sysdeps/x86_64/tlsdesc.c
@@ -20,7 +20,6 @@
#include <tls.h>
#include <dl-tlsdesc.h>
#include <dl-unmap-segments.h>
-#define _dl_tlsdesc_resolve_hold 0
#include <tlsdeschtab.h>
/* Unmap the dynamic object, but also release its TLS descriptor table

View File

@ -0,0 +1,182 @@
commit 1387ad6225c2222f027790e3f460e31aa5dd2c54
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed Dec 30 19:19:37 2020 +0000
elf: Fix data races in pthread_create and TLS access [BZ #19329]
DTV setup at thread creation (_dl_allocate_tls_init) is changed
to take the dlopen lock, GL(dl_load_lock). Avoiding data races
here without locks would require design changes: the map that is
accessed for static TLS initialization here may be concurrently
freed by dlclose. That use after free may be solved by only
locking around static TLS setup or by ensuring dlclose does not
free modules with static TLS, however currently every link map
with TLS has to be accessed at least to see if it needs static
TLS. And even if that's solved, still a lot of atomics would be
needed to synchronize DTV related globals without a lock. So fix
both bug 19329 and bug 27111 with a lock that prevents DTV setup
running concurrently with dlopen or dlclose.
_dl_update_slotinfo at TLS access still does not use any locks
so CONCURRENCY NOTES are added to explain the synchronization.
The early exit from the slotinfo walk when max_modid is reached
is not strictly necessary, but does not hurt either.
An incorrect acquire load was removed from _dl_resize_dtv: it
did not synchronize with any release store or fence and
synchronization is now handled separately at thread creation
and TLS access time.
There are still a number of racy read accesses to globals that
will be changed to relaxed MO atomics in a followup patch. This
should not introduce regressions compared to existing behaviour
and avoid cluttering the main part of the fix.
Not all TLS access related data races got fixed here: there are
additional races at lazy tlsdesc relocations see bug 27137.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 15ed01d795a8627a..da83cd6ae2ee6504 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -471,14 +471,11 @@ extern dtv_t _dl_static_dtv[];
#endif
static dtv_t *
-_dl_resize_dtv (dtv_t *dtv)
+_dl_resize_dtv (dtv_t *dtv, size_t max_modid)
{
/* Resize the dtv. */
dtv_t *newp;
- /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
- other threads concurrently. */
- size_t newsize
- = atomic_load_acquire (&GL(dl_tls_max_dtv_idx)) + DTV_SURPLUS;
+ size_t newsize = max_modid + DTV_SURPLUS;
size_t oldsize = dtv[-1].counter;
if (dtv == GL(dl_initial_dtv))
@@ -524,11 +521,14 @@ _dl_allocate_tls_init (void *result)
size_t total = 0;
size_t maxgen = 0;
+ /* Protects global dynamic TLS related state. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
/* Check if the current dtv is big enough. */
if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
{
/* Resize the dtv. */
- dtv = _dl_resize_dtv (dtv);
+ dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx));
/* Install this new dtv in the thread data structures. */
INSTALL_DTV (result, &dtv[-1]);
@@ -596,6 +596,7 @@ _dl_allocate_tls_init (void *result)
listp = listp->next;
assert (listp != NULL);
}
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
/* The DTV version is up-to-date now. */
dtv[0].counter = maxgen;
@@ -730,12 +731,29 @@ _dl_update_slotinfo (unsigned long int req_modid)
if (dtv[0].counter < listp->slotinfo[idx].gen)
{
- /* The generation counter for the slot is higher than what the
- current dtv implements. We have to update the whole dtv but
- only those entries with a generation counter <= the one for
- the entry we need. */
+ /* CONCURRENCY NOTES:
+
+ Here the dtv needs to be updated to new_gen generation count.
+
+ This code may be called during TLS access when GL(dl_load_lock)
+ is not held. In that case the user code has to synchronize with
+ dlopen and dlclose calls of relevant modules. A module m is
+ relevant if the generation of m <= new_gen and dlclose of m is
+ synchronized: a memory access here happens after the dlopen and
+ before the dlclose of relevant modules. The dtv entries for
+ relevant modules need to be updated, other entries can be
+ arbitrary.
+
+ This e.g. means that the first part of the slotinfo list can be
+ accessed race free, but the tail may be concurrently extended.
+ Similarly relevant slotinfo entries can be read race free, but
+ other entries are racy. However updating a non-relevant dtv
+ entry does not affect correctness. For a relevant module m,
+ max_modid >= modid of m. */
size_t new_gen = listp->slotinfo[idx].gen;
size_t total = 0;
+ size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
+ assert (max_modid >= req_modid);
/* We have to look through the entire dtv slotinfo list. */
listp = GL(dl_tls_dtv_slotinfo_list);
@@ -745,12 +763,14 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
size_t modid = total + cnt;
+ /* Later entries are not relevant. */
+ if (modid > max_modid)
+ break;
+
size_t gen = listp->slotinfo[cnt].gen;
if (gen > new_gen)
- /* This is a slot for a generation younger than the
- one we are handling now. It might be incompletely
- set up so ignore it. */
+ /* Not relevant. */
continue;
/* If the entry is older than the current dtv layout we
@@ -767,7 +787,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
continue;
/* Resize the dtv. */
- dtv = _dl_resize_dtv (dtv);
+ dtv = _dl_resize_dtv (dtv, max_modid);
assert (modid <= dtv[-1].counter);
@@ -789,8 +809,17 @@ _dl_update_slotinfo (unsigned long int req_modid)
}
total += listp->len;
+ if (total > max_modid)
+ break;
+
+ /* Synchronize with _dl_add_to_slotinfo. Ideally this would
+ be consume MO since we only need to order the accesses to
+ the next node after the read of the address and on most
+ hardware (other than alpha) a normal load would do that
+ because of the address dependency. */
+ listp = atomic_load_acquire (&listp->next);
}
- while ((listp = listp->next) != NULL);
+ while (listp != NULL);
/* This will be the new maximum generation counter. */
dtv[0].counter = new_gen;
@@ -982,7 +1011,7 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
the first slot. */
assert (idx == 0);
- listp = prevp->next = (struct dtv_slotinfo_list *)
+ listp = (struct dtv_slotinfo_list *)
malloc (sizeof (struct dtv_slotinfo_list)
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
if (listp == NULL)
@@ -996,6 +1025,8 @@ cannot create TLS data structures"));
listp->next = NULL;
memset (listp->slotinfo, '\0',
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+ /* Synchronize with _dl_update_slotinfo. */
+ atomic_store_release (&prevp->next, listp);
}
/* Add the information into the slotinfo data structure. */

View File

@ -0,0 +1,193 @@
commit f4f8f4d4e0f92488431b268c8cd9555730b9afe9
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed Dec 30 19:19:37 2020 +0000
elf: Use relaxed atomics for racy accesses [BZ #19329]
This is a follow up patch to the fix for bug 19329. This adds relaxed
MO atomics to accesses that were previously data races but are now
race conditions, and where relaxed MO is sufficient.
The race conditions all follow the pattern that the write is behind the
dlopen lock, but a read can happen concurrently (e.g. during tls access)
without holding the lock. For slotinfo entries the read value only
matters if it reads from a synchronized write in dlopen or dlclose,
otherwise the related dtv entry is not valid to access so it is fine
to leave it in an inconsistent state. The same applies for
GL(dl_tls_max_dtv_idx) and GL(dl_tls_generation), but there the
algorithm relies on the fact that the read of the last synchronized
write is an increasing value.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 1ece0ae1dd062d1e..7d2dc2272cd643f5 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -79,9 +79,10 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
{
assert (old_map->l_tls_modid == idx);
- /* Mark the entry as unused. */
- listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
- listp->slotinfo[idx - disp].map = NULL;
+ /* Mark the entry as unused. These can be read concurrently. */
+ atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,
+ GL(dl_tls_generation) + 1);
+ atomic_store_relaxed (&listp->slotinfo[idx - disp].map, NULL);
}
/* If this is not the last currently used entry no need to look
@@ -96,8 +97,8 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
if (listp->slotinfo[idx - disp].map != NULL)
{
- /* Found a new last used index. */
- GL(dl_tls_max_dtv_idx) = idx;
+ /* Found a new last used index. This can be read concurrently. */
+ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), idx);
return true;
}
}
@@ -571,7 +572,9 @@ _dl_close_worker (struct link_map *map, bool force)
GL(dl_tls_dtv_slotinfo_list), 0,
imap->l_init_called))
/* All dynamically loaded modules with TLS are unloaded. */
- GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
+ /* Can be read concurrently. */
+ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx),
+ GL(dl_tls_static_nelem));
if (imap->l_tls_offset != NO_TLS_OFFSET
&& imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
@@ -769,8 +772,11 @@ _dl_close_worker (struct link_map *map, bool force)
/* If we removed any object which uses TLS bump the generation counter. */
if (any_tls)
{
- if (__glibc_unlikely (++GL(dl_tls_generation) == 0))
+ size_t newgen = GL(dl_tls_generation) + 1;
+ if (__glibc_unlikely (newgen == 0))
_dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n");
+ /* Can be read concurrently. */
+ atomic_store_relaxed (&GL(dl_tls_generation), newgen);
if (tls_free_end == GL(dl_tls_static_used))
GL(dl_tls_static_used) = tls_free_start;
diff --git a/elf/dl-open.c b/elf/dl-open.c
index b052bb0bc2cd17aa..a67fb3aee40860e1 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -395,9 +395,12 @@ update_tls_slotinfo (struct link_map *new)
}
}
- if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
+ size_t newgen = GL(dl_tls_generation) + 1;
+ if (__glibc_unlikely (newgen == 0))
_dl_fatal_printf (N_("\
TLS generation counter wrapped! Please report this."));
+ /* Can be read concurrently. */
+ atomic_store_relaxed (&GL(dl_tls_generation), newgen);
/* We need a second pass for static tls data, because
_dl_update_slotinfo must not be run while calls to
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index da83cd6ae2ee6504..801eafad3961573c 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -175,7 +175,9 @@ _dl_next_tls_modid (void)
/* No gaps, allocate a new entry. */
nogaps:
- result = ++GL(dl_tls_max_dtv_idx);
+ result = GL(dl_tls_max_dtv_idx) + 1;
+ /* Can be read concurrently. */
+ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result);
}
return result;
@@ -359,10 +361,12 @@ allocate_dtv (void *result)
dtv_t *dtv;
size_t dtv_length;
+ /* Relaxed MO, because the dtv size is later rechecked, not relied on. */
+ size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
/* We allocate a few more elements in the dtv than are needed for the
initial set of modules. This should avoid in most cases expansions
of the dtv. */
- dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+ dtv_length = max_modid + DTV_SURPLUS;
dtv = calloc (dtv_length + 2, sizeof (dtv_t));
if (dtv != NULL)
{
@@ -767,7 +771,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
if (modid > max_modid)
break;
- size_t gen = listp->slotinfo[cnt].gen;
+ size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen);
if (gen > new_gen)
/* Not relevant. */
@@ -779,7 +783,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
continue;
/* If there is no map this means the entry is empty. */
- struct link_map *map = listp->slotinfo[cnt].map;
+ struct link_map *map
+ = atomic_load_relaxed (&listp->slotinfo[cnt].map);
/* Check whether the current dtv array is large enough. */
if (dtv[-1].counter < modid)
{
@@ -923,7 +928,12 @@ __tls_get_addr (GET_ADDR_ARGS)
{
dtv_t *dtv = THREAD_DTV ();
- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
+ /* Update is needed if dtv[0].counter < the generation of the accessed
+ module. The global generation counter is used here as it is easier
+ to check. Synchronization for the relaxed MO access is guaranteed
+ by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */
+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
+ if (__glibc_unlikely (dtv[0].counter != gen))
return update_get_addr (GET_ADDR_PARAM);
void *p = dtv[GET_ADDR_MODULE].pointer.val;
@@ -946,7 +956,10 @@ _dl_tls_get_addr_soft (struct link_map *l)
return NULL;
dtv_t *dtv = THREAD_DTV ();
- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
+ /* This may be called without holding the GL(dl_load_lock). Reading
+ arbitrary gen value is fine since this is best effort code. */
+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
+ if (__glibc_unlikely (dtv[0].counter != gen))
{
/* This thread's DTV is not completely current,
but it might already cover this module. */
@@ -1032,7 +1045,9 @@ cannot create TLS data structures"));
/* Add the information into the slotinfo data structure. */
if (do_add)
{
- listp->slotinfo[idx].map = l;
- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
+ /* Can be read concurrently. See _dl_update_slotinfo. */
+ atomic_store_relaxed (&listp->slotinfo[idx].map, l);
+ atomic_store_relaxed (&listp->slotinfo[idx].gen,
+ GL(dl_tls_generation) + 1);
}
}
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
index 533ee2b3a6e85ad8..bc543dcc264ea361 100644
--- a/sysdeps/x86_64/dl-tls.c
+++ b/sysdeps/x86_64/dl-tls.c
@@ -40,7 +40,8 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
{
dtv_t *dtv = THREAD_DTV ();
- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
+ if (__glibc_unlikely (dtv[0].counter != gen))
return update_get_addr (GET_ADDR_PARAM);
return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);

View File

@ -0,0 +1,133 @@
commit 9d0e30329c23b5ad736fda3f174208c25970dbce
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Tue Dec 13 12:28:41 2016 +0000
elf: Add test case for [BZ #19329]
Test concurrent dlopen and pthread_create when the loaded modules have
TLS. This triggers dl-tls assertion failures more reliably than the
nptl/tst-stack4 test.
The dlopened module has 100 DT_NEEDED dependencies with TLS, they were
reused from an existing TLS test. The number of created threads during
dlopen depends on filesystem speed and hardware, but at most 3 threads
are alive at a time to limit resource usage.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
elf/Makefile
(usual testing differences)
diff --git a/elf/Makefile b/elf/Makefile
index 0995d810b57d0dda..be40e3761cf91c4a 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -210,7 +210,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls-ie tst-tls-ie-dlmopen \
argv0test \
tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
- tst-tls20
+ tst-tls20 tst-tls21
# reldep9
tests-internal += loadtest unload unload2 circleload1 \
neededtest neededtest2 neededtest3 neededtest4 \
@@ -333,7 +333,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
libmarkermod2-1 libmarkermod2-2 \
libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \
libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
- tst-tls20mod-bad
+ tst-tls20mod-bad tst-tls21mod \
# Most modules build with _ISOMAC defined, but those filtered out
# depend on internal headers.
@@ -1836,3 +1836,8 @@ tst-tls20mod-bad.so-no-z-defs = yes
$(objpfx)tst-tls20: $(libdl) $(shared-thread-library)
$(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \
$(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
+
+# Reuses tst-tls-many-dynamic-modules
+$(objpfx)tst-tls21: $(libdl) $(shared-thread-library)
+$(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so
+$(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
diff --git a/elf/tst-tls21.c b/elf/tst-tls21.c
new file mode 100644
index 0000000000000000..560bf5813a746417
--- /dev/null
+++ b/elf/tst-tls21.c
@@ -0,0 +1,68 @@
+/* Test concurrent dlopen and pthread_create: BZ 19329.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdatomic.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+
+#define THREADS 10000
+
+static atomic_int done;
+
+static void *
+start (void *a)
+{
+ /* Load a module with many dependencies that each have TLS. */
+ xdlopen ("tst-tls21mod.so", RTLD_LAZY);
+ atomic_store_explicit (&done, 1, memory_order_release);
+ return 0;
+}
+
+static void *
+nop (void *a)
+{
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ pthread_t t1, t2;
+ int i;
+
+ /* Load a module with lots of dependencies and TLS. */
+ t1 = xpthread_create (0, start, 0);
+
+ /* Concurrently create lots of threads until dlopen is observably done. */
+ for (i = 0; i < THREADS; i++)
+ {
+ if (atomic_load_explicit (&done, memory_order_acquire) != 0)
+ break;
+ t2 = xpthread_create (0, nop, 0);
+ xpthread_join (t2);
+ }
+
+ xpthread_join (t1);
+ printf ("threads created during dlopen: %d\n", i);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-tls21mod.c b/elf/tst-tls21mod.c
new file mode 100644
index 0000000000000000..206ece4fb34622a9
--- /dev/null
+++ b/elf/tst-tls21mod.c
@@ -0,0 +1 @@
+int __thread x;

View File

@ -0,0 +1,81 @@
commit 572bd547d57a39b6cf0ea072545dc4048921f4c3
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Dec 31 13:59:38 2020 +0000
elf: Fix DTV gap reuse logic [BZ #27135]
For some reason only dlopen failure caused dtv gaps to be reused.
It is possible that the intent was to never reuse modids for a
different module, but after dlopen failure all gaps are reused
not just the ones caused by the unfinished dlopened.
So the code has to handle reused modids already which seems to
work, however the data races at thread creation and tls access
(see bug 19329 and bug 27111) may be more severe if slots are
reused so this is scheduled after those fixes. I think fixing
the races are not simpler if reuse is disallowed and reuse has
other benefits, so set GL(dl_tls_dtv_gaps) whenever entries are
removed from the middle of the slotinfo list. The value does
not have to be correct: incorrect true value causes the next
modid query to do a slotinfo walk, incorrect false will leave
gaps and new entries are added at the end.
Fixes bug 27135.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 7d2dc2272cd643f5..41cb6c58491c364b 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -88,7 +88,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
/* If this is not the last currently used entry no need to look
further. */
if (idx != GL(dl_tls_max_dtv_idx))
- return true;
+ {
+ /* There is an unused dtv entry in the middle. */
+ GL(dl_tls_dtv_gaps) = true;
+ return true;
+ }
}
while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
diff --git a/elf/dl-open.c b/elf/dl-open.c
index a67fb3aee40860e1..54727402750f4c0c 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -896,16 +896,6 @@ no more namespaces available for dlmopen()"));
state if relocation failed, for example. */
if (args.map)
{
- /* Maybe some of the modules which were loaded use TLS.
- Since it will be removed in the following _dl_close call
- we have to mark the dtv array as having gaps to fill the
- holes. This is a pessimistic assumption which won't hurt
- if not true. There is no need to do this when we are
- loading the auditing DSOs since TLS has not yet been set
- up. */
- if ((mode & __RTLD_AUDIT) == 0)
- GL(dl_tls_dtv_gaps) = true;
-
_dl_close_worker (args.map, true);
/* All l_nodelete_pending objects should have been deleted
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 801eafad3961573c..bacb4101e2e2c4e5 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -187,10 +187,7 @@ _dl_next_tls_modid (void)
size_t
_dl_count_modids (void)
{
- /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
- we fail to load a module and unload it leaving a gap. If we don't
- have gaps then the number of modids is the current maximum so
- return that. */
+ /* The count is the max unless dlclose or failed dlopen created gaps. */
if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
return GL(dl_tls_max_dtv_idx);

View File

@ -0,0 +1,71 @@
commit 40ebfd016ad284872f434bdd76dbe9c708db4d6b
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jun 25 08:09:08 2021 +0200
elf: Disable most of TLS modid gaps processing [BZ #27135]
Revert "elf: Fix DTV gap reuse logic [BZ #27135]"
This reverts commit 572bd547d57a39b6cf0ea072545dc4048921f4c3.
It turns out that the _dl_next_tls_modid in _dl_map_object_from_fd keeps
returning the same modid over and over again if there is a gap and
more than TLS-using module is loaded in one dlopen call. This corrupts
TLS data structures. The bug is still present after a revert, but
empirically it is much more difficult to trigger (because it involves a
dlopen failure).
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 41cb6c58491c364b..7d2dc2272cd643f5 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -88,11 +88,7 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
/* If this is not the last currently used entry no need to look
further. */
if (idx != GL(dl_tls_max_dtv_idx))
- {
- /* There is an unused dtv entry in the middle. */
- GL(dl_tls_dtv_gaps) = true;
- return true;
- }
+ return true;
}
while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 54727402750f4c0c..a67fb3aee40860e1 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -896,6 +896,16 @@ no more namespaces available for dlmopen()"));
state if relocation failed, for example. */
if (args.map)
{
+ /* Maybe some of the modules which were loaded use TLS.
+ Since it will be removed in the following _dl_close call
+ we have to mark the dtv array as having gaps to fill the
+ holes. This is a pessimistic assumption which won't hurt
+ if not true. There is no need to do this when we are
+ loading the auditing DSOs since TLS has not yet been set
+ up. */
+ if ((mode & __RTLD_AUDIT) == 0)
+ GL(dl_tls_dtv_gaps) = true;
+
_dl_close_worker (args.map, true);
/* All l_nodelete_pending objects should have been deleted
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index bacb4101e2e2c4e5..801eafad3961573c 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -187,7 +187,10 @@ _dl_next_tls_modid (void)
size_t
_dl_count_modids (void)
{
- /* The count is the max unless dlclose or failed dlopen created gaps. */
+ /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
+ we fail to load a module and unload it leaving a gap. If we don't
+ have gaps then the number of modids is the current maximum so
+ return that. */
if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
return GL(dl_tls_max_dtv_idx);

View File

@ -0,0 +1,585 @@
commit ba33937be210da5d07f7f01709323743f66011ce
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri Jun 25 10:54:12 2021 -0300
elf: Fix DTV gap reuse logic (BZ #27135)
This is updated version of the 572bd547d57a (reverted by 40ebfd016ad2)
that fixes the _dl_next_tls_modid issues.
This issue with 572bd547d57a patch is the DTV entry will be only
update on dl_open_worker() with the update_tls_slotinfo() call after
all dependencies are being processed by _dl_map_object_deps(). However
_dl_map_object_deps() itself might call _dl_next_tls_modid(), and since
the _dl_tls_dtv_slotinfo_list::map is not yet set the entry will be
wrongly reused.
This patch fixes by renaming the _dl_next_tls_modid() function to
_dl_assign_tls_modid() and by passing the link_map so it can set
the slotinfo value so a subsequente _dl_next_tls_modid() call will
see the entry as allocated.
The intermediary value is cleared up on remove_slotinfo() for the case
a library fails to load with RTLD_NOW.
This patch fixes BZ #27135.
Checked on x86_64-linux-gnu.
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
Conflicts:
elf/Makefile
(testing differences; libdl removal upstream)
diff --git a/elf/Makefile b/elf/Makefile
index be40e3761cf91c4a..3e71939d3234c4c3 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -242,6 +242,13 @@ one-hundred = $(foreach x,0 1 2 3 4 5 6 7 8 9, \
0$x 1$x 2$x 3$x 4$x 5$x 6$x 7$x 8$x 9$x)
tst-tls-many-dynamic-modules := \
$(foreach n,$(one-hundred),tst-tls-manydynamic$(n)mod)
+tst-tls-many-dynamic-modules-dep-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 \
+ 14 15 16 17 18 19
+tst-tls-many-dynamic-modules-dep = \
+ $(foreach n,$(tst-tls-many-dynamic-modules-dep-suffixes),tst-tls-manydynamic$(n)mod-dep)
+tst-tls-many-dynamic-modules-dep-bad-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+tst-tls-many-dynamic-modules-dep-bad = \
+ $(foreach n,$(tst-tls-many-dynamic-modules-dep-bad-suffixes),tst-tls-manydynamic$(n)mod-dep-bad)
extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \
tst-tlsalign-vars.o
test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars
@@ -314,6 +321,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
+ $(tst-tls-many-dynamic-modules-dep) \
+ $(tst-tls-many-dynamic-modules-dep-bad) \
tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
tst-absolute-zero-lib tst-big-note-lib \
@@ -1832,10 +1841,63 @@ $(objpfx)tst-rtld-help.out: $(objpfx)ld.so
$(evaluate-test)
# Reuses tst-tls-many-dynamic-modules
+$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules-dep)): \
+ $(objpfx)tst-tls-manydynamic%mod-dep.os : tst-tls-manydynamicmod.c
+ $(compile-command.c) \
+ -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$*
+$(patsubst %,$(objpfx)%.os,$(tst-tls-many-dynamic-modules-dep-bad)): \
+ $(objpfx)tst-tls-manydynamic%mod-dep-bad.os : tst-tls-manydynamicmod.c
+ $(compile-command.c) \
+ -DNAME=tls_global_$* -DSETTER=set_value_$* -DGETTER=get_value_$*
tst-tls20mod-bad.so-no-z-defs = yes
+# Single dependency.
+$(objpfx)tst-tls-manydynamic0mod-dep.so: $(objpfx)tst-tls-manydynamic1mod-dep.so
+# Double dependencies.
+$(objpfx)tst-tls-manydynamic2mod-dep.so: $(objpfx)tst-tls-manydynamic3mod-dep.so \
+ $(objpfx)tst-tls-manydynamic4mod-dep.so
+# Double dependencies with each dependency depent of another module.
+$(objpfx)tst-tls-manydynamic5mod-dep.so: $(objpfx)tst-tls-manydynamic6mod-dep.so \
+ $(objpfx)tst-tls-manydynamic7mod-dep.so
+$(objpfx)tst-tls-manydynamic6mod-dep.so: $(objpfx)tst-tls-manydynamic8mod-dep.so
+$(objpfx)tst-tls-manydynamic7mod-dep.so: $(objpfx)tst-tls-manydynamic8mod-dep.so
+# Long chain with one double dependency in the middle
+$(objpfx)tst-tls-manydynamic9mod-dep.so: $(objpfx)tst-tls-manydynamic10mod-dep.so \
+ $(objpfx)tst-tls-manydynamic11mod-dep.so
+$(objpfx)tst-tls-manydynamic10mod-dep.so: $(objpfx)tst-tls-manydynamic12mod-dep.so
+$(objpfx)tst-tls-manydynamic12mod-dep.so: $(objpfx)tst-tls-manydynamic13mod-dep.so
+# Long chain with two double depedencies in the middle
+$(objpfx)tst-tls-manydynamic14mod-dep.so: $(objpfx)tst-tls-manydynamic15mod-dep.so
+$(objpfx)tst-tls-manydynamic15mod-dep.so: $(objpfx)tst-tls-manydynamic16mod-dep.so \
+ $(objpfx)tst-tls-manydynamic17mod-dep.so
+$(objpfx)tst-tls-manydynamic16mod-dep.so: $(objpfx)tst-tls-manydynamic18mod-dep.so \
+ $(objpfx)tst-tls-manydynamic19mod-dep.so
+# Same but with an invalid module.
+# Single dependency.
+$(objpfx)tst-tls-manydynamic0mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so
+# Double dependencies.
+$(objpfx)tst-tls-manydynamic1mod-dep-bad.so: $(objpfx)tst-tls-manydynamic2mod-dep-bad.so \
+ $(objpfx)tst-tls20mod-bad.so
+# Double dependencies with each dependency depent of another module.
+$(objpfx)tst-tls-manydynamic3mod-dep-bad.so: $(objpfx)tst-tls-manydynamic4mod-dep-bad.so \
+ $(objpfx)tst-tls-manydynamic5mod-dep-bad.so
+$(objpfx)tst-tls-manydynamic4mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so
+$(objpfx)tst-tls-manydynamic5mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so
+# Long chain with one double dependency in the middle
+$(objpfx)tst-tls-manydynamic6mod-dep-bad.so: $(objpfx)tst-tls-manydynamic7mod-dep-bad.so \
+ $(objpfx)tst-tls-manydynamic8mod-dep-bad.so
+$(objpfx)tst-tls-manydynamic7mod-dep-bad.so: $(objpfx)tst-tls-manydynamic9mod-dep-bad.so
+$(objpfx)tst-tls-manydynamic9mod-dep-bad.so: $(objpfx)tst-tls20mod-bad.so
+# Long chain with two double depedencies in the middle
+$(objpfx)tst-tls-manydynamic10mod-dep-bad.so: $(objpfx)tst-tls-manydynamic11mod-dep-bad.so
+$(objpfx)tst-tls-manydynamic11mod-dep-bad.so: $(objpfx)tst-tls-manydynamic12mod-dep-bad.so \
+ $(objpfx)tst-tls-manydynamic13mod-dep-bad.so
+$(objpfx)tst-tls-manydynamic12mod-dep-bad.so: $(objpfx)tst-tls-manydynamic14mod-dep-bad.so \
+ $(objpfx)tst-tls20mod-bad.so
$(objpfx)tst-tls20: $(libdl) $(shared-thread-library)
$(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \
- $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
+ $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) \
+ $(tst-tls-many-dynamic-modules-dep:%=$(objpfx)%.so) \
+ $(tst-tls-many-dynamic-modules-dep-bad:%=$(objpfx)%.so) \
# Reuses tst-tls-many-dynamic-modules
$(objpfx)tst-tls21: $(libdl) $(shared-thread-library)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 7d2dc2272cd643f5..18227fe992029364 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -77,8 +77,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
object that wasn't fully set up. */
if (__glibc_likely (old_map != NULL))
{
- assert (old_map->l_tls_modid == idx);
-
/* Mark the entry as unused. These can be read concurrently. */
atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,
GL(dl_tls_generation) + 1);
@@ -88,7 +86,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
/* If this is not the last currently used entry no need to look
further. */
if (idx != GL(dl_tls_max_dtv_idx))
- return true;
+ {
+ /* There is an unused dtv entry in the middle. */
+ GL(dl_tls_dtv_gaps) = true;
+ return true;
+ }
}
while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 80fc38041a936c3c..cdb5d4b5b67f1ca1 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1419,7 +1419,7 @@ cannot enable executable stack as shared object requires");
not set up TLS data structures, so don't use them now. */
|| __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL)))
/* Assign the next available module ID. */
- l->l_tls_modid = _dl_next_tls_modid ();
+ _dl_assign_tls_modid (l);
#ifdef DL_AFTER_LOAD
DL_AFTER_LOAD (l);
diff --git a/elf/dl-open.c b/elf/dl-open.c
index a67fb3aee40860e1..54727402750f4c0c 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -896,16 +896,6 @@ no more namespaces available for dlmopen()"));
state if relocation failed, for example. */
if (args.map)
{
- /* Maybe some of the modules which were loaded use TLS.
- Since it will be removed in the following _dl_close call
- we have to mark the dtv array as having gaps to fill the
- holes. This is a pessimistic assumption which won't hurt
- if not true. There is no need to do this when we are
- loading the auditing DSOs since TLS has not yet been set
- up. */
- if ((mode & __RTLD_AUDIT) == 0)
- GL(dl_tls_dtv_gaps) = true;
-
_dl_close_worker (args.map, true);
/* All l_nodelete_pending objects should have been deleted
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 801eafad3961573c..8c0f9e972d7a0eac 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -122,8 +122,8 @@ oom (void)
}
-size_t
-_dl_next_tls_modid (void)
+void
+_dl_assign_tls_modid (struct link_map *l)
{
size_t result;
@@ -153,7 +153,11 @@ _dl_next_tls_modid (void)
}
if (result - disp < runp->len)
- break;
+ {
+ /* Mark the entry as used, so any dependency see it. */
+ atomic_store_relaxed (&runp->slotinfo[result - disp].map, l);
+ break;
+ }
disp += runp->len;
}
@@ -180,17 +184,14 @@ _dl_next_tls_modid (void)
atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result);
}
- return result;
+ l->l_tls_modid = result;
}
size_t
_dl_count_modids (void)
{
- /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
- we fail to load a module and unload it leaving a gap. If we don't
- have gaps then the number of modids is the current maximum so
- return that. */
+ /* The count is the max unless dlclose or failed dlopen created gaps. */
if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
return GL(dl_tls_max_dtv_idx);
diff --git a/elf/rtld.c b/elf/rtld.c
index 992f825ba00762a7..118c454a2329573f 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1693,7 +1693,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
/* Add the dynamic linker to the TLS list if it also uses TLS. */
if (GL(dl_rtld_map).l_tls_blocksize != 0)
/* Assign a module ID. Do this before loading any audit modules. */
- GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
+ _dl_assign_tls_modid (&GL(dl_rtld_map));
audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT);
audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT);
diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c
index 9977ec803208b9c8..d8d04fe574597f35 100644
--- a/elf/tst-tls20.c
+++ b/elf/tst-tls20.c
@@ -16,12 +16,14 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <array_length.h>
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <support/check.h>
#include <support/support.h>
+#include <support/test-driver.h>
#include <support/xdlfcn.h>
#include <support/xthread.h>
@@ -59,28 +61,75 @@ access (int i)
char *buf = xasprintf ("tls_global_%02d", i);
dlerror ();
int *p = dlsym (mod[i], buf);
- printf ("mod[%d]: &tls = %p\n", i, p);
+ if (test_verbose)
+ printf ("mod[%d]: &tls = %p\n", i, p);
if (p == NULL)
FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
+ TEST_COMPARE (*p, 0);
++*p;
free (buf);
}
+static void
+access_mod (const char *modname, void *mod, int i)
+{
+ char *modsym = xasprintf ("tls_global_%d", i);
+ dlerror ();
+ int *p = dlsym (mod, modsym);
+ if (test_verbose)
+ printf ("%s: &tls = %p\n", modname, p);
+ if (p == NULL)
+ FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
+ TEST_COMPARE (*p, 0);
+ ++*p;
+ free (modsym);
+}
+
+static void
+access_dep (int i)
+{
+ char *modname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", i);
+ void *moddep = xdlopen (modname, RTLD_LAZY);
+ access_mod (modname, moddep, i);
+ free (modname);
+ xdlclose (moddep);
+}
+
+struct start_args
+{
+ const char *modname;
+ void *mod;
+ int modi;
+ int ndeps;
+ const int *deps;
+};
+
static void *
start (void *a)
{
+ struct start_args *args = a;
+
for (int i = 0; i < NMOD; i++)
if (mod[i] != NULL)
access (i);
+
+ if (args != NULL)
+ {
+ access_mod (args->modname, args->mod, args->modi);
+ for (int n = 0; n < args->ndeps; n++)
+ access_dep (args->deps[n]);
+ }
+
return 0;
}
-static int
-do_test (void)
+/* This test gaps with shared libraries with dynamic TLS that has no
+ dependencies. The DTV gap is set with by trying to load an invalid
+ module, the entry should be used on the dlopen. */
+static void
+do_test_no_depedency (void)
{
- int i;
-
- for (i = 0; i < NMOD; i++)
+ for (int i = 0; i < NMOD; i++)
{
load_mod (i);
/* Bump the generation of mod[0] without using new dtv slot. */
@@ -91,8 +140,220 @@ do_test (void)
pthread_t t = xpthread_create (0, start, 0);
xpthread_join (t);
}
- for (i = 0; i < NMOD; i++)
+ for (int i = 0; i < NMOD; i++)
unload_mod (i);
+}
+
+/* The following test check DTV gaps handling with shared libraries that has
+ dependencies. It defines 5 different sets:
+
+ 1. Single dependency:
+ mod0 -> mod1
+ 2. Double dependency:
+ mod2 -> [mod3,mod4]
+ 3. Double dependency with each dependency depent of another module:
+ mod5 -> [mod6,mod7] -> mod8
+ 4. Long chain with one double dependency in the middle:
+ mod9 -> [mod10, mod11] -> mod12 -> mod13
+ 5. Long chain with two double depedencies in the middle:
+ mod14 -> mod15 -> [mod16, mod17]
+ mod15 -> [mod18, mod19]
+
+ This does not cover all the possible gaps and configuration, but it
+ should check if different dynamic shared sets are placed correctly in
+ different gaps configurations. */
+
+static int
+nmodules (uint32_t v)
+{
+ unsigned int r = 0;
+ while (v >>= 1)
+ r++;
+ return r + 1;
+}
+
+static inline bool
+is_mod_set (uint32_t g, uint32_t n)
+{
+ return (1U << (n - 1)) & g;
+}
+
+static void
+print_gap (uint32_t g)
+{
+ if (!test_verbose)
+ return;
+ printf ("gap: ");
+ int nmods = nmodules (g);
+ for (int n = 1; n <= nmods; n++)
+ printf ("%c", ((1 << (n - 1)) & g) == 0 ? 'G' : 'M');
+ printf ("\n");
+}
+
+static void
+do_test_dependency (void)
+{
+ /* Maps the module and its dependencies, use thread to access the TLS on
+ each loaded module. */
+ static const int tlsmanydeps0[] = { 1 };
+ static const int tlsmanydeps1[] = { 3, 4 };
+ static const int tlsmanydeps2[] = { 6, 7, 8 };
+ static const int tlsmanydeps3[] = { 10, 11, 12 };
+ static const int tlsmanydeps4[] = { 15, 16, 17, 18, 19 };
+ static const struct tlsmanydeps_t
+ {
+ int modi;
+ int ndeps;
+ const int *deps;
+ } tlsmanydeps[] =
+ {
+ { 0, array_length (tlsmanydeps0), tlsmanydeps0 },
+ { 2, array_length (tlsmanydeps1), tlsmanydeps1 },
+ { 5, array_length (tlsmanydeps2), tlsmanydeps2 },
+ { 9, array_length (tlsmanydeps3), tlsmanydeps3 },
+ { 14, array_length (tlsmanydeps4), tlsmanydeps4 },
+ };
+
+ /* The gap configuration is defined as a bitmap: the bit set represents a
+ loaded module prior the tests execution, while a bit unsed is a module
+ unloaded. Not all permtation will show gaps, but it is simpler than
+ define each one independently. */
+ for (uint32_t g = 0; g < 64; g++)
+ {
+ print_gap (g);
+ int nmods = nmodules (g);
+
+ int mods[nmods];
+ /* We use '0' as indication for a gap, to avoid the dlclose on iteration
+ cleanup. */
+ for (int n = 1; n <= nmods; n++)
+ {
+ load_mod (n);
+ mods[n] = n;
+ }
+ for (int n = 1; n <= nmods; n++)
+ {
+ if (!is_mod_set (g, n))
+ {
+ unload_mod (n);
+ mods[n] = 0;
+ }
+ }
+
+ for (int t = 0; t < array_length (tlsmanydeps); t++)
+ {
+ char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep.so",
+ tlsmanydeps[t].modi);
+ void *moddep = xdlopen (moddepname, RTLD_LAZY);
+
+ /* Access TLS in all loaded modules. */
+ struct start_args args =
+ {
+ moddepname,
+ moddep,
+ tlsmanydeps[t].modi,
+ tlsmanydeps[t].ndeps,
+ tlsmanydeps[t].deps
+ };
+ pthread_t t = xpthread_create (0, start, &args);
+ xpthread_join (t);
+
+ free (moddepname);
+ xdlclose (moddep);
+ }
+
+ for (int n = 1; n <= nmods; n++)
+ if (mods[n] != 0)
+ unload_mod (n);
+ }
+}
+
+/* The following test check DTV gaps handling with shared libraries that has
+ invalid dependencies. It defines 5 different sets:
+
+ 1. Single dependency:
+ mod0 -> invalid
+ 2. Double dependency:
+ mod1 -> [mod2,invalid]
+ 3. Double dependency with each dependency depent of another module:
+ mod3 -> [mod4,mod5] -> invalid
+ 4. Long chain with one double dependency in the middle:
+ mod6 -> [mod7, mod8] -> mod12 -> invalid
+ 5. Long chain with two double depedencies in the middle:
+ mod10 -> mod11 -> [mod12, mod13]
+ mod12 -> [mod14, invalid]
+
+ This does not cover all the possible gaps and configuration, but it
+ should check if different dynamic shared sets are placed correctly in
+ different gaps configurations. */
+
+static void
+do_test_invalid_dependency (bool bind_now)
+{
+ static const int tlsmanydeps[] = { 0, 1, 3, 6, 10 };
+
+ /* The gap configuration is defined as a bitmap: the bit set represents a
+ loaded module prior the tests execution, while a bit unsed is a module
+ unloaded. Not all permtation will show gaps, but it is simpler than
+ define each one independently. */
+ for (uint32_t g = 0; g < 64; g++)
+ {
+ print_gap (g);
+ int nmods = nmodules (g);
+
+ int mods[nmods];
+ /* We use '0' as indication for a gap, to avoid the dlclose on iteration
+ cleanup. */
+ for (int n = 1; n <= nmods; n++)
+ {
+ load_mod (n);
+ mods[n] = n;
+ }
+ for (int n = 1; n <= nmods; n++)
+ {
+ if (!is_mod_set (g, n))
+ {
+ unload_mod (n);
+ mods[n] = 0;
+ }
+ }
+
+ for (int t = 0; t < array_length (tlsmanydeps); t++)
+ {
+ char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep-bad.so",
+ tlsmanydeps[t]);
+ void *moddep;
+ if (bind_now)
+ {
+ moddep = dlopen (moddepname, RTLD_NOW);
+ TEST_VERIFY (moddep == 0);
+ }
+ else
+ moddep = dlopen (moddepname, RTLD_LAZY);
+
+ /* Access TLS in all loaded modules. */
+ pthread_t t = xpthread_create (0, start, NULL);
+ xpthread_join (t);
+
+ free (moddepname);
+ if (!bind_now)
+ xdlclose (moddep);
+ }
+
+ for (int n = 1; n <= nmods; n++)
+ if (mods[n] != 0)
+ unload_mod (n);
+ }
+}
+
+static int
+do_test (void)
+{
+ do_test_no_depedency ();
+ do_test_dependency ();
+ do_test_invalid_dependency (true);
+ do_test_invalid_dependency (false);
+
return 0;
}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 6cbbaa808a596f77..0138353ccb41c5f1 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1111,8 +1111,8 @@ extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
extern void _dl_sysdep_start_cleanup (void) attribute_hidden;
-/* Determine next available module ID. */
-extern size_t _dl_next_tls_modid (void) attribute_hidden;
+/* Determine next available module ID and set the L l_tls_modid. */
+extern void _dl_assign_tls_modid (struct link_map *l) attribute_hidden;
/* Count the modules with TLS segments. */
extern size_t _dl_count_modids (void) attribute_hidden;

View File

@ -0,0 +1,42 @@
commit 881b68e45c3a518319dcf5a3c4a2b3ec59e1c1e5
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri Jul 16 08:32:05 2021 -0300
elf: Fix a wrong array access on tst-tls20
Check on x86_64-linux-gnu with --enable-stack-protector=all.
diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c
index d8d04fe574597f35..831c3336c914790d 100644
--- a/elf/tst-tls20.c
+++ b/elf/tst-tls20.c
@@ -226,12 +226,12 @@ do_test_dependency (void)
int mods[nmods];
/* We use '0' as indication for a gap, to avoid the dlclose on iteration
cleanup. */
- for (int n = 1; n <= nmods; n++)
+ for (int n = 1; n < nmods; n++)
{
load_mod (n);
mods[n] = n;
}
- for (int n = 1; n <= nmods; n++)
+ for (int n = 1; n < nmods; n++)
{
if (!is_mod_set (g, n))
{
@@ -304,12 +304,12 @@ do_test_invalid_dependency (bool bind_now)
int mods[nmods];
/* We use '0' as indication for a gap, to avoid the dlclose on iteration
cleanup. */
- for (int n = 1; n <= nmods; n++)
+ for (int n = 1; n < nmods; n++)
{
load_mod (n);
mods[n] = n;
}
- for (int n = 1; n <= nmods; n++)
+ for (int n = 1; n < nmods; n++)
{
if (!is_mod_set (g, n))
{

View File

@ -0,0 +1,468 @@
commit 83b5323261bb72313bffcf37476c1b8f0847c736
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed Sep 15 15:16:19 2021 +0100
elf: Avoid deadlock between pthread_create and ctors [BZ #28357]
The fix for bug 19329 caused a regression such that pthread_create can
deadlock when concurrent ctors from dlopen are waiting for it to finish.
Use a new GL(dl_load_tls_lock) in pthread_create that is not taken
around ctors in dlopen.
The new lock is also used in __tls_get_addr instead of GL(dl_load_lock).
The new lock is held in _dl_open_worker and _dl_close_worker around
most of the logic before/after the init/fini routines. When init/fini
routines are running then TLS is in a consistent, usable state.
In _dl_open_worker the new lock requires catching and reraising dlopen
failures that happen in the critical section.
The new lock is reinitialized in a fork child, to keep the existing
behaviour and it is kept recursive in case malloc interposition or TLS
access from signal handlers can retake it. It is not obvious if this
is necessary or helps, but avoids changing the preexisting behaviour.
The new lock may be more appropriate for dl_iterate_phdr too than
GL(dl_load_write_lock), since TLS state of an incompletely loaded
module may be accessed. If the new lock can replace the old one,
that can be a separate change.
Fixes bug 28357.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
posix/fork.c
(reworked due to file rename upstream and libpthread integration)
sysdeps/pthread/Makefile
(htl testing support was missing downstream, reconstituted here;
added $(libdl) required downstream)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 18227fe992029364..7fe91bdd9aaf694e 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force)
size_t tls_free_end;
tls_free_start = tls_free_end = NO_TLS_OFFSET;
+ /* Protects global and module specitic TLS state. */
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
/* We modify the list of loaded objects. */
__rtld_lock_lock_recursive (GL(dl_load_write_lock));
@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force)
GL(dl_tls_static_used) = tls_free_start;
}
+ /* TLS is cleaned up for the unloaded modules. */
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
#ifdef SHARED
/* Auditing checkpoint: we have deleted all objects. */
if (__glibc_unlikely (do_audit))
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 54727402750f4c0c..736df62ce6e46d34 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -65,6 +65,9 @@ struct dl_open_args
libc_map value in the namespace in case of a dlopen failure. */
bool libc_already_loaded;
+ /* Set to true if the end of dl_open_worker_begin was reached. */
+ bool worker_continue;
+
/* Original parameters to the program and the current environment. */
int argc;
char **argv;
@@ -481,7 +484,7 @@ call_dl_init (void *closure)
}
static void
-dl_open_worker (void *a)
+dl_open_worker_begin (void *a)
{
struct dl_open_args *args = a;
const char *file = args->file;
@@ -772,6 +775,36 @@ dl_open_worker (void *a)
DL_STATIC_INIT (new);
#endif
+ args->worker_continue = true;
+}
+
+static void
+dl_open_worker (void *a)
+{
+ struct dl_open_args *args = a;
+
+ args->worker_continue = false;
+
+ {
+ /* Protects global and module specific TLS state. */
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
+ struct dl_exception ex;
+ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args);
+
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
+ if (__glibc_unlikely (ex.errstring != NULL))
+ /* Reraise the error. */
+ _dl_signal_exception (err, &ex, NULL);
+ }
+
+ if (!args->worker_continue)
+ return;
+
+ int mode = args->mode;
+ struct link_map *new = args->map;
+
/* Run the initializer functions of new objects. Temporarily
disable the exception handler, so that lazy binding failures are
fatal. */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 34be8e5babfb6af3..3e5531138eaa18f8 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -212,6 +212,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock)
list of loaded objects while an object is added to or removed from
that list. */
__rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
+ /* This lock protects global and module specific TLS related data.
+ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+ accessed and when TLS related relocations are processed for a
+ module. It was introduced to keep pthread_create accessing TLS
+ state that is being set up. */
+__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
#ifdef HAVE_AUX_VECTOR
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 8c0f9e972d7a0eac..7865fc390c3f3f0a 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -527,7 +527,7 @@ _dl_allocate_tls_init (void *result)
size_t maxgen = 0;
/* Protects global dynamic TLS related state. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
/* Check if the current dtv is big enough. */
if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
@@ -601,7 +601,7 @@ _dl_allocate_tls_init (void *result)
listp = listp->next;
assert (listp != NULL);
}
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
/* The DTV version is up-to-date now. */
dtv[0].counter = maxgen;
@@ -740,7 +740,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
Here the dtv needs to be updated to new_gen generation count.
- This code may be called during TLS access when GL(dl_load_lock)
+ This code may be called during TLS access when GL(dl_load_tls_lock)
is not held. In that case the user code has to synchronize with
dlopen and dlclose calls of relevant modules. A module m is
relevant if the generation of m <= new_gen and dlclose of m is
@@ -862,11 +862,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
if (__glibc_unlikely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET))
{
- __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
{
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
}
else if (__glibc_likely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET))
@@ -878,7 +878,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
dtv[GET_ADDR_MODULE].pointer.val = p;
@@ -886,7 +886,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
return (char *) p + GET_ADDR_OFFSET;
}
else
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
}
struct dtv_pointer result = allocate_and_init (the_map);
dtv[GET_ADDR_MODULE].pointer = result;
@@ -957,7 +957,7 @@ _dl_tls_get_addr_soft (struct link_map *l)
return NULL;
dtv_t *dtv = THREAD_DTV ();
- /* This may be called without holding the GL(dl_load_lock). Reading
+ /* This may be called without holding the GL(dl_load_tls_lock). Reading
arbitrary gen value is fine since this is best effort code. */
size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
if (__glibc_unlikely (dtv[0].counter != gen))
diff --git a/elf/rtld.c b/elf/rtld.c
index 118c454a2329573f..9e09896da078274d 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -317,6 +317,7 @@ struct rtld_global _rtld_global =
#ifdef _LIBC_REENTRANT
._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
#endif
._dl_nns = 1,
._dl_ns =
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 0138353ccb41c5f1..7b0a667629ddc06a 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -373,6 +373,13 @@ struct rtld_global
list of loaded objects while an object is added to or removed
from that list. */
__rtld_lock_define_recursive (EXTERN, _dl_load_write_lock)
+ /* This lock protects global and module specific TLS related data.
+ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+ accessed and when TLS related relocations are processed for a
+ module. It was introduced to keep pthread_create accessing TLS
+ state that is being set up. */
+ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock)
/* Incremented whenever something may have been added to dl_loaded. */
EXTERN unsigned long long _dl_load_adds;
@@ -1192,7 +1199,7 @@ extern int _dl_scope_free (void *) attribute_hidden;
/* Add module to slot information data. If DO_ADD is false, only the
required memory is allocated. Must be called with GL
- (dl_load_lock) acquired. If the function has already been called
+ (dl_load_tls_lock) acquired. If the function has already been called
for the link map L with !do_add, then this function will not raise
an exception, otherwise it is possible that it encounters a memory
allocation failure. */
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
index 37db30f3d1e846b6..b4d20fa652f4ba3b 100644
--- a/sysdeps/nptl/fork.c
+++ b/sysdeps/nptl/fork.c
@@ -125,6 +125,9 @@ __libc_fork (void)
/* Reset the lock the dynamic loader uses to protect its data. */
__rtld_lock_initialize (GL(dl_load_lock));
+ /* Reset the lock protecting dynamic TLS related data. */
+ __rtld_lock_initialize (GL(dl_load_tls_lock));
+
/* Run the handlers registered for the child. */
__run_fork_handlers (atfork_run_child, multiple_threads);
}
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index ea4f8894891b2636..98a92f8d6bb119ba 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -25,3 +25,24 @@ $(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library)
endif
endif
+
+ifneq (,$(filter $(subdir),htl nptl))
+ifeq ($(build-shared),yes)
+tests += tst-create1
+endif
+
+tst-create1mod.so-no-z-defs = yes
+
+ifeq ($(build-shared),yes)
+# Build all the modules even when not actually running test programs.
+tests: $(test-modules)
+endif
+
+modules-names += tst-create1mod
+test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
+
+LDFLAGS-tst-create1 = -Wl,-export-dynamic
+$(objpfx)tst-create1: $(libdl) $(shared-thread-library)
+$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so
+
+endif
diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c
new file mode 100644
index 0000000000000000..932586c30990d1d4
--- /dev/null
+++ b/sysdeps/pthread/tst-create1.c
@@ -0,0 +1,119 @@
+/* Verify that pthread_create does not deadlock when ctors take locks.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+
+/*
+Check if ctor and pthread_create deadlocks in
+
+thread 1: dlopen -> ctor -> lock(user_lock)
+thread 2: lock(user_lock) -> pthread_create
+
+or in
+
+thread 1: dlclose -> dtor -> lock(user_lock)
+thread 2: lock(user_lock) -> pthread_create
+*/
+
+static pthread_barrier_t bar_ctor;
+static pthread_barrier_t bar_dtor;
+static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void
+ctor (void)
+{
+ xpthread_barrier_wait (&bar_ctor);
+ dprintf (1, "thread 1: in ctor: started.\n");
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 1: in ctor: locked user_lock.\n");
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 1: in ctor: unlocked user_lock.\n");
+ dprintf (1, "thread 1: in ctor: done.\n");
+}
+
+void
+dtor (void)
+{
+ xpthread_barrier_wait (&bar_dtor);
+ dprintf (1, "thread 1: in dtor: started.\n");
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 1: in dtor: locked user_lock.\n");
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 1: in dtor: unlocked user_lock.\n");
+ dprintf (1, "thread 1: in dtor: done.\n");
+}
+
+static void *
+thread3 (void *a)
+{
+ dprintf (1, "thread 3: started.\n");
+ dprintf (1, "thread 3: done.\n");
+ return 0;
+}
+
+static void *
+thread2 (void *a)
+{
+ pthread_t t3;
+ dprintf (1, "thread 2: started.\n");
+
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 2: locked user_lock.\n");
+ xpthread_barrier_wait (&bar_ctor);
+ t3 = xpthread_create (0, thread3, 0);
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 2: unlocked user_lock.\n");
+ xpthread_join (t3);
+
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 2: locked user_lock.\n");
+ xpthread_barrier_wait (&bar_dtor);
+ t3 = xpthread_create (0, thread3, 0);
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 2: unlocked user_lock.\n");
+ xpthread_join (t3);
+
+ dprintf (1, "thread 2: done.\n");
+ return 0;
+}
+
+static void
+thread1 (void)
+{
+ dprintf (1, "thread 1: started.\n");
+ xpthread_barrier_init (&bar_ctor, NULL, 2);
+ xpthread_barrier_init (&bar_dtor, NULL, 2);
+ pthread_t t2 = xpthread_create (0, thread2, 0);
+ void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL);
+ dprintf (1, "thread 1: dlopen done.\n");
+ xdlclose (p);
+ dprintf (1, "thread 1: dlclose done.\n");
+ xpthread_join (t2);
+ dprintf (1, "thread 1: done.\n");
+}
+
+static int
+do_test (void)
+{
+ thread1 ();
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c
new file mode 100644
index 0000000000000000..62c9006961683177
--- /dev/null
+++ b/sysdeps/pthread/tst-create1mod.c
@@ -0,0 +1,41 @@
+/* Verify that pthread_create does not deadlock when ctors take locks.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+/* Require TLS setup for the module. */
+__thread int tlsvar;
+
+void ctor (void);
+void dtor (void);
+
+static void __attribute__ ((constructor))
+do_init (void)
+{
+ dprintf (1, "constructor started: %d.\n", tlsvar++);
+ ctor ();
+ dprintf (1, "constructor done: %d.\n", tlsvar++);
+}
+
+static void __attribute__ ((destructor))
+do_end (void)
+{
+ dprintf (1, "destructor started: %d.\n", tlsvar++);
+ dtor ();
+ dprintf (1, "destructor done: %d.\n", tlsvar++);
+}

View File

@ -0,0 +1,28 @@
commit d2b997c7172e9a00895a9deb379f8782fbd2e36f
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed Dec 30 23:40:14 2020 +0000
elf: Fix a DTV setup issue [BZ #27136]
The max modid is a valid index in the dtv, it should not be skipped.
The bug is observable if the last module has modid == 64 and its
generation is same or less than the max generation of the previous
modules. Then dtv[0].counter implies dtv[64] is initialized but
it isn't. Fixes bug 27136.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index cccf74b33481b866..0b96b1dceed99d58 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -590,7 +590,7 @@ _dl_allocate_tls_init (void *result)
}
total += cnt;
- if (total >= GL(dl_tls_max_dtv_idx))
+ if (total > GL(dl_tls_max_dtv_idx))
break;
listp = listp->next;

View File

@ -0,0 +1,20 @@
commit 3c7c5117826816021f9d3f352f49e0dd0236cbad
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Nov 30 14:35:54 2021 +0100
elf: Include <stdint.h> in tst-tls20.c
The test uses standard integer types.
diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c
index 831c3336c914790d..18067e6b0a6093f9 100644
--- a/elf/tst-tls20.c
+++ b/elf/tst-tls20.c
@@ -19,6 +19,7 @@
#include <array_length.h>
#include <dlfcn.h>
#include <pthread.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <support/check.h>

View File

@ -0,0 +1,20 @@
commit df4cb2280e32187380520f71bd27ab32252cbc85
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Nov 30 15:39:17 2021 +0100
elf: Include <stdbool.h> in tst-tls20.c
The test uses the bool type.
diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c
index 18067e6b0a6093f9..200dacb748af21a8 100644
--- a/elf/tst-tls20.c
+++ b/elf/tst-tls20.c
@@ -19,6 +19,7 @@
#include <array_length.h>
#include <dlfcn.h>
#include <pthread.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -0,0 +1,62 @@
commit 5cc338565479a620244c2f8ff35956629c4dbf81
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 10 05:14:24 2021 +0100
nptl: Add one more barrier to nptl/tst-create1
Without the bar_ctor_finish barrier, it was possible that thread2
re-locked user_lock before ctor had a chance to lock it. ctor then
blocked in its locking operation, xdlopen from the main thread
did not return, and thread2 was stuck waiting in bar_dtor:
thread 1: started.
thread 2: started.
thread 2: locked user_lock.
constructor started: 0.
thread 1: in ctor: started.
thread 3: started.
thread 3: done.
thread 2: unlocked user_lock.
thread 2: locked user_lock.
Fixes the test in commit 83b5323261bb72313bffcf37476c1b8f0847c736
("elf: Avoid deadlock between pthread_create and ctors [BZ #28357]").
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c
index 932586c30990d1d4..763ded8d7956f943 100644
--- a/sysdeps/pthread/tst-create1.c
+++ b/sysdeps/pthread/tst-create1.c
@@ -33,6 +33,7 @@ thread 2: lock(user_lock) -> pthread_create
*/
static pthread_barrier_t bar_ctor;
+static pthread_barrier_t bar_ctor_finish;
static pthread_barrier_t bar_dtor;
static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -46,6 +47,7 @@ ctor (void)
xpthread_mutex_unlock (&user_lock);
dprintf (1, "thread 1: in ctor: unlocked user_lock.\n");
dprintf (1, "thread 1: in ctor: done.\n");
+ xpthread_barrier_wait (&bar_ctor_finish);
}
void
@@ -81,6 +83,7 @@ thread2 (void *a)
xpthread_mutex_unlock (&user_lock);
dprintf (1, "thread 2: unlocked user_lock.\n");
xpthread_join (t3);
+ xpthread_barrier_wait (&bar_ctor_finish);
xpthread_mutex_lock (&user_lock);
dprintf (1, "thread 2: locked user_lock.\n");
@@ -99,6 +102,7 @@ thread1 (void)
{
dprintf (1, "thread 1: started.\n");
xpthread_barrier_init (&bar_ctor, NULL, 2);
+ xpthread_barrier_init (&bar_ctor_finish, NULL, 2);
xpthread_barrier_init (&bar_dtor, NULL, 2);
pthread_t t2 = xpthread_create (0, thread2, 0);
void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL);

View File

@ -0,0 +1,163 @@
commit 8f85075a2e9c26ff7486d4bbaf358999807d215c
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Dec 31 12:24:38 2020 +0000
elf: Add a DTV setup test [BZ #27136]
The test dlopens a large number of modules with TLS, they are reused
from an existing test.
The test relies on the reuse of slotinfo entries after dlclose, without
bug 27135 fixed this needs a failing dlopen. With a slotinfo list that
has non-monotone increasing generation counters, bug 27136 can trigger.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
elf/Makefile
(usual test differences)
diff --git a/elf/Makefile b/elf/Makefile
index 82fb019a634caf81..0995d810b57d0dda 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -209,7 +209,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-audit14 tst-audit15 tst-audit16 \
tst-tls-ie tst-tls-ie-dlmopen \
argv0test \
- tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask
+ tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
+ tst-tls20
# reldep9
tests-internal += loadtest unload unload2 circleload1 \
neededtest neededtest2 neededtest3 neededtest4 \
@@ -332,6 +333,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
libmarkermod2-1 libmarkermod2-2 \
libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \
libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
+ tst-tls20mod-bad
# Most modules build with _ISOMAC defined, but those filtered out
# depend on internal headers.
@@ -1828,3 +1830,9 @@ $(objpfx)tst-rtld-help.out: $(objpfx)ld.so
fi; \
(exit $$status); \
$(evaluate-test)
+
+# Reuses tst-tls-many-dynamic-modules
+tst-tls20mod-bad.so-no-z-defs = yes
+$(objpfx)tst-tls20: $(libdl) $(shared-thread-library)
+$(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \
+ $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
diff --git a/elf/tst-tls20.c b/elf/tst-tls20.c
new file mode 100644
index 0000000000000000..ac5f8c8d39b66dd6
--- /dev/null
+++ b/elf/tst-tls20.c
@@ -0,0 +1,98 @@
+/* Test dtv setup if entries don't have monotone increasing generation.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+
+#define NMOD 100
+static void *mod[NMOD];
+
+static void
+load_fail (void)
+{
+ /* Expected to fail because of a missing symbol. */
+ void *m = dlopen ("tst-tls20mod-bad.so", RTLD_NOW);
+ if (m != NULL)
+ FAIL_EXIT1 ("dlopen of tst-tls20mod-bad.so succeeded\n");
+}
+
+static void
+load_mod (int i)
+{
+ char *buf = xasprintf ("tst-tls-manydynamic%02dmod.so", i);
+ mod[i] = xdlopen (buf, RTLD_LAZY);
+ free (buf);
+}
+
+static void
+unload_mod (int i)
+{
+ if (mod[i] != NULL)
+ xdlclose (mod[i]);
+ mod[i] = NULL;
+}
+
+static void
+access (int i)
+{
+ char *buf = xasprintf ("tls_global_%02d", i);
+ dlerror ();
+ int *p = dlsym (mod[i], buf);
+ printf ("mod[%d]: &tls = %p\n", i, p);
+ if (p == NULL)
+ FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
+ ++*p;
+ free (buf);
+}
+
+static void *
+start (void *a)
+{
+ for (int i = 0; i < NMOD; i++)
+ if (mod[i] != NULL)
+ access (i);
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ int i;
+
+ for (i = 0; i < NMOD; i++)
+ {
+ load_mod (i);
+ /* Bump the generation of mod[0] without using new dtv slot. */
+ unload_mod (0);
+ load_fail (); /* Ensure GL(dl_tls_dtv_gaps) is true: see bug 27135. */
+ load_mod (0);
+ /* Access TLS in all loaded modules. */
+ pthread_t t = xpthread_create (0, start, 0);
+ xpthread_join (t);
+ }
+ for (i = 0; i < NMOD; i++)
+ unload_mod (i);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-tls20mod-bad.c b/elf/tst-tls20mod-bad.c
new file mode 100644
index 0000000000000000..c1aed8ea7deffd22
--- /dev/null
+++ b/elf/tst-tls20mod-bad.c
@@ -0,0 +1,2 @@
+void missing_symbol (void);
+void f (void) {missing_symbol ();}

View File

@ -0,0 +1,41 @@
commit c489c35054c39d7f2437ca61b369e3ede448f022
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed Nov 30 11:44:25 2016 +0000
elf: Fix comments and logic in _dl_add_to_slotinfo
Since
commit a509eb117fac1d764b15eba64993f4bdb63d7f3c
Avoid late dlopen failure due to scope, TLS slotinfo updates [BZ #25112]
the generation counter update is not needed in the failure path.
That commit ensures allocation in _dl_add_to_slotinfo happens before
the demarcation point in dlopen (it is called twice, first time is for
allocation only where dlopen can still be reverted on failure, then
second time actual dtv updates are done which then cannot fail).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 0b96b1dceed99d58..9375650a3ab5247d 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -998,16 +998,7 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
if (listp == NULL)
{
- /* We ran out of memory. We will simply fail this
- call but don't undo anything we did so far. The
- application will crash or be terminated anyway very
- soon. */
-
- /* We have to do this since some entries in the dtv
- slotinfo array might already point to this
- generation. */
- ++GL(dl_tls_generation);
-
+ /* We ran out of memory while resizing the dtv slotinfo list. */
_dl_signal_error (ENOMEM, "dlopen", NULL, N_("\
cannot create TLS data structures"));
}

View File

@ -0,0 +1,58 @@
commit c0669ae1a629e16b536bf11cdd0865e0dbcf4bee
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Wed Dec 30 21:52:38 2020 +0000
elf: Refactor _dl_update_slotinfo to avoid use after free
map is not valid to access here because it can be freed by a concurrent
dlclose: during tls access (via __tls_get_addr) _dl_update_slotinfo is
called without holding dlopen locks. So don't check the modid of map.
The map == 0 and map != 0 code paths can be shared (avoiding the dtv
resize in case of map == 0 is just an optimization: larger dtv than
necessary would be fine too).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 9375650a3ab5247d..15ed01d795a8627a 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -743,6 +743,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
{
+ size_t modid = total + cnt;
+
size_t gen = listp->slotinfo[cnt].gen;
if (gen > new_gen)
@@ -758,25 +760,12 @@ _dl_update_slotinfo (unsigned long int req_modid)
/* If there is no map this means the entry is empty. */
struct link_map *map = listp->slotinfo[cnt].map;
- if (map == NULL)
- {
- if (dtv[-1].counter >= total + cnt)
- {
- /* If this modid was used at some point the memory
- might still be allocated. */
- free (dtv[total + cnt].pointer.to_free);
- dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
- dtv[total + cnt].pointer.to_free = NULL;
- }
-
- continue;
- }
-
/* Check whether the current dtv array is large enough. */
- size_t modid = map->l_tls_modid;
- assert (total + cnt == modid);
if (dtv[-1].counter < modid)
{
+ if (map == NULL)
+ continue;
+
/* Resize the dtv. */
dtv = _dl_resize_dtv (dtv);

View File

@ -0,0 +1,48 @@
commit 8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Feb 11 11:29:23 2021 +0000
x86_64: Avoid lazy relocation of tlsdesc [BZ #27137]
Lazy tlsdesc relocation is racy because the static tls optimization and
tlsdesc management operations are done without holding the dlopen lock.
This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67
for aarch64, but it fixes a different race: bug 27137.
Another issue is that ld auditing ignores DT_BIND_NOW and thus tries to
relocate tlsdesc lazily, but that does not work in a BIND_NOW module
due to missing DT_TLSDESC_PLT. Unconditionally relocating tlsdesc at
load time fixes this bug 27721 too.
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index e308b662d245cc63..ef5740ba281c7282 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -563,12 +563,21 @@ elf_machine_lazy_rel (struct link_map *map,
}
else if (__glibc_likely (r_type == R_X86_64_TLSDESC))
{
- struct tlsdesc volatile * __attribute__((__unused__)) td =
- (struct tlsdesc volatile *)reloc_addr;
+ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
+ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
+ const ElfW (Sym) *sym = &symtab[symndx];
+ const struct r_found_version *version = NULL;
- td->arg = (void*)reloc;
- td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
- + map->l_addr);
+ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW (Half) *vernum =
+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ version = &map->l_versions[vernum[symndx] & 0x7fff];
+ }
+
+ /* Always initialize TLS descriptors completely at load time, in
+ case static TLS is allocated for it that requires locking. */
+ elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
}
else if (__glibc_unlikely (r_type == R_X86_64_IRELATIVE))
{

View File

@ -0,0 +1,116 @@
commit ddcacd91cc10ff92d6201eda87047d029c14158d
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Feb 11 11:40:11 2021 +0000
i386: Avoid lazy relocation of tlsdesc [BZ #27137]
Lazy tlsdesc relocation is racy because the static tls optimization and
tlsdesc management operations are done without holding the dlopen lock.
This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67
for aarch64, but it fixes a different race: bug 27137.
On i386 the code is a bit more complicated than on x86_64 because both
rel and rela relocs are supported.
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index e5776ef7bc8ad749..3a30671591284d79 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -679,50 +679,32 @@ elf_machine_lazy_rel (struct link_map *map,
}
else if (__glibc_likely (r_type == R_386_TLS_DESC))
{
- struct tlsdesc volatile * __attribute__((__unused__)) td =
- (struct tlsdesc volatile *)reloc_addr;
-
- /* Handle relocations that reference the local *ABS* in a simple
- way, so as to preserve a potential addend. */
- if (ELF32_R_SYM (reloc->r_info) == 0)
- td->entry = _dl_tlsdesc_resolve_abs_plus_addend;
- /* Given a known-zero addend, we can store a pointer to the
- reloc in the arg position. */
- else if (td->arg == 0)
- {
- td->arg = (void*)reloc;
- td->entry = _dl_tlsdesc_resolve_rel;
- }
- else
- {
- /* We could handle non-*ABS* relocations with non-zero addends
- by allocating dynamically an arg to hold a pointer to the
- reloc, but that sounds pointless. */
- const Elf32_Rel *const r = reloc;
- /* The code below was borrowed from elf_dynamic_do_rel(). */
- const ElfW(Sym) *const symtab =
- (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const Elf32_Rel *const r = reloc;
+ /* The code below was borrowed from elf_dynamic_do_rel(). */
+ const ElfW(Sym) *const symtab =
+ (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ /* Always initialize TLS descriptors completely at load time, in
+ case static TLS is allocated for it that requires locking. */
# ifdef RTLD_BOOTSTRAP
- /* The dynamic linker always uses versioning. */
- assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
+ /* The dynamic linker always uses versioning. */
+ assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
# else
- if (map->l_info[VERSYMIDX (DT_VERSYM)])
+ if (map->l_info[VERSYMIDX (DT_VERSYM)])
# endif
- {
- const ElfW(Half) *const version =
- (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
- ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
- &map->l_versions[ndx],
- (void *) (l_addr + r->r_offset), skip_ifunc);
- }
+ {
+ const ElfW(Half) *const version =
+ (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r->r_offset), skip_ifunc);
+ }
# ifndef RTLD_BOOTSTRAP
- else
- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
- (void *) (l_addr + r->r_offset), skip_ifunc);
+ else
+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
+ (void *) (l_addr + r->r_offset), skip_ifunc);
# endif
- }
}
else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
{
@@ -749,11 +731,21 @@ elf_machine_lazy_rela (struct link_map *map,
;
else if (__glibc_likely (r_type == R_386_TLS_DESC))
{
- struct tlsdesc volatile * __attribute__((__unused__)) td =
- (struct tlsdesc volatile *)reloc_addr;
+ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
+ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
+ const ElfW (Sym) *sym = &symtab[symndx];
+ const struct r_found_version *version = NULL;
+
+ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW (Half) *vernum =
+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ version = &map->l_versions[vernum[symndx] & 0x7fff];
+ }
- td->arg = (void*)reloc;
- td->entry = _dl_tlsdesc_resolve_rela;
+ /* Always initialize TLS descriptors completely at load time, in
+ case static TLS is allocated for it that requires locking. */
+ elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
}
else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
{

View File

@ -0,0 +1,277 @@
commit 55c9f3238080e9aba733bc0902779c46cfa16446
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Feb 11 11:52:24 2021 +0000
x86_64: Remove lazy tlsdesc relocation related code
_dl_tlsdesc_resolve_rela and _dl_tlsdesc_resolve_hold are only used for
lazy tlsdesc relocation processing which is no longer supported.
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index ef5740ba281c7282..b94d3b39ec1dca64 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -127,10 +127,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
}
}
- if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
- *(ElfW(Addr)*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
- = (ElfW(Addr)) &_dl_tlsdesc_resolve_rela;
-
return lazy;
}
diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S
index 80d771cd887dd626..77e78cf0a6d8babc 100644
--- a/sysdeps/x86_64/dl-tlsdesc.S
+++ b/sysdeps/x86_64/dl-tlsdesc.S
@@ -148,107 +148,3 @@ _dl_tlsdesc_dynamic:
cfi_endproc
.size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
#endif /* SHARED */
-
- /* This function is a wrapper for a lazy resolver for TLS_DESC
- RELA relocations. The incoming 0(%rsp) points to the caller's
- link map, pushed by the dynamic object's internal lazy TLS
- resolver front-end before tail-calling us. We need to pop it
- ourselves. %rax points to a TLS descriptor, such that 0(%rax)
- holds the address of the internal resolver front-end (unless
- some other thread beat us to resolving it) and 8(%rax) holds a
- pointer to the relocation.
-
- When the actual resolver returns, it will have adjusted the
- TLS descriptor such that we can tail-call it for it to return
- the TP offset of the symbol. */
-
- .hidden _dl_tlsdesc_resolve_rela
- .global _dl_tlsdesc_resolve_rela
- .type _dl_tlsdesc_resolve_rela,@function
- cfi_startproc
- .align 16
- /* The PLT entry will have pushed the link_map pointer. */
-_dl_tlsdesc_resolve_rela:
- _CET_ENDBR
- cfi_adjust_cfa_offset (8)
- /* Save all call-clobbered registers. Add 8 bytes for push in
- the PLT entry to align the stack. */
- subq $80, %rsp
- cfi_adjust_cfa_offset (80)
- movq %rax, (%rsp)
- movq %rdi, 8(%rsp)
- movq %rax, %rdi /* Pass tlsdesc* in %rdi. */
- movq %rsi, 16(%rsp)
- movq 80(%rsp), %rsi /* Pass link_map* in %rsi. */
- movq %r8, 24(%rsp)
- movq %r9, 32(%rsp)
- movq %r10, 40(%rsp)
- movq %r11, 48(%rsp)
- movq %rdx, 56(%rsp)
- movq %rcx, 64(%rsp)
- call _dl_tlsdesc_resolve_rela_fixup
- movq (%rsp), %rax
- movq 8(%rsp), %rdi
- movq 16(%rsp), %rsi
- movq 24(%rsp), %r8
- movq 32(%rsp), %r9
- movq 40(%rsp), %r10
- movq 48(%rsp), %r11
- movq 56(%rsp), %rdx
- movq 64(%rsp), %rcx
- addq $88, %rsp
- cfi_adjust_cfa_offset (-88)
- jmp *(%rax)
- cfi_endproc
- .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
-
- /* This function is a placeholder for lazy resolving of TLS
- relocations. Once some thread starts resolving a TLS
- relocation, it sets up the TLS descriptor to use this
- resolver, such that other threads that would attempt to
- resolve it concurrently may skip the call to the original lazy
- resolver and go straight to a condition wait.
-
- When the actual resolver returns, it will have adjusted the
- TLS descriptor such that we can tail-call it for it to return
- the TP offset of the symbol. */
-
- .hidden _dl_tlsdesc_resolve_hold
- .global _dl_tlsdesc_resolve_hold
- .type _dl_tlsdesc_resolve_hold,@function
- cfi_startproc
- .align 16
-_dl_tlsdesc_resolve_hold:
-0:
- _CET_ENDBR
- /* Save all call-clobbered registers. */
- subq $72, %rsp
- cfi_adjust_cfa_offset (72)
- movq %rax, (%rsp)
- movq %rdi, 8(%rsp)
- movq %rax, %rdi /* Pass tlsdesc* in %rdi. */
- movq %rsi, 16(%rsp)
- /* Pass _dl_tlsdesc_resolve_hold's address in %rsi. */
- leaq . - _dl_tlsdesc_resolve_hold(%rip), %rsi
- movq %r8, 24(%rsp)
- movq %r9, 32(%rsp)
- movq %r10, 40(%rsp)
- movq %r11, 48(%rsp)
- movq %rdx, 56(%rsp)
- movq %rcx, 64(%rsp)
- call _dl_tlsdesc_resolve_hold_fixup
-1:
- movq (%rsp), %rax
- movq 8(%rsp), %rdi
- movq 16(%rsp), %rsi
- movq 24(%rsp), %r8
- movq 32(%rsp), %r9
- movq 40(%rsp), %r10
- movq 48(%rsp), %r11
- movq 56(%rsp), %rdx
- movq 64(%rsp), %rcx
- addq $72, %rsp
- cfi_adjust_cfa_offset (-72)
- jmp *(%rax)
- cfi_endproc
- .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
diff --git a/sysdeps/x86_64/dl-tlsdesc.h b/sysdeps/x86_64/dl-tlsdesc.h
index 66e659bb5c7ede74..1cde1ee9664f4908 100644
--- a/sysdeps/x86_64/dl-tlsdesc.h
+++ b/sysdeps/x86_64/dl-tlsdesc.h
@@ -55,9 +55,7 @@ struct tlsdesc_dynamic_arg
extern ptrdiff_t attribute_hidden
_dl_tlsdesc_return(struct tlsdesc *on_rax),
- _dl_tlsdesc_undefweak(struct tlsdesc *on_rax),
- _dl_tlsdesc_resolve_rela(struct tlsdesc *on_rax),
- _dl_tlsdesc_resolve_hold(struct tlsdesc *on_rax);
+ _dl_tlsdesc_undefweak(struct tlsdesc *on_rax);
# ifdef SHARED
extern void *_dl_make_tlsdesc_dynamic (struct link_map *map,
diff --git a/sysdeps/x86_64/tlsdesc.c b/sysdeps/x86_64/tlsdesc.c
index 302d097dbb0c4f1e..61a19ae26944c84f 100644
--- a/sysdeps/x86_64/tlsdesc.c
+++ b/sysdeps/x86_64/tlsdesc.c
@@ -16,120 +16,13 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <link.h>
#include <ldsodefs.h>
-#include <elf/dynamic-link.h>
#include <tls.h>
#include <dl-tlsdesc.h>
#include <dl-unmap-segments.h>
+#define _dl_tlsdesc_resolve_hold 0
#include <tlsdeschtab.h>
-/* The following 2 functions take a caller argument, that contains the
- address expected to be in the TLS descriptor. If it's changed, we
- want to return immediately. */
-
-/* This function is used to lazily resolve TLS_DESC RELA relocations.
- The argument location is used to hold a pointer to the relocation. */
-
-void
-attribute_hidden
-_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td,
- struct link_map *l)
-{
- const ElfW(Rela) *reloc = td->arg;
-
- if (_dl_tlsdesc_resolve_early_return_p
- (td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr)))
- return;
-
- /* The code below was borrowed from _dl_fixup(). */
- const ElfW(Sym) *const symtab
- = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
- const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
- lookup_t result;
-
- /* Look up the target symbol. If the normal lookup rules are not
- used don't look in the global scope. */
- if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
- && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
- {
- const struct r_found_version *version = NULL;
-
- if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
- {
- const ElfW(Half) *vernum =
- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
- ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
- version = &l->l_versions[ndx];
- if (version->hash == 0)
- version = NULL;
- }
-
- result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
- l->l_scope, version, ELF_RTYPE_CLASS_PLT,
- DL_LOOKUP_ADD_DEPENDENCY, NULL);
- }
- else
- {
- /* We already found the symbol. The module (and therefore its load
- address) is also known. */
- result = l;
- }
-
- if (! sym)
- {
- td->arg = (void*)reloc->r_addend;
- td->entry = _dl_tlsdesc_undefweak;
- }
- else
- {
-# ifndef SHARED
- CHECK_STATIC_TLS (l, result);
-# else
- if (!TRY_STATIC_TLS (l, result))
- {
- td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value
- + reloc->r_addend);
- td->entry = _dl_tlsdesc_dynamic;
- }
- else
-# endif
- {
- td->arg = (void*)(sym->st_value - result->l_tls_offset
- + reloc->r_addend);
- td->entry = _dl_tlsdesc_return;
- }
- }
-
- _dl_tlsdesc_wake_up_held_fixups ();
-}
-
-/* This function is used to avoid busy waiting for other threads to
- complete the lazy relocation. Once another thread wins the race to
- relocate a TLS descriptor, it sets the descriptor up such that this
- function is called to wait until the resolver releases the
- lock. */
-
-void
-attribute_hidden
-_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
- void *caller)
-{
- /* Maybe we're lucky and can return early. */
- if (caller != td->entry)
- return;
-
- /* Locking here will stop execution until the running resolver runs
- _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
-
- FIXME: We'd be better off waiting on a condition variable, such
- that we didn't have to hold the lock throughout the relocation
- processing. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
-}
-
/* Unmap the dynamic object, but also release its TLS descriptor table
if there is one. */

View File

@ -0,0 +1,443 @@
commit a75a02a696f9f869d77b17b99964823aa8833a8b
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date: Thu Feb 11 11:58:20 2021 +0000
i386: Remove lazy tlsdesc relocation related code
Like in commit e75711ebfa976d5468ec292282566a18b07e4d67 for x86_64,
remove unused lazy tlsdesc relocation processing code:
_dl_tlsdesc_resolve_abs_plus_addend
_dl_tlsdesc_resolve_rel
_dl_tlsdesc_resolve_rela
_dl_tlsdesc_resolve_hold
diff --git a/sysdeps/i386/dl-tlsdesc.S b/sysdeps/i386/dl-tlsdesc.S
index 128f0af3188f46bb..22ecb2c6adc6cc6e 100644
--- a/sysdeps/i386/dl-tlsdesc.S
+++ b/sysdeps/i386/dl-tlsdesc.S
@@ -138,159 +138,3 @@ _dl_tlsdesc_dynamic:
cfi_endproc
.size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
#endif /* SHARED */
-
- /* This function is a wrapper for a lazy resolver for TLS_DESC
- REL relocations that reference the *ABS* segment in their own
- link maps. %ebx points to the caller's GOT. %eax points to a
- TLS descriptor, such that 0(%eax) holds the address of the
- resolver wrapper itself (unless some other thread beat us to
- it) and 4(%eax) holds the addend in the relocation.
-
- When the actual resolver returns, it will have adjusted the
- TLS descriptor such that we can tail-call it for it to return
- the TP offset of the symbol. */
-
- .hidden _dl_tlsdesc_resolve_abs_plus_addend
- .global _dl_tlsdesc_resolve_abs_plus_addend
- .type _dl_tlsdesc_resolve_abs_plus_addend,@function
- cfi_startproc
- .align 16
-_dl_tlsdesc_resolve_abs_plus_addend:
-0:
- _CET_ENDBR
- pushl %eax
- cfi_adjust_cfa_offset (4)
- pushl %ecx
- cfi_adjust_cfa_offset (4)
- pushl %edx
- cfi_adjust_cfa_offset (4)
- movl $1f - 0b, %ecx
- movl 4(%ebx), %edx
- call _dl_tlsdesc_resolve_abs_plus_addend_fixup
-1:
- popl %edx
- cfi_adjust_cfa_offset (-4)
- popl %ecx
- cfi_adjust_cfa_offset (-4)
- popl %eax
- cfi_adjust_cfa_offset (-4)
- jmp *(%eax)
- cfi_endproc
- .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
-
- /* This function is a wrapper for a lazy resolver for TLS_DESC
- REL relocations that had zero addends. %ebx points to the
- caller's GOT. %eax points to a TLS descriptor, such that
- 0(%eax) holds the address of the resolver wrapper itself
- (unless some other thread beat us to it) and 4(%eax) holds a
- pointer to the relocation.
-
- When the actual resolver returns, it will have adjusted the
- TLS descriptor such that we can tail-call it for it to return
- the TP offset of the symbol. */
-
- .hidden _dl_tlsdesc_resolve_rel
- .global _dl_tlsdesc_resolve_rel
- .type _dl_tlsdesc_resolve_rel,@function
- cfi_startproc
- .align 16
-_dl_tlsdesc_resolve_rel:
-0:
- _CET_ENDBR
- pushl %eax
- cfi_adjust_cfa_offset (4)
- pushl %ecx
- cfi_adjust_cfa_offset (4)
- pushl %edx
- cfi_adjust_cfa_offset (4)
- movl $1f - 0b, %ecx
- movl 4(%ebx), %edx
- call _dl_tlsdesc_resolve_rel_fixup
-1:
- popl %edx
- cfi_adjust_cfa_offset (-4)
- popl %ecx
- cfi_adjust_cfa_offset (-4)
- popl %eax
- cfi_adjust_cfa_offset (-4)
- jmp *(%eax)
- cfi_endproc
- .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
-
- /* This function is a wrapper for a lazy resolver for TLS_DESC
- RELA relocations. %ebx points to the caller's GOT. %eax
- points to a TLS descriptor, such that 0(%eax) holds the
- address of the resolver wrapper itself (unless some other
- thread beat us to it) and 4(%eax) holds a pointer to the
- relocation.
-
- When the actual resolver returns, it will have adjusted the
- TLS descriptor such that we can tail-call it for it to return
- the TP offset of the symbol. */
-
- .hidden _dl_tlsdesc_resolve_rela
- .global _dl_tlsdesc_resolve_rela
- .type _dl_tlsdesc_resolve_rela,@function
- cfi_startproc
- .align 16
-_dl_tlsdesc_resolve_rela:
-0:
- _CET_ENDBR
- pushl %eax
- cfi_adjust_cfa_offset (4)
- pushl %ecx
- cfi_adjust_cfa_offset (4)
- pushl %edx
- cfi_adjust_cfa_offset (4)
- movl $1f - 0b, %ecx
- movl 4(%ebx), %edx
- call _dl_tlsdesc_resolve_rela_fixup
-1:
- popl %edx
- cfi_adjust_cfa_offset (-4)
- popl %ecx
- cfi_adjust_cfa_offset (-4)
- popl %eax
- cfi_adjust_cfa_offset (-4)
- jmp *(%eax)
- cfi_endproc
- .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
-
- /* This function is a placeholder for lazy resolving of TLS
- relocations. Once some thread starts resolving a TLS
- relocation, it sets up the TLS descriptor to use this
- resolver, such that other threads that would attempt to
- resolve it concurrently may skip the call to the original lazy
- resolver and go straight to a condition wait.
-
- When the actual resolver returns, it will have adjusted the
- TLS descriptor such that we can tail-call it for it to return
- the TP offset of the symbol. */
-
- .hidden _dl_tlsdesc_resolve_hold
- .global _dl_tlsdesc_resolve_hold
- .type _dl_tlsdesc_resolve_hold,@function
- cfi_startproc
- .align 16
-_dl_tlsdesc_resolve_hold:
-0:
- _CET_ENDBR
- pushl %eax
- cfi_adjust_cfa_offset (4)
- pushl %ecx
- cfi_adjust_cfa_offset (4)
- pushl %edx
- cfi_adjust_cfa_offset (4)
- movl $1f - 0b, %ecx
- movl 4(%ebx), %edx
- call _dl_tlsdesc_resolve_hold_fixup
-1:
- popl %edx
- cfi_adjust_cfa_offset (-4)
- popl %ecx
- cfi_adjust_cfa_offset (-4)
- popl %eax
- cfi_adjust_cfa_offset (-4)
- jmp *(%eax)
- cfi_endproc
- .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
diff --git a/sysdeps/i386/dl-tlsdesc.h b/sysdeps/i386/dl-tlsdesc.h
index c8a1e056150dc418..1a1a22c303baf85b 100644
--- a/sysdeps/i386/dl-tlsdesc.h
+++ b/sysdeps/i386/dl-tlsdesc.h
@@ -43,11 +43,7 @@ struct tlsdesc_dynamic_arg
extern ptrdiff_t attribute_hidden __attribute__ ((regparm (1)))
_dl_tlsdesc_return (struct tlsdesc *),
- _dl_tlsdesc_undefweak (struct tlsdesc *),
- _dl_tlsdesc_resolve_abs_plus_addend (struct tlsdesc *),
- _dl_tlsdesc_resolve_rel (struct tlsdesc *),
- _dl_tlsdesc_resolve_rela (struct tlsdesc *),
- _dl_tlsdesc_resolve_hold (struct tlsdesc *);
+ _dl_tlsdesc_undefweak (struct tlsdesc *);
# ifdef SHARED
extern void *_dl_make_tlsdesc_dynamic (struct link_map *map,
diff --git a/sysdeps/i386/tlsdesc.c b/sysdeps/i386/tlsdesc.c
index 82fa8a1d35fd1912..1b4227c8381e1b3d 100644
--- a/sysdeps/i386/tlsdesc.c
+++ b/sysdeps/i386/tlsdesc.c
@@ -16,242 +16,13 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <link.h>
#include <ldsodefs.h>
-#include <elf/dynamic-link.h>
#include <tls.h>
#include <dl-tlsdesc.h>
#include <dl-unmap-segments.h>
+#define _dl_tlsdesc_resolve_hold 0
#include <tlsdeschtab.h>
-/* The following 4 functions take an entry_check_offset argument.
- It's computed by the caller as an offset between its entry point
- and the call site, such that by adding the built-in return address
- that is implicitly passed to the function with this offset, we can
- easily obtain the caller's entry point to compare with the entry
- point given in the TLS descriptor. If it's changed, we want to
- return immediately. */
-
-/* This function is used to lazily resolve TLS_DESC REL relocations
- that reference the *ABS* segment in their own link maps. The
- argument is the addend originally stored there. */
-
-void
-__attribute__ ((regparm (3))) attribute_hidden
-_dl_tlsdesc_resolve_abs_plus_addend_fixup (struct tlsdesc volatile *td,
- struct link_map *l,
- ptrdiff_t entry_check_offset)
-{
- ptrdiff_t addend = (ptrdiff_t) td->arg;
-
- if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0)
- - entry_check_offset))
- return;
-
-#ifndef SHARED
- CHECK_STATIC_TLS (l, l);
-#else
- if (!TRY_STATIC_TLS (l, l))
- {
- td->arg = _dl_make_tlsdesc_dynamic (l, addend);
- td->entry = _dl_tlsdesc_dynamic;
- }
- else
-#endif
- {
- td->arg = (void*) (addend - l->l_tls_offset);
- td->entry = _dl_tlsdesc_return;
- }
-
- _dl_tlsdesc_wake_up_held_fixups ();
-}
-
-/* This function is used to lazily resolve TLS_DESC REL relocations
- that originally had zero addends. The argument location, that
- originally held the addend, is used to hold a pointer to the
- relocation, but it has to be restored before we call the function
- that applies relocations. */
-
-void
-__attribute__ ((regparm (3))) attribute_hidden
-_dl_tlsdesc_resolve_rel_fixup (struct tlsdesc volatile *td,
- struct link_map *l,
- ptrdiff_t entry_check_offset)
-{
- const ElfW(Rel) *reloc = td->arg;
-
- if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0)
- - entry_check_offset))
- return;
-
- /* The code below was borrowed from _dl_fixup(),
- except for checking for STB_LOCAL. */
- const ElfW(Sym) *const symtab
- = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
- const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
- lookup_t result;
-
- /* Look up the target symbol. If the normal lookup rules are not
- used don't look in the global scope. */
- if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
- && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
- {
- const struct r_found_version *version = NULL;
-
- if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
- {
- const ElfW(Half) *vernum =
- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
- ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
- version = &l->l_versions[ndx];
- if (version->hash == 0)
- version = NULL;
- }
-
- result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
- l->l_scope, version, ELF_RTYPE_CLASS_PLT,
- DL_LOOKUP_ADD_DEPENDENCY, NULL);
- }
- else
- {
- /* We already found the symbol. The module (and therefore its load
- address) is also known. */
- result = l;
- }
-
- if (!sym)
- {
- td->arg = 0;
- td->entry = _dl_tlsdesc_undefweak;
- }
- else
- {
-# ifndef SHARED
- CHECK_STATIC_TLS (l, result);
-# else
- if (!TRY_STATIC_TLS (l, result))
- {
- td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value);
- td->entry = _dl_tlsdesc_dynamic;
- }
- else
-# endif
- {
- td->arg = (void*)(sym->st_value - result->l_tls_offset);
- td->entry = _dl_tlsdesc_return;
- }
- }
-
- _dl_tlsdesc_wake_up_held_fixups ();
-}
-
-/* This function is used to lazily resolve TLS_DESC RELA relocations.
- The argument location is used to hold a pointer to the relocation. */
-
-void
-__attribute__ ((regparm (3))) attribute_hidden
-_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td,
- struct link_map *l,
- ptrdiff_t entry_check_offset)
-{
- const ElfW(Rela) *reloc = td->arg;
-
- if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0)
- - entry_check_offset))
- return;
-
- /* The code below was borrowed from _dl_fixup(),
- except for checking for STB_LOCAL. */
- const ElfW(Sym) *const symtab
- = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
- const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
- lookup_t result;
-
- /* Look up the target symbol. If the normal lookup rules are not
- used don't look in the global scope. */
- if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
- && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
- {
- const struct r_found_version *version = NULL;
-
- if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
- {
- const ElfW(Half) *vernum =
- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
- ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
- version = &l->l_versions[ndx];
- if (version->hash == 0)
- version = NULL;
- }
-
- result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
- l->l_scope, version, ELF_RTYPE_CLASS_PLT,
- DL_LOOKUP_ADD_DEPENDENCY, NULL);
- }
- else
- {
- /* We already found the symbol. The module (and therefore its load
- address) is also known. */
- result = l;
- }
-
- if (!sym)
- {
- td->arg = (void*) reloc->r_addend;
- td->entry = _dl_tlsdesc_undefweak;
- }
- else
- {
-# ifndef SHARED
- CHECK_STATIC_TLS (l, result);
-# else
- if (!TRY_STATIC_TLS (l, result))
- {
- td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value
- + reloc->r_addend);
- td->entry = _dl_tlsdesc_dynamic;
- }
- else
-# endif
- {
- td->arg = (void*) (sym->st_value - result->l_tls_offset
- + reloc->r_addend);
- td->entry = _dl_tlsdesc_return;
- }
- }
-
- _dl_tlsdesc_wake_up_held_fixups ();
-}
-
-/* This function is used to avoid busy waiting for other threads to
- complete the lazy relocation. Once another thread wins the race to
- relocate a TLS descriptor, it sets the descriptor up such that this
- function is called to wait until the resolver releases the
- lock. */
-
-void
-__attribute__ ((regparm (3))) attribute_hidden
-_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
- struct link_map *l __attribute__((__unused__)),
- ptrdiff_t entry_check_offset)
-{
- /* Maybe we're lucky and can return early. */
- if (__builtin_return_address (0) - entry_check_offset != td->entry)
- return;
-
- /* Locking here will stop execution until the running resolver runs
- _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
-
- FIXME: We'd be better off waiting on a condition variable, such
- that we didn't have to hold the lock throughout the relocation
- processing. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
-}
-
-
/* Unmap the dynamic object, but also release its TLS descriptor table
if there is one. */

View File

@ -0,0 +1,205 @@
Bug RHEL #2000374
Bugs Upstream #24046, #25923
This patch provides 12-hour time for the English language UTF-8 locale as a
new locale en_US@ampm.UTF-8.
Two upstream commits were applied to en_US to create the new file en_US@ampm:
Upstream commit: 7395f3a0efad9fc51bb54fa383ef6524702e0c49
Upstream commit: 8cde977077b3568310c743b21a905ca9ab286724
en_US remains unchanged and the new file en_US@ampm is now supported.
diff -Nrup a/localedata/locales/en_US@ampm b/localedata/locales/en_US@ampm
--- a/localedata/locales/en_US@ampm 1969-12-31 19:00:00.000000000 -0500
+++ b/localedata/locales/en_US@ampm 2021-11-17 17:19:15.338720307 -0500
@@ -0,0 +1,177 @@
+comment_char %
+escape_char /
+
+% This file is part of the GNU C Library and contains locale data.
+% The Free Software Foundation does not claim any copyright interest
+% in the locale data contained in this file. The foregoing does not
+% affect the license of the GNU C Library as a whole. It does not
+% exempt you from the conditions of the license if your use would
+% otherwise be governed by that license.
+
+% Locale for English locale in the USA
+% Contributed by Ulrich Drepper <drepper@redhat.com>, 2000
+
+LC_IDENTIFICATION
+title "English locale for the USA"
+source "Free Software Foundation, Inc."
+address "http:////www.gnu.org//software//libc//"
+contact ""
+email "bug-glibc-locales@gnu.org"
+tel ""
+fax ""
+language "American English"
+territory "United States"
+revision "1.0"
+date "2000-06-24"
+
+category "i18n:2012";LC_IDENTIFICATION
+category "i18n:2012";LC_CTYPE
+category "i18n:2012";LC_COLLATE
+category "i18n:2012";LC_TIME
+category "i18n:2012";LC_NUMERIC
+category "i18n:2012";LC_MONETARY
+category "i18n:2012";LC_MESSAGES
+category "i18n:2012";LC_PAPER
+category "i18n:2012";LC_NAME
+category "i18n:2012";LC_ADDRESS
+category "i18n:2012";LC_TELEPHONE
+category "i18n:2012";LC_MEASUREMENT
+END LC_IDENTIFICATION
+
+LC_CTYPE
+copy "en_GB"
+END LC_CTYPE
+
+LC_COLLATE
+
+% Copy the template from ISO/IEC 14651
+copy "iso14651_t1"
+
+END LC_COLLATE
+
+LC_MONETARY
+int_curr_symbol "USD "
+currency_symbol "$"
+mon_decimal_point "."
+mon_thousands_sep ","
+mon_grouping 3;3
+positive_sign ""
+negative_sign "-"
+int_frac_digits 2
+frac_digits 2
+p_cs_precedes 1
+int_p_sep_by_space 1
+p_sep_by_space 0
+n_cs_precedes 1
+int_n_sep_by_space 1
+n_sep_by_space 0
+p_sign_posn 1
+n_sign_posn 1
+%
+END LC_MONETARY
+
+LC_NUMERIC
+decimal_point "."
+thousands_sep ","
+grouping 3;3
+END LC_NUMERIC
+
+LC_TIME
+abday "Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat"
+day "Sunday";/
+ "Monday";/
+ "Tuesday";/
+ "Wednesday";/
+ "Thursday";/
+ "Friday";/
+ "Saturday"
+
+week 7;19971130;1
+abmon "Jan";"Feb";/
+ "Mar";"Apr";/
+ "May";"Jun";/
+ "Jul";"Aug";/
+ "Sep";"Oct";/
+ "Nov";"Dec"
+mon "January";/
+ "February";/
+ "March";/
+ "April";/
+ "May";/
+ "June";/
+ "July";/
+ "August";/
+ "September";/
+ "October";/
+ "November";/
+ "December"
+% Appropriate date and time representation (%c)
+d_t_fmt "%a %d %b %Y %r %Z"
+%
+% Appropriate date representation (%x)
+d_fmt "%m//%d//%Y"
+%
+% Appropriate time representation (%X)
+t_fmt "%r"
+%
+% Appropriate AM/PM time representation (%r)
+t_fmt_ampm "%I:%M:%S %p"
+%
+% Appropriate date and time representation for date(1). This is
+% different from d_t_fmt for historical reasons and has been different
+% since 2000 when date_fmt was added as a GNU extension. At the end
+% of 2018 it was adjusted to use 12H time (bug 24046) instead of 24H.
+date_fmt "%a %b %e %r %Z %Y"
+%
+% Strings for AM/PM
+%
+am_pm "AM";"PM"
+END LC_TIME
+
+LC_MESSAGES
+yesexpr "^[+1yY]"
+noexpr "^[-0nN]"
+yesstr "yes"
+nostr "no"
+END LC_MESSAGES
+
+LC_PAPER
+height 279
+width 216
+END LC_PAPER
+
+LC_NAME
+name_fmt "%d%t%g%t%m%t%f"
+name_miss "Miss."
+name_mr "Mr."
+name_mrs "Mrs."
+name_ms "Ms."
+END LC_NAME
+
+
+LC_ADDRESS
+postal_fmt "%a%N%f%N%d%N%b%N%h %s %e %r%N%T, %S %z%N%c%N"
+country_name "United States"
+country_post "USA"
+country_ab2 "US"
+country_ab3 "USA"
+country_num 840
+country_car "USA"
+country_isbn 0
+lang_name "English"
+lang_ab "en"
+lang_term "eng"
+lang_lib "eng"
+END LC_ADDRESS
+
+LC_TELEPHONE
+tel_int_fmt "+%c (%a) %l"
+tel_dom_fmt "(%a) %l"
+int_select "11"
+int_prefix "1"
+END LC_TELEPHONE
+
+LC_MEASUREMENT
+% US customary units.
+measurement 2
+END LC_MEASUREMENT
diff -Nrup a/localedata/SUPPORTED b/localedata/SUPPORTED
--- a/localedata/SUPPORTED 2021-11-17 17:14:33.831631483 -0500
+++ b/localedata/SUPPORTED 2021-11-17 17:21:16.418188595 -0500
@@ -159,6 +159,7 @@ en_SG/ISO-8859-1 \
en_US.UTF-8/UTF-8 \
en_US/ISO-8859-1 \
en_US.ISO-8859-15/ISO-8859-15 \
+en_US@ampm.UTF-8/UTF-8 \
en_ZA.UTF-8/UTF-8 \
en_ZA/ISO-8859-1 \
en_ZM/UTF-8 \

View File

@ -0,0 +1,92 @@
commit 28c30a6232aa9a54783c146590498a061fc0112a
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date: Sun Feb 9 19:50:21 2020 +0000
pthread: Move most once tests from nptl to sysdeps/pthread
So they can be checked with htl too.
# Conflicts:
# sysdeps/pthread/Makefile
# (Moved only the tests in this commit which subsequently
# needed for the pthread_once fix)
diff --git a/nptl/Makefile b/nptl/Makefile
index b14de3ffb330c10b..dcf3868869767015 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -260,7 +260,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \
tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \
tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \
- tst-once1 tst-once2 tst-once3 tst-once4 tst-once5 \
+ tst-once5 \
tst-key1 tst-key2 tst-key3 tst-key4 \
tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
tst-sem8 tst-sem9 tst-sem10 tst-sem14 \
@@ -384,8 +384,7 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
tst-cancelx6 tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 \
tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15 \
tst-cancelx16 tst-cancelx17 tst-cancelx18 tst-cancelx20 tst-cancelx21 \
- tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \
- tst-oncex3 tst-oncex4
+ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4
ifeq ($(build-shared),yes)
tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \
tst-audit-threads
@@ -525,8 +524,6 @@ CFLAGS-tst-cleanupx2.c += -fexceptions
CFLAGS-tst-cleanupx3.c += -fexceptions
CFLAGS-tst-cleanupx4.c += -fexceptions
CFLAGS-tst-cleanupx4aux.c += -fexceptions
-CFLAGS-tst-oncex3.c += -fexceptions
-CFLAGS-tst-oncex4.c += -fexceptions
CFLAGS-tst-align.c += $(stack-align-test-flags)
CFLAGS-tst-align3.c += $(stack-align-test-flags)
CFLAGS-tst-initializers1.c += -W -Wall -Werror
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 98a92f8d6bb119ba..14ef04247cb84ad3 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -33,11 +33,18 @@ endif
tst-create1mod.so-no-z-defs = yes
+tests += tst-once1 tst-once2 tst-once3 tst-once4
+
+tests += tst-oncex3 tst-oncex4
+
ifeq ($(build-shared),yes)
# Build all the modules even when not actually running test programs.
tests: $(test-modules)
endif
+CFLAGS-tst-oncex3.c += -fexceptions
+CFLAGS-tst-oncex4.c += -fexceptions
+
modules-names += tst-create1mod
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
diff --git a/nptl/tst-once1.c b/sysdeps/pthread/tst-once1.c
similarity index 100%
rename from nptl/tst-once1.c
rename to sysdeps/pthread/tst-once1.c
diff --git a/nptl/tst-once2.c b/sysdeps/pthread/tst-once2.c
similarity index 100%
rename from nptl/tst-once2.c
rename to sysdeps/pthread/tst-once2.c
diff --git a/nptl/tst-once3.c b/sysdeps/pthread/tst-once3.c
similarity index 100%
rename from nptl/tst-once3.c
rename to sysdeps/pthread/tst-once3.c
diff --git a/nptl/tst-once4.c b/sysdeps/pthread/tst-once4.c
similarity index 100%
rename from nptl/tst-once4.c
rename to sysdeps/pthread/tst-once4.c
diff --git a/nptl/tst-oncex3.c b/sysdeps/pthread/tst-oncex3.c
similarity index 100%
rename from nptl/tst-oncex3.c
rename to sysdeps/pthread/tst-oncex3.c
diff --git a/nptl/tst-oncex4.c b/sysdeps/pthread/tst-oncex4.c
similarity index 100%
rename from nptl/tst-oncex4.c
rename to sysdeps/pthread/tst-oncex4.c

View File

@ -0,0 +1,200 @@
commit f0419e6a10740a672b28e112c409ae24f5e890ab
Author: Jakub Jelinek <jakub@redhat.com>
Date: Thu Mar 4 15:15:33 2021 +0100
[PATCH] pthread_once hangs when init routine throws an exception [BZ #18435]
This is another attempt at making pthread_once handle throwing exceptions
from the init routine callback. As the new testcases show, just switching
to the cleanup attribute based cleanup does fix the tst-once5 test, but
breaks the new tst-oncey3 test. That is because when throwing exceptions,
only the unwind info registered cleanups (i.e. C++ destructors or cleanup
attribute), when cancelling threads and there has been unwind info from the
cancellation point up to whatever needs cleanup both unwind info registered
cleanups and THREAD_SETMEM (self, cleanup, ...) registered cleanups are
invoked, but once we hit some frame with no unwind info, only the
THREAD_SETMEM (self, cleanup, ...) registered cleanups are invoked.
So, to stay fully backwards compatible (allow init routines without
unwind info which encounter cancellation points) and handle exception throwing
we actually need to register the pthread_once cleanups in both unwind info
and in the THREAD_SETMEM (self, cleanup, ...) way.
If an exception is thrown, only the former will happen and we in that case
need to also unregister the THREAD_SETMEM (self, cleanup, ...) registered
handler, because otherwise after catching the exception the user code could
call deeper into the stack some cancellation point, get cancelled and then
a stale cleanup handler would clobber stack and probably crash.
If a thread calling init routine is cancelled and unwind info ends before
the pthread_once frame, it will be cleaned up through self->cleanup as
before. And if unwind info is present, unwind_stop first calls the
self->cleanup registered handler for the frame, then it will call the
unwind info registered handler but that will already see __do_it == 0
and do nothing.
# Conflicts:
# nptl/Makefile
# (The usual cleanups because they don't match.)
# sysdeps/pthread/Makefile
# (The usual cleanups because all the other tests aren't moved.)
diff --git a/nptl/Makefile b/nptl/Makefile
index dcf3868869767015..70a3be23ecfcd9c9 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -334,10 +334,6 @@ xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \
tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
test-srcs = tst-oddstacklimit
-# Test expected to fail on most targets (except x86_64) due to bug
-# 18435 - pthread_once hangs when init routine throws an exception.
-test-xfail-tst-once5 = yes
-
# Files which must not be linked with libpthread.
tests-nolibpthread = tst-unload
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index a2d48b2015cd385c..7ddc166cf32414c4 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -571,6 +571,67 @@ extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
# undef pthread_cleanup_pop
# define pthread_cleanup_pop(execute) \
__pthread_cleanup_pop (&_buffer, (execute)); }
+
+# if defined __EXCEPTIONS && !defined __cplusplus
+/* Structure to hold the cleanup handler information. */
+struct __pthread_cleanup_combined_frame
+{
+ void (*__cancel_routine) (void *);
+ void *__cancel_arg;
+ int __do_it;
+ struct _pthread_cleanup_buffer __buffer;
+};
+
+/* Special cleanup macros which register cleanup both using
+ __pthread_cleanup_{push,pop} and using cleanup attribute. This is needed
+ for pthread_once, so that it supports both throwing exceptions from the
+ pthread_once callback (only cleanup attribute works there) and cancellation
+ of the thread running the callback if the callback or some routines it
+ calls don't have unwind information. */
+
+static __always_inline void
+__pthread_cleanup_combined_routine (struct __pthread_cleanup_combined_frame
+ *__frame)
+{
+ if (__frame->__do_it)
+ {
+ __frame->__cancel_routine (__frame->__cancel_arg);
+ __frame->__do_it = 0;
+ __pthread_cleanup_pop (&__frame->__buffer, 0);
+ }
+}
+
+static inline void
+__pthread_cleanup_combined_routine_voidptr (void *__arg)
+{
+ struct __pthread_cleanup_combined_frame *__frame
+ = (struct __pthread_cleanup_combined_frame *) __arg;
+ if (__frame->__do_it)
+ {
+ __frame->__cancel_routine (__frame->__cancel_arg);
+ __frame->__do_it = 0;
+ }
+}
+
+# define pthread_cleanup_combined_push(routine, arg) \
+ do { \
+ void (*__cancel_routine) (void *) = (routine); \
+ struct __pthread_cleanup_combined_frame __clframe \
+ __attribute__ ((__cleanup__ (__pthread_cleanup_combined_routine))) \
+ = { .__cancel_routine = __cancel_routine, .__cancel_arg = (arg), \
+ .__do_it = 1 }; \
+ __pthread_cleanup_push (&__clframe.__buffer, \
+ __pthread_cleanup_combined_routine_voidptr, \
+ &__clframe);
+
+# define pthread_cleanup_combined_pop(execute) \
+ __pthread_cleanup_pop (&__clframe.__buffer, 0); \
+ __clframe.__do_it = 0; \
+ if (execute) \
+ __cancel_routine (__clframe.__cancel_arg); \
+ } while (0)
+
+# endif
#endif
extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
diff --git a/nptl/pthread_once.c b/nptl/pthread_once.c
index 1653226286dc3539..45e965e8743d9412 100644
--- a/nptl/pthread_once.c
+++ b/nptl/pthread_once.c
@@ -111,11 +111,11 @@ __pthread_once_slow (pthread_once_t *once_control, void (*init_routine) (void))
/* This thread is the first here. Do the initialization.
Register a cleanup handler so that in case the thread gets
interrupted the initialization can be restarted. */
- pthread_cleanup_push (clear_once_control, once_control);
+ pthread_cleanup_combined_push (clear_once_control, once_control);
init_routine ();
- pthread_cleanup_pop (0);
+ pthread_cleanup_combined_pop (0);
/* Mark *once_control as having finished the initialization. We need
diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc
index d232266c3ace89d9..dda18e610c9114bc 100644
--- a/nptl/tst-once5.cc
+++ b/nptl/tst-once5.cc
@@ -59,7 +59,7 @@ do_test (void)
" throwing an exception", stderr);
}
catch (OnceException) {
- if (1 < niter)
+ if (niter > 1)
fputs ("pthread_once unexpectedly threw", stderr);
result = 0;
}
@@ -75,7 +75,5 @@ do_test (void)
return result;
}
-// The test currently hangs and is XFAILed. Reduce the timeout.
-#define TIMEOUT 1
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 14ef04247cb84ad3..80a71f3f9f0e72ae 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -35,7 +35,7 @@ tst-create1mod.so-no-z-defs = yes
tests += tst-once1 tst-once2 tst-once3 tst-once4
-tests += tst-oncex3 tst-oncex4
+tests += tst-oncex3 tst-oncex4 tst-oncey3 tst-oncey4
ifeq ($(build-shared),yes)
# Build all the modules even when not actually running test programs.
@@ -44,6 +44,8 @@ endif
CFLAGS-tst-oncex3.c += -fexceptions
CFLAGS-tst-oncex4.c += -fexceptions
+CFLAGS-tst-oncey3.c += -fno-exceptions -fno-asynchronous-unwind-tables
+CFLAGS-tst-oncey4.c += -fno-exceptions -fno-asynchronous-unwind-tables
modules-names += tst-create1mod
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
diff --git a/sysdeps/pthread/tst-oncey3.c b/sysdeps/pthread/tst-oncey3.c
new file mode 100644
index 0000000000000000..08225b88dc06b979
--- /dev/null
+++ b/sysdeps/pthread/tst-oncey3.c
@@ -0,0 +1 @@
+#include "tst-once3.c"
diff --git a/sysdeps/pthread/tst-oncey4.c b/sysdeps/pthread/tst-oncey4.c
new file mode 100644
index 0000000000000000..9b4d98f3f13c265a
--- /dev/null
+++ b/sysdeps/pthread/tst-oncey4.c
@@ -0,0 +1 @@
+#include "tst-once4.c"

View File

@ -0,0 +1,40 @@
commit 98966749f2b418825ff2ea496a0ee89fe63d2cc8
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 10 15:21:37 2021 +0100
s390: Use long branches across object boundaries (jgh instead of jh)
Depending on the layout chosen by the linker, the 16-bit displacement
of the jh instruction is insufficient to reach the target label.
Analysis of the linker failure was carried out by Nick Clifton.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Stefan Liebler <stli@linux.ibm.com>
diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S
index b59d60acf0f6aaa0..4faede0cd2f942e3 100644
--- a/sysdeps/s390/memmem-arch13.S
+++ b/sysdeps/s390/memmem-arch13.S
@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13)
# error The arch13 variant of memmem needs the z13 variant of memmem!
# endif
clgfi %r5,9
- jh MEMMEM_Z13
+ jgh MEMMEM_Z13
aghik %r0,%r5,-1 /* vll needs highest index. */
bc 4,0(%r14) /* cc==1: return if needle-len == 0. */
diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S
index faa969849e09c2e1..ffc34c2523ce635a 100644
--- a/sysdeps/s390/strstr-arch13.S
+++ b/sysdeps/s390/strstr-arch13.S
@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13)
# error The arch13 variant of strstr needs the z13 variant of strstr!
# endif
clgfi %r4,9
- jh STRSTR_Z13
+ jgh STRSTR_Z13
/* In case of a partial match, the vstrs instruction returns the index
of the partial match in a vector-register. Then we have to

View File

@ -0,0 +1,304 @@
commit 86f65dffc2396d408beb628f1cad2b8f63e197bd
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Sun Jul 12 06:04:53 2020 -0700
ld.so: Add --list-tunables to print tunable values
Pass --list-tunables to ld.so to print tunables with min and max values.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
elf/Makefile
(different backporting order)
diff --git a/elf/Makefile b/elf/Makefile
index 3e71939d3234c4c3..aa65ec59f143bccf 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -44,6 +44,10 @@ dl-routines += dl-tunables
tunables-type = $(addprefix TUNABLES_FRONTEND_,$(have-tunables))
CPPFLAGS-dl-tunables.c += -DTUNABLES_FRONTEND=$(tunables-type)
+ifeq (yesyes,$(build-shared)$(run-built-tests))
+tests-special += $(objpfx)list-tunables.out
+endif
+
# Make sure that the compiler does not insert any library calls in tunables
# code paths.
ifeq (yes,$(have-loop-to-function))
@@ -1825,6 +1829,13 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \
# tst-glibc-hwcaps-cache.
$(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps
+$(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so
+ $(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \
+ '$(run_program_env)' > $(objpfx)/tst-rtld-list-tunables.out
+ cmp tst-rtld-list-tunables.exp \
+ $(objpfx)/tst-rtld-list-tunables.out > $@; \
+ $(evaluate-test)
+
tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN'
$(objpfx)tst-rtld-help.out: $(objpfx)ld.so
diff --git a/elf/dl-main.h b/elf/dl-main.h
index 566713a0d10cfdb7..9e7b51d8f010e904 100644
--- a/elf/dl-main.h
+++ b/elf/dl-main.h
@@ -63,7 +63,7 @@ struct audit_list
enum rtld_mode
{
rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace,
- rtld_mode_help,
+ rtld_mode_list_tunables, rtld_mode_help,
};
/* Aggregated state information extracted from environment variables
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index bbc3679e3564a766..3c84809d44381241 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -26,6 +26,7 @@
#include <sysdep.h>
#include <fcntl.h>
#include <ldsodefs.h>
+#include <array_length.h>
#define TUNABLES_INTERNAL 1
#include "dl-tunables.h"
@@ -359,6 +360,48 @@ __tunables_init (char **envp)
}
}
+void
+__tunables_print (void)
+{
+ for (int i = 0; i < array_length (tunable_list); i++)
+ {
+ const tunable_t *cur = &tunable_list[i];
+ if (cur->type.type_code == TUNABLE_TYPE_STRING
+ && cur->val.strval == NULL)
+ _dl_printf ("%s:\n", cur->name);
+ else
+ {
+ _dl_printf ("%s: ", cur->name);
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_INT_32:
+ _dl_printf ("%d (min: %d, max: %d)\n",
+ (int) cur->val.numval,
+ (int) cur->type.min,
+ (int) cur->type.max);
+ break;
+ case TUNABLE_TYPE_UINT_64:
+ _dl_printf ("0x%lx (min: 0x%lx, max: 0x%lx)\n",
+ (long int) cur->val.numval,
+ (long int) cur->type.min,
+ (long int) cur->type.max);
+ break;
+ case TUNABLE_TYPE_SIZE_T:
+ _dl_printf ("0x%Zx (min: 0x%Zx, max: 0x%Zx)\n",
+ (size_t) cur->val.numval,
+ (size_t) cur->type.min,
+ (size_t) cur->type.max);
+ break;
+ case TUNABLE_TYPE_STRING:
+ _dl_printf ("%s\n", cur->val.strval);
+ break;
+ default:
+ __builtin_unreachable ();
+ }
+ }
+ }
+}
+
/* Set the tunable value. This is called by the module that the tunable exists
in. */
void
diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h
index 7f181f3316cd9fc1..f4f2cfaeb9828599 100644
--- a/elf/dl-tunables.h
+++ b/elf/dl-tunables.h
@@ -69,9 +69,11 @@ typedef struct _tunable tunable_t;
# include "dl-tunable-list.h"
extern void __tunables_init (char **);
+extern void __tunables_print (void);
extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
extern void __tunable_set_val (tunable_id_t, void *);
rtld_hidden_proto (__tunables_init)
+rtld_hidden_proto (__tunables_print)
rtld_hidden_proto (__tunable_get_val)
/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
diff --git a/elf/dl-usage.c b/elf/dl-usage.c
index e22a9c39427187d1..908b4894b3014b2d 100644
--- a/elf/dl-usage.c
+++ b/elf/dl-usage.c
@@ -255,7 +255,12 @@ setting environment variables (which would be inherited by subprocesses).\n\
in LIST\n\
--audit LIST use objects named in LIST as auditors\n\
--preload LIST preload objects named in LIST\n\
- --argv0 STRING set argv[0] to STRING before running\n\
+ --argv0 STRING set argv[0] to STRING before running\n"
+#if HAVE_TUNABLES
+"\
+ --list-tunables list all tunables with minimum and maximum values\n"
+#endif
+"\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
diff --git a/elf/rtld.c b/elf/rtld.c
index 9e09896da078274d..54b621ec5ca014fa 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -47,6 +47,7 @@
#include <libc-early-init.h>
#include <dl-main.h>
#include <gnu/lib-names.h>
+#include <dl-tunables.h>
#include <assert.h>
@@ -1262,6 +1263,16 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_argc -= 2;
_dl_argv += 2;
}
+#if HAVE_TUNABLES
+ else if (! strcmp (_dl_argv[1], "--list-tunables"))
+ {
+ state.mode = rtld_mode_list_tunables;
+
+ ++_dl_skip_args;
+ --_dl_argc;
+ ++_dl_argv;
+ }
+#endif
else if (strcmp (_dl_argv[1], "--help") == 0)
{
state.mode = rtld_mode_help;
@@ -1282,6 +1293,14 @@ dl_main (const ElfW(Phdr) *phdr,
else
break;
+#if HAVE_TUNABLES
+ if (__glibc_unlikely (state.mode == rtld_mode_list_tunables))
+ {
+ __tunables_print ();
+ _exit (0);
+ }
+#endif
+
/* If we have no further argument the program was called incorrectly.
Grant the user some education. */
if (_dl_argc < 2)
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
new file mode 100644
index 0000000000000000..4f3f7ee4e30a2b42
--- /dev/null
+++ b/elf/tst-rtld-list-tunables.exp
@@ -0,0 +1,14 @@
+glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0x[f]+)
+glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0x[f]+)
+glibc.malloc.check: 0 (min: 0, max: 3)
+glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647)
+glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.malloc.perturb: 0 (min: 0, max: 255)
+glibc.malloc.tcache_count: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
+glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
diff --git a/elf/tst-rtld-list-tunables.sh b/elf/tst-rtld-list-tunables.sh
new file mode 100755
index 0000000000000000..e7bbdde94952b872
--- /dev/null
+++ b/elf/tst-rtld-list-tunables.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Test for --list-tunables option ld.so.
+# Copyright (C) 2021 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+set -e
+
+rtld=$1
+test_wrapper_env=$2
+run_program_env=$3
+
+LC_ALL=C
+export LC_ALL
+
+${test_wrapper_env} \
+${run_program_env} \
+$rtld --list-tunables \
+| sort -u \
+| egrep "(rtld|malloc)" \
+| sed -e "s/0xf\+/0x[f]+/"
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 07887981748bc44b..43272cf885d1e3e6 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -28,6 +28,44 @@ Finally, the set of tunables available may vary between distributions as
the tunables feature allows distributions to add their own tunables under
their own namespace.
+Passing @option{--list-tunables} to the dynamic loader to print all
+tunables with minimum and maximum values:
+
+@example
+$ /lib64/ld-linux-x86-64.so.2 --list-tunables
+glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
+glibc.elision.skip_lock_after_retries: 3 (min: -2147483648, max: 2147483647)
+glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.malloc.perturb: 0 (min: 0, max: 255)
+glibc.cpu.x86_shared_cache_size: 0x100000 (min: 0x0, max: 0xffffffffffffffff)
+glibc.mem.tagging: 0 (min: 0, max: 255)
+glibc.elision.tries: 3 (min: -2147483648, max: 2147483647)
+glibc.elision.enable: 0 (min: 0, max: 1)
+glibc.cpu.x86_rep_movsb_threshold: 0x1000 (min: 0x100, max: 0xffffffffffffffff)
+glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.elision.skip_lock_busy: 3 (min: -2147483648, max: 2147483647)
+glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.cpu.x86_rep_stosb_threshold: 0x800 (min: 0x1, max: 0xffffffffffffffff)
+glibc.cpu.x86_non_temporal_threshold: 0xc0000 (min: 0x0, max: 0xffffffffffffffff)
+glibc.cpu.x86_shstk:
+glibc.cpu.hwcap_mask: 0x6 (min: 0x0, max: 0xffffffffffffffff)
+glibc.malloc.mmap_max: 0 (min: -2147483648, max: 2147483647)
+glibc.elision.skip_trylock_internal_abort: 3 (min: -2147483648, max: 2147483647)
+glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.cpu.x86_ibt:
+glibc.cpu.hwcaps:
+glibc.elision.skip_lock_internal_abort: 3 (min: -2147483648, max: 2147483647)
+glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0xffffffffffffffff)
+glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.cpu.x86_data_cache_size: 0x8000 (min: 0x0, max: 0xffffffffffffffff)
+glibc.malloc.tcache_count: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0xffffffffffffffff)
+glibc.pthread.mutex_spin_count: 100 (min: 0, max: 32767)
+glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0xffffffffffffffff)
+glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0xffffffffffffffff)
+glibc.malloc.check: 0 (min: 0, max: 3)
+@end example
+
@menu
* Tunable names:: The structure of a tunable name
* Memory Allocation Tunables:: Tunables in the memory allocation subsystem

View File

@ -0,0 +1,30 @@
commit d2d12c7a988a9a04aec23b5e4af549db61b0a005
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Tue Feb 2 09:31:56 2021 -0800
tst-rtld-list-tunables.sh: Unset glibc tunables
Unset glibc tunables and their aliases for --list-tunables test.
diff --git a/elf/tst-rtld-list-tunables.sh b/elf/tst-rtld-list-tunables.sh
index e7bbdde94952b872..78f4ed2ebbd3db2c 100755
--- a/elf/tst-rtld-list-tunables.sh
+++ b/elf/tst-rtld-list-tunables.sh
@@ -26,6 +26,17 @@ run_program_env=$3
LC_ALL=C
export LC_ALL
+# Unset tunables and their aliases.
+GLIBC_TUNABLES=
+MALLOC_ARENA_MAX=
+MALLOC_ARENA_TEST=
+MALLOC_CHECK_=
+MALLOC_MMAP_MAX_=
+MALLOC_MMAP_THRESHOLD_=
+MALLOC_PERTURB_=
+MALLOC_TOP_PAD_=
+MALLOC_TRIM_THRESHOLD_=
+
${test_wrapper_env} \
${run_program_env} \
$rtld --list-tunables \

View File

@ -0,0 +1,578 @@
commit 851f32cf7bf7067f73b991610778915edd57d7b4
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Mar 2 14:38:42 2021 +0100
ld.so: Implement the --list-diagnostics option
diff --git a/elf/Makefile b/elf/Makefile
index aa65ec59f143bccf..d246f1c0d9e019fd 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -64,7 +64,7 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
# interpreter and operating independent of libc.
rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \
- dl-usage
+ dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu
all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables
@@ -672,6 +672,9 @@ CFLAGS-cache.c += $(SYSCONF-FLAGS)
CFLAGS-rtld.c += $(SYSCONF-FLAGS)
CFLAGS-dl-usage.c += $(SYSCONF-FLAGS) \
-D'RTLD="$(rtlddir)/$(rtld-installed-name)"'
+CFLAGS-dl-diagnostics.c += $(SYSCONF-FLAGS) \
+ -D'PREFIX="$(prefix)"' \
+ -D'RTLD="$(rtlddir)/$(rtld-installed-name)"'
cpp-srcs-left := $(all-rtld-routines:=.os)
lib := rtld
diff --git a/elf/dl-diagnostics-cpu.c b/elf/dl-diagnostics-cpu.c
new file mode 100644
index 0000000000000000..f7d149764bcb35a1
--- /dev/null
+++ b/elf/dl-diagnostics-cpu.c
@@ -0,0 +1,24 @@
+/* Print CPU diagnostics data in ld.so. Stub version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dl-diagnostics.h>
+
+void
+_dl_diagnostics_cpu (void)
+{
+}
diff --git a/elf/dl-diagnostics-kernel.c b/elf/dl-diagnostics-kernel.c
new file mode 100644
index 0000000000000000..831c358f1463cbf4
--- /dev/null
+++ b/elf/dl-diagnostics-kernel.c
@@ -0,0 +1,24 @@
+/* Print kernel diagnostics data in ld.so. Stub version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dl-diagnostics.h>
+
+void
+_dl_diagnostics_kernel (void)
+{
+}
diff --git a/elf/dl-diagnostics.c b/elf/dl-diagnostics.c
new file mode 100644
index 0000000000000000..bef224b36cbf5fc3
--- /dev/null
+++ b/elf/dl-diagnostics.c
@@ -0,0 +1,265 @@
+/* Print diagnostics data in ld.so.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <gnu/lib-names.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <dl-diagnostics.h>
+#include <dl-hwcaps.h>
+#include <dl-main.h>
+#include <dl-procinfo.h>
+#include <dl-sysdep.h>
+#include <ldsodefs.h>
+#include "trusted-dirs.h"
+#include "version.h"
+
+/* Write CH to standard output. */
+static void
+_dl_putc (char ch)
+{
+ _dl_write (STDOUT_FILENO, &ch, 1);
+}
+
+/* Print CH to standard output, quoting it if necessary. */
+static void
+print_quoted_char (char ch)
+{
+ if (ch < ' ' || ch > '~')
+ {
+ char buf[4];
+ buf[0] = '\\';
+ buf[1] = '0' + ((ch >> 6) & 7);
+ buf[2] = '0' + ((ch >> 6) & 7);
+ buf[3] = '0' + (ch & 7);
+ _dl_write (STDOUT_FILENO, buf, 4);
+ }
+ else
+ {
+ if (ch == '\\' || ch == '"')
+ _dl_putc ('\\');
+ _dl_putc (ch);
+ }
+}
+
+/* Print S of LEN bytes to standard output, quoting characters as
+ needed. */
+static void
+print_string_length (const char *s, size_t len)
+{
+ _dl_putc ('"');
+ for (size_t i = 0; i < len; ++i)
+ print_quoted_char (s[i]);
+ _dl_putc ('"');
+}
+
+void
+_dl_diagnostics_print_string (const char *s)
+{
+ if (s == NULL)
+ {
+ _dl_printf ("0x0");
+ return;
+ }
+
+ _dl_putc ('"');
+ while (*s != '\0')
+ {
+ print_quoted_char (*s);
+ ++s;
+ }
+ _dl_putc ('"');
+}
+
+void
+_dl_diagnostics_print_labeled_string (const char *label, const char *s)
+{
+ _dl_printf ("%s=", label);
+ _dl_diagnostics_print_string (s);
+ _dl_putc ('\n');
+}
+
+void
+_dl_diagnostics_print_labeled_value (const char *label, uint64_t value)
+{
+ if (sizeof (value) == sizeof (unsigned long int))
+ /* _dl_printf can print 64-bit values directly. */
+ _dl_printf ("%s=0x%lx\n", label, (unsigned long int) value);
+ else
+ {
+ uint32_t high = value >> 32;
+ uint32_t low = value;
+ if (high == 0)
+ _dl_printf ("%s=0x%x\n", label, low);
+ else
+ _dl_printf ("%s=0x%x%08x\n", label, high, low);
+ }
+}
+
+/* Return true if ENV is an unfiltered environment variable. */
+static bool
+unfiltered_envvar (const char *env, size_t *name_length)
+{
+ char *env_equal = strchr (env, '=');
+ if (env_equal == NULL)
+ {
+ /* Always dump malformed entries. */
+ *name_length = strlen (env);
+ return true;
+ }
+ size_t envname_length = env_equal - env;
+ *name_length = envname_length;
+
+ /* LC_ and LD_ variables. */
+ if (env[0] == 'L' && (env[1] == 'C' || env[1] == 'D')
+ && env[2] == '_')
+ return true;
+
+ /* MALLOC_ variables. */
+ if (strncmp (env, "MALLOC_", strlen ("MALLOC_")) == 0)
+ return true;
+
+ static const char unfiltered[] =
+ "DATEMSK\0"
+ "GCONV_PATH\0"
+ "GETCONF_DIR\0"
+ "GETCONF_DIR\0"
+ "GLIBC_TUNABLES\0"
+ "GMON_OUTPUT_PREFIX\0"
+ "HESIOD_CONFIG\0"
+ "HES_DOMAIN\0"
+ "HOSTALIASES\0"
+ "I18NPATH\0"
+ "IFS\0"
+ "LANG\0"
+ "LOCALDOMAIN\0"
+ "LOCPATH\0"
+ "MSGVERB\0"
+ "NIS_DEFAULTS\0"
+ "NIS_GROUP\0"
+ "NIS_PATH\0"
+ "NLSPATH\0"
+ "PATH\0"
+ "POSIXLY_CORRECT\0"
+ "RESOLV_HOST_CONF\0"
+ "RES_OPTIONS\0"
+ "SEV_LEVEL\0"
+ "TMPDIR\0"
+ "TZ\0"
+ "TZDIR\0"
+ /* Two null bytes at the end to mark the end of the list via an
+ empty substring. */
+ ;
+ for (const char *candidate = unfiltered; *candidate != '\0'; )
+ {
+ size_t candidate_length = strlen (candidate);
+ if (candidate_length == envname_length
+ && memcmp (candidate, env, candidate_length) == 0)
+ return true;
+ candidate += candidate_length + 1;
+ }
+
+ return false;
+}
+
+/* Dump the process environment. */
+static void
+print_environ (char **environ)
+{
+ unsigned int index = 0;
+ for (char **envp = environ; *envp != NULL; ++envp)
+ {
+ char *env = *envp;
+ size_t name_length;
+ bool unfiltered = unfiltered_envvar (env, &name_length);
+ _dl_printf ("env%s[0x%x]=",
+ unfiltered ? "" : "_filtered", index);
+ if (unfiltered)
+ _dl_diagnostics_print_string (env);
+ else
+ print_string_length (env, name_length);
+ _dl_putc ('\n');
+ ++index;
+ }
+}
+
+/* Print configured paths and the built-in search path. */
+static void
+print_paths (void)
+{
+ _dl_diagnostics_print_labeled_string ("path.prefix", PREFIX);
+ _dl_diagnostics_print_labeled_string ("path.rtld", RTLD);
+ _dl_diagnostics_print_labeled_string ("path.sysconfdir", SYSCONFDIR);
+
+ unsigned int index = 0;
+ static const char *system_dirs = SYSTEM_DIRS "\0";
+ for (const char *e = system_dirs; *e != '\0'; )
+ {
+ size_t len = strlen (e);
+ _dl_printf ("path.system_dirs[0x%x]=", index);
+ print_string_length (e, len);
+ _dl_putc ('\n');
+ ++index;
+ e += len + 1;
+ }
+}
+
+/* Print information about the glibc version. */
+static void
+print_version (void)
+{
+ _dl_diagnostics_print_labeled_string ("version.release", RELEASE);
+ _dl_diagnostics_print_labeled_string ("version.version", VERSION);
+}
+
+void
+_dl_print_diagnostics (char **environ)
+{
+#ifdef HAVE_DL_DISCOVER_OSVERSION
+ _dl_diagnostics_print_labeled_value
+ ("dl_discover_osversion", _dl_discover_osversion ());
+#endif
+ _dl_diagnostics_print_labeled_string ("dl_dst_lib", DL_DST_LIB);
+ _dl_diagnostics_print_labeled_value ("dl_hwcap", GLRO (dl_hwcap));
+ _dl_diagnostics_print_labeled_value ("dl_hwcap_important", HWCAP_IMPORTANT);
+ _dl_diagnostics_print_labeled_value ("dl_hwcap2", GLRO (dl_hwcap2));
+ _dl_diagnostics_print_labeled_string
+ ("dl_hwcaps_subdirs", _dl_hwcaps_subdirs);
+ _dl_diagnostics_print_labeled_value
+ ("dl_hwcaps_subdirs_active", _dl_hwcaps_subdirs_active ());
+ _dl_diagnostics_print_labeled_value ("dl_osversion", GLRO (dl_osversion));
+ _dl_diagnostics_print_labeled_value ("dl_pagesize", GLRO (dl_pagesize));
+ _dl_diagnostics_print_labeled_string ("dl_platform", GLRO (dl_platform));
+ _dl_diagnostics_print_labeled_string
+ ("dl_profile_output", GLRO (dl_profile_output));
+ _dl_diagnostics_print_labeled_value
+ ("dl_string_platform", _dl_string_platform ( GLRO (dl_platform)));
+
+ _dl_diagnostics_print_labeled_string ("dso.ld", LD_SO);
+ _dl_diagnostics_print_labeled_string ("dso.libc", LIBC_SO);
+
+ print_environ (environ);
+ print_paths ();
+ print_version ();
+
+ _dl_diagnostics_kernel ();
+ _dl_diagnostics_cpu ();
+
+ _exit (EXIT_SUCCESS);
+}
diff --git a/elf/dl-diagnostics.h b/elf/dl-diagnostics.h
new file mode 100644
index 0000000000000000..27dcb12bca12e5b6
--- /dev/null
+++ b/elf/dl-diagnostics.h
@@ -0,0 +1,46 @@
+/* Interfaces for printing diagnostics in ld.so.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_DIAGNOSTICS_H
+#define _DL_DIAGNOSTICS_H
+
+#include <stdint.h>
+
+/* Write the null-terminated string to standard output, surrounded in
+ quotation marks. */
+void _dl_diagnostics_print_string (const char *s) attribute_hidden;
+
+/* Like _dl_diagnostics_print_string, but add a LABEL= prefix, and a
+ newline character as a suffix. */
+void _dl_diagnostics_print_labeled_string (const char *label, const char *s)
+ attribute_hidden;
+
+/* Print LABEL=VALUE to standard output, followed by a newline
+ character. */
+void _dl_diagnostics_print_labeled_value (const char *label, uint64_t value)
+ attribute_hidden;
+
+/* Print diagnostics data for the kernel. Called from
+ _dl_print_diagnostics. */
+void _dl_diagnostics_kernel (void) attribute_hidden;
+
+/* Print diagnostics data for the CPU(s). Called from
+ _dl_print_diagnostics. */
+void _dl_diagnostics_cpu (void) attribute_hidden;
+
+#endif /* _DL_DIAGNOSTICS_H */
diff --git a/elf/dl-main.h b/elf/dl-main.h
index 9e7b51d8f010e904..9fbbdb0fac09adf3 100644
--- a/elf/dl-main.h
+++ b/elf/dl-main.h
@@ -63,7 +63,7 @@ struct audit_list
enum rtld_mode
{
rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace,
- rtld_mode_list_tunables, rtld_mode_help,
+ rtld_mode_list_tunables, rtld_mode_list_diagnostics, rtld_mode_help,
};
/* Aggregated state information extracted from environment variables
@@ -121,4 +121,7 @@ _Noreturn void _dl_version (void) attribute_hidden;
_Noreturn void _dl_help (const char *argv0, struct dl_main_state *state)
attribute_hidden;
+/* Print a diagnostics dump. */
+_Noreturn void _dl_print_diagnostics (char **environ) attribute_hidden;
+
#endif /* _DL_MAIN */
diff --git a/elf/dl-usage.c b/elf/dl-usage.c
index 908b4894b3014b2d..e19e1791d9169da2 100644
--- a/elf/dl-usage.c
+++ b/elf/dl-usage.c
@@ -261,6 +261,7 @@ setting environment variables (which would be inherited by subprocesses).\n\
--list-tunables list all tunables with minimum and maximum values\n"
#endif
"\
+ --list-diagnostics list diagnostics information\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
diff --git a/elf/rtld.c b/elf/rtld.c
index 54b621ec5ca014fa..d14c388f548d6d51 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -138,6 +138,7 @@ static void dl_main_state_init (struct dl_main_state *state);
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
+extern char **_environ attribute_hidden;
static void process_envvars (struct dl_main_state *state);
#ifdef DL_ARGV_NOT_RELRO
@@ -1273,6 +1274,14 @@ dl_main (const ElfW(Phdr) *phdr,
++_dl_argv;
}
#endif
+ else if (! strcmp (_dl_argv[1], "--list-diagnostics"))
+ {
+ state.mode = rtld_mode_list_diagnostics;
+
+ ++_dl_skip_args;
+ --_dl_argc;
+ ++_dl_argv;
+ }
else if (strcmp (_dl_argv[1], "--help") == 0)
{
state.mode = rtld_mode_help;
@@ -1301,6 +1310,9 @@ dl_main (const ElfW(Phdr) *phdr,
}
#endif
+ if (state.mode == rtld_mode_list_diagnostics)
+ _dl_print_diagnostics (_environ);
+
/* If we have no further argument the program was called incorrectly.
Grant the user some education. */
if (_dl_argc < 2)
@@ -2623,12 +2635,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
}
}
-/* Process all environments variables the dynamic linker must recognize.
- Since all of them start with `LD_' we are a bit smarter while finding
- all the entries. */
-extern char **_environ attribute_hidden;
-
-
static void
process_envvars (struct dl_main_state *state)
{
diff --git a/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c b/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c
new file mode 100644
index 0000000000000000..59f6402c547ba590
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-diagnostics-kernel.c
@@ -0,0 +1,77 @@
+/* Print kernel diagnostics data in ld.so. Linux version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dl-diagnostics.h>
+#include <ldsodefs.h>
+#include <sys/utsname.h>
+
+/* Dump the auxiliary vector to standard output. */
+static void
+print_auxv (void)
+{
+ /* See _dl_show_auxv. The code below follows the general output
+ format for diagnostic dumps. */
+ unsigned int index = 0;
+ for (ElfW(auxv_t) *av = GLRO(dl_auxv); av->a_type != AT_NULL; ++av)
+ {
+ _dl_printf ("auxv[0x%x].a_type=0x%lx\n"
+ "auxv[0x%x].a_val=",
+ index, (unsigned long int) av->a_type, index);
+ if (av->a_type == AT_EXECFN
+ || av->a_type == AT_PLATFORM
+ || av->a_type == AT_BASE_PLATFORM)
+ /* The address of the strings is not useful at all, so print
+ the strings themselvs. */
+ _dl_diagnostics_print_string ((const char *) av->a_un.a_val);
+ else
+ _dl_printf ("0x%lx", (unsigned long int) av->a_un.a_val);
+ _dl_printf ("\n");
+ ++index;
+ }
+}
+
+/* Print one uname entry. */
+static void
+print_utsname_entry (const char *field, const char *value)
+{
+ _dl_printf ("uname.");
+ _dl_diagnostics_print_labeled_string (field, value);
+}
+
+/* Print information from uname, including the kernel version. */
+static void
+print_uname (void)
+{
+ struct utsname uts;
+ if (__uname (&uts) == 0)
+ {
+ print_utsname_entry ("sysname", uts.sysname);
+ print_utsname_entry ("nodename", uts.nodename);
+ print_utsname_entry ("release", uts.release);
+ print_utsname_entry ("version", uts.version);
+ print_utsname_entry ("machine", uts.machine);
+ print_utsname_entry ("domainname", uts.domainname);
+ }
+}
+
+void
+_dl_diagnostics_kernel (void)
+{
+ print_auxv ();
+ print_uname ();
+}

View File

@ -0,0 +1,117 @@
commit e4933c8a92ea08eecdf3ab45e7f76c95dc3d20ac
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Mar 2 14:58:05 2021 +0100
x86: Automate generation of PREFERRED_FEATURE_INDEX_1 bitfield
Use a .def file to define the bitfield layout, so that it is possible
to iterate over field members using the preprocessor.
Conflicts:
sysdeps/x86/include/cpu-features.h
(re-did the change from scratch)
sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
(adjusted to the downstream bits)
diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
new file mode 100644
index 0000000000000000..17a5cc428c1dabea
--- /dev/null
+++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
@@ -0,0 +1,34 @@
+/* Bits in the PREFERRED_FEATURE_INDEX_1 bitfield of <cpu-features.h>.
+ Copyright (C) 2020-2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+BIT (I586)
+BIT (I686)
+BIT (Fast_Rep_String)
+BIT (Fast_Copy_Backward)
+BIT (Fast_Unaligned_Load)
+BIT (Fast_Unaligned_Copy)
+BIT (Slow_BSF)
+BIT (Slow_SSE4_2)
+BIT (AVX_Fast_Unaligned_Load)
+BIT (Prefer_MAP_32BIT_EXEC)
+BIT (Prefer_PMINUB_for_stringop)
+BIT (Prefer_No_VZEROUPPER)
+BIT (Prefer_ERMS)
+BIT (Prefer_FSRM)
+BIT (Prefer_No_AVX512)
+BIT (MathVec_Prefer_No_AVX512)
diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h
index f62be0b9b3746675..f43e22f677b249a9 100644
--- a/sysdeps/x86/include/cpu-features.h
+++ b/sysdeps/x86/include/cpu-features.h
@@ -80,40 +80,23 @@ enum
# define HAS_ARCH_FEATURE(name) \
CPU_FEATURE_PREFERRED (name)
-/* PREFERRED_FEATURE_INDEX_1. */
-# define bit_arch_I586 (1u << 0)
-# define bit_arch_I686 (1u << 1)
-# define bit_arch_Fast_Rep_String (1u << 2)
-# define bit_arch_Fast_Copy_Backward (1u << 3)
-# define bit_arch_Fast_Unaligned_Load (1u << 4)
-# define bit_arch_Fast_Unaligned_Copy (1u << 5)
-# define bit_arch_Slow_BSF (1u << 6)
-# define bit_arch_Slow_SSE4_2 (1u << 7)
-# define bit_arch_AVX_Fast_Unaligned_Load (1u << 8)
-# define bit_arch_Prefer_MAP_32BIT_EXEC (1u << 9)
-# define bit_arch_Prefer_PMINUB_for_stringop (1u << 10)
-# define bit_arch_Prefer_No_VZEROUPPER (1u << 11)
-# define bit_arch_Prefer_ERMS (1u << 12)
-# define bit_arch_Prefer_FSRM (1u << 13)
-# define bit_arch_Prefer_No_AVX512 (1u << 14)
-# define bit_arch_MathVec_Prefer_No_AVX512 (1u << 15)
-
-# define index_arch_Fast_Rep_String PREFERRED_FEATURE_INDEX_1
-# define index_arch_Fast_Copy_Backward PREFERRED_FEATURE_INDEX_1
-# define index_arch_Slow_BSF PREFERRED_FEATURE_INDEX_1
-# define index_arch_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1
-# define index_arch_Prefer_PMINUB_for_stringop PREFERRED_FEATURE_INDEX_1
-# define index_arch_Fast_Unaligned_Copy PREFERRED_FEATURE_INDEX_1
-# define index_arch_I586 PREFERRED_FEATURE_INDEX_1
-# define index_arch_I686 PREFERRED_FEATURE_INDEX_1
-# define index_arch_Slow_SSE4_2 PREFERRED_FEATURE_INDEX_1
-# define index_arch_AVX_Fast_Unaligned_Load PREFERRED_FEATURE_INDEX_1
-# define index_arch_Prefer_MAP_32BIT_EXEC PREFERRED_FEATURE_INDEX_1
-# define index_arch_Prefer_No_VZEROUPPER PREFERRED_FEATURE_INDEX_1
-# define index_arch_Prefer_ERMS PREFERRED_FEATURE_INDEX_1
-# define index_arch_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1
-# define index_arch_MathVec_Prefer_No_AVX512 PREFERRED_FEATURE_INDEX_1
-# define index_arch_Prefer_FSRM PREFERRED_FEATURE_INDEX_1
+/* PREFERRED_FEATURE_INDEX_1. First define the bitindex values
+ sequentially, then define the bit_arch* and index_arch_* lookup
+ constants. */
+enum
+ {
+#define BIT(x) _bitindex_arch_##x ,
+#include "cpu-features-preferred_feature_index_1.def"
+#undef BIT
+ };
+enum
+ {
+#define BIT(x) \
+ bit_arch_##x = 1u << _bitindex_arch_##x , \
+ index_arch_##x = PREFERRED_FEATURE_INDEX_1,
+#include "cpu-features-preferred_feature_index_1.def"
+#undef BIT
+ };
/* XCR0 Feature flags. */
# define bit_XMM_state (1u << 1)

View File

@ -0,0 +1,131 @@
commit 01a5746b6c8a44dc29d33e056b63485075a6a3cc
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Feb 24 13:12:04 2021 +0100
x86: Add CPU-specific diagnostics to ld.so --list-diagnostics
Conflicts:
sysdeps/x86/dl-diagnostics-cpu.c
(reworked due to struct differences, different knobs
downstream)
diff --git a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c
new file mode 100644
index 0000000000000000..0ba286a828b69937
--- /dev/null
+++ b/sysdeps/x86/dl-diagnostics-cpu.c
@@ -0,0 +1,101 @@
+/* Print CPU diagnostics data in ld.so. x86 version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dl-diagnostics.h>
+#include <ldsodefs.h>
+
+static void
+print_cpu_features_value (const char *label, uint64_t value)
+{
+ _dl_printf ("x86.cpu_features.");
+ _dl_diagnostics_print_labeled_value (label, value);
+}
+
+static void
+print_cpu_feature_internal (unsigned int index, const char *kind,
+ unsigned int reg, uint32_t value)
+{
+ _dl_printf ("x86.cpu_features.features[0x%x].%s[0x%x]=0x%x\n",
+ index, kind, reg, value);
+}
+
+static void
+print_cpu_feature_preferred (const char *label, unsigned int flag)
+{
+ _dl_printf("x86.cpu_features.preferred.%s=0x%x\n", label, flag);
+}
+
+void
+_dl_diagnostics_cpu (void)
+{
+ const struct cpu_features *cpu_features = __get_cpu_features ();
+
+ print_cpu_features_value ("basic.kind", cpu_features->basic.kind);
+ print_cpu_features_value ("basic.max_cpuid", cpu_features->basic.max_cpuid);
+ print_cpu_features_value ("basic.family", cpu_features->basic.family);
+ print_cpu_features_value ("basic.model", cpu_features->basic.model);
+ print_cpu_features_value ("basic.stepping", cpu_features->basic.stepping);
+
+ for (unsigned int index = 0; index < COMMON_CPUID_INDEX_MAX; ++index)
+ {
+ /* Downstream, these constants are not part of the ABI yet, so
+ analysis needs to take the precise glibc version into
+ account. */
+ print_cpu_feature_internal
+ (index, "cpuid", 0, cpu_features->features[index].cpuid.eax);
+ print_cpu_feature_internal
+ (index, "cpuid", 1, cpu_features->features[index].cpuid.ebx);
+ print_cpu_feature_internal
+ (index, "cpuid", 2, cpu_features->features[index].cpuid.ecx);
+ print_cpu_feature_internal
+ (index, "cpuid", 3, cpu_features->features[index].cpuid.edx);
+ print_cpu_feature_internal
+ (index, "usable", 0, cpu_features->features[index].usable.eax);
+ print_cpu_feature_internal
+ (index, "usable", 1, cpu_features->features[index].usable.ebx);
+ print_cpu_feature_internal
+ (index, "usable", 2, cpu_features->features[index].usable.ecx);
+ print_cpu_feature_internal
+ (index, "usable", 3, cpu_features->features[index].usable.edx);
+ }
+
+ /* The preferred indicators are not part of the ABI and need to be
+ translated. */
+#define BIT(x) \
+ print_cpu_feature_preferred (#x, CPU_FEATURE_PREFERRED_P (cpu_features, x));
+#include "cpu-features-preferred_feature_index_1.def"
+#undef BIT
+
+ print_cpu_features_value ("xsave_state_size",
+ cpu_features->xsave_state_size);
+ print_cpu_features_value ("xsave_state_full_size",
+ cpu_features->xsave_state_full_size);
+ print_cpu_features_value ("data_cache_size", cpu_features->data_cache_size);
+ print_cpu_features_value ("shared_cache_size",
+ cpu_features->shared_cache_size);
+ print_cpu_features_value ("non_temporal_threshold",
+ cpu_features->non_temporal_threshold);
+ print_cpu_features_value ("rep_movsb_threshold",
+ cpu_features->rep_movsb_threshold);
+ print_cpu_features_value ("rep_stosb_threshold",
+ cpu_features->rep_stosb_threshold);
+ _Static_assert (offsetof (struct cpu_features, rep_stosb_threshold)
+ + sizeof (cpu_features->rep_stosb_threshold)
+ == sizeof (*cpu_features),
+ "last cpu_features field has been printed");
+}
diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h
index f43e22f677b249a9..536643b209425198 100644
--- a/sysdeps/x86/include/cpu-features.h
+++ b/sysdeps/x86/include/cpu-features.h
@@ -107,6 +107,8 @@ enum
# define bit_XTILECFG_state (1u << 17)
# define bit_XTILEDATA_state (1u << 18)
+/* NB: When adding new fields, update sysdeps/x86/dl-diagnostics-cpu.c
+ to print them. */
struct cpu_features
{
struct cpu_features_basic basic;

View File

@ -0,0 +1,255 @@
commit c1cb2deeca1a85c6fc5bd41b90816d48a95bc434
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Dec 5 11:28:34 2021 +0100
elf: execve statically linked programs instead of crashing [BZ #28648]
Programs without dynamic dependencies and without a program
interpreter are now run via execve.
Previously, the dynamic linker either crashed while attempting to
read a non-existing dynamic segment (looking for DT_AUDIT/DT_DEPAUDIT
data), or the self-relocated in the static PIE executable crashed
because the outer dynamic linker had already applied RELRO protection.
<dl-execve.h> is needed because execve is not available in the
dynamic loader on Hurd.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
Conflicts:
elf/Makefile
(some missing backports)
elf/rtld.c
(missing rework of ld.so self-relocation downstream,
always print error as a number due to missing
sterrorname_np, also fix errcode/errno glitch)
sysdeps/unix/sysv/linux/dl-execve.h
(missing INTERNAL_SYSCALL_CALL refactoring to Linux-like
calling convention)
diff --git a/elf/Makefile b/elf/Makefile
index d246f1c0d9e019fd..b3e8ab2792608de7 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -214,7 +214,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls-ie tst-tls-ie-dlmopen \
argv0test \
tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
- tst-tls20 tst-tls21
+ tst-tls20 tst-tls21 \
+ tst-rtld-run-static \
# reldep9
tests-internal += loadtest unload unload2 circleload1 \
neededtest neededtest2 neededtest3 neededtest4 \
@@ -1917,3 +1918,5 @@ $(objpfx)tst-tls20.out: $(objpfx)tst-tls20mod-bad.so \
$(objpfx)tst-tls21: $(libdl) $(shared-thread-library)
$(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so
$(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
+
+$(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig
diff --git a/elf/rtld.c b/elf/rtld.c
index d14c388f548d6d51..461d8c114a875a9b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -48,6 +48,7 @@
#include <dl-main.h>
#include <gnu/lib-names.h>
#include <dl-tunables.h>
+#include <dl-execve.h>
#include <assert.h>
@@ -1114,6 +1115,40 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
}
}
+/* Check if the executable is not actualy dynamically linked, and
+ invoke it directly in that case. */
+static void
+rtld_chain_load (struct link_map *main_map, char *argv0)
+{
+ /* The dynamic loader run against itself. */
+ const char *rtld_soname
+ = ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+ + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val);
+ if (main_map->l_info[DT_SONAME] != NULL
+ && strcmp (rtld_soname,
+ ((const char *) D_PTR (main_map, l_info[DT_STRTAB])
+ + main_map->l_info[DT_SONAME]->d_un.d_val)) == 0)
+ _dl_fatal_printf ("%s: loader cannot load itself\n", rtld_soname);
+
+ /* With DT_NEEDED dependencies, the executable is dynamically
+ linked. */
+ if (__glibc_unlikely (main_map->l_info[DT_NEEDED] != NULL))
+ return;
+
+ /* If the executable has program interpreter, it is dynamically
+ linked. */
+ for (size_t i = 0; i < main_map->l_phnum; ++i)
+ if (main_map->l_phdr[i].p_type == PT_INTERP)
+ return;
+
+ const char *pathname = _dl_argv[0];
+ if (argv0 != NULL)
+ _dl_argv[0] = argv0;
+ int errcode = __rtld_execve (pathname, _dl_argv, _environ);
+ _dl_fatal_printf("%s: cannot execute %s: %d\n",
+ rtld_soname, pathname, errcode);
+}
+
static void
dl_main (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
@@ -1384,14 +1419,8 @@ dl_main (const ElfW(Phdr) *phdr,
/* Now the map for the main executable is available. */
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
- if (__glibc_likely (state.mode == rtld_mode_normal)
- && GL(dl_rtld_map).l_info[DT_SONAME] != NULL
- && main_map->l_info[DT_SONAME] != NULL
- && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
- + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val,
- (const char *) D_PTR (main_map, l_info[DT_STRTAB])
- + main_map->l_info[DT_SONAME]->d_un.d_val) == 0)
- _dl_fatal_printf ("loader cannot load itself\n");
+ if (__glibc_likely (state.mode == rtld_mode_normal))
+ rtld_chain_load (main_map, argv0);
phdr = main_map->l_phdr;
phnum = main_map->l_phnum;
diff --git a/elf/tst-rtld-run-static.c b/elf/tst-rtld-run-static.c
new file mode 100644
index 0000000000000000..7281093504b675c4
--- /dev/null
+++ b/elf/tst-rtld-run-static.c
@@ -0,0 +1,62 @@
+/* Test running statically linked programs using ld.so.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/capture_subprocess.h>
+#include <string.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+ char *ldconfig_path = xasprintf ("%s/elf/ldconfig", support_objdir_root);
+
+ {
+ char *argv[] = { (char *) "ld.so", ldconfig_path, (char *) "--help", NULL };
+ struct support_capture_subprocess cap
+ = support_capture_subprogram (support_objdir_elf_ldso, argv);
+ support_capture_subprocess_check (&cap, "no --argv0", 0, sc_allow_stdout);
+ puts ("info: output without --argv0:");
+ puts (cap.out.buffer);
+ TEST_VERIFY (strstr (cap.out.buffer, "Usage: ldconfig [OPTION...]\n")
+ == cap.out.buffer);
+ support_capture_subprocess_free (&cap);
+ }
+
+ {
+ char *argv[] =
+ {
+ (char *) "ld.so", (char *) "--argv0", (char *) "ldconfig-argv0",
+ ldconfig_path, (char *) "--help", NULL
+ };
+ struct support_capture_subprocess cap
+ = support_capture_subprogram (support_objdir_elf_ldso, argv);
+ support_capture_subprocess_check (&cap, "with --argv0", 0, sc_allow_stdout);
+ puts ("info: output with --argv0:");
+ puts (cap.out.buffer);
+ TEST_VERIFY (strstr (cap.out.buffer, "Usage: ldconfig-argv0 [OPTION...]\n")
+ == cap.out.buffer);
+ support_capture_subprocess_free (&cap);
+ }
+
+ free (ldconfig_path);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/dl-execve.h b/sysdeps/generic/dl-execve.h
new file mode 100644
index 0000000000000000..5fd097df69e1770c
--- /dev/null
+++ b/sysdeps/generic/dl-execve.h
@@ -0,0 +1,25 @@
+/* execve for the dynamic linker. Generic stub version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+
+static int
+__rtld_execve (const char *path, char *const *argv, char *const *envp)
+{
+ return ENOSYS;
+}
diff --git a/sysdeps/unix/sysv/linux/dl-execve.h b/sysdeps/unix/sysv/linux/dl-execve.h
new file mode 100644
index 0000000000000000..9ec6539286bb0589
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-execve.h
@@ -0,0 +1,30 @@
+/* execve for the dynamic linker. Linux version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+
+static inline int
+__rtld_execve (const char *path, char *const *argv, char *const *envp)
+{
+ INTERNAL_SYSCALL_DECL (err);
+ long int r = INTERNAL_SYSCALL_CALL (execve, err, path, argv, envp);
+ if (INTERNAL_SYSCALL_ERROR_P (r, err))
+ return INTERNAL_SYSCALL_ERRNO (r, err);
+ else
+ return 0;
+}

View File

@ -0,0 +1,41 @@
commit 2e75604f8337fa4332977f72a8f6726309679edf
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 10 16:06:36 2021 +0100
elf: Install a symbolic link to ld.so as /usr/bin/ld.so
This makes ld.so features such as --preload, --audit,
and --list-diagnostics more accessible to end users because they
do not need to know the ABI name of the dynamic loader.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/Makefile
(versioned shared objects downstream)
diff --git a/elf/Makefile b/elf/Makefile
index b3e8ab2792608de7..c552aff350c2faac 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -99,7 +99,7 @@ endif
ifeq (yes,$(build-shared))
extra-objs = $(all-rtld-routines:%=%.os) soinit.os sofini.os interp.os
generated += librtld.os dl-allobjs.os ld.so ldd
-install-others = $(inst_rtlddir)/$(rtld-installed-name)
+install-others = $(inst_rtlddir)/$(rtld-installed-name) $(inst_bindir)/ld.so
install-bin-script = ldd
endif
@@ -622,6 +622,11 @@ $(inst_rtlddir)/$(rtld-installed-name): \
$(make-target-directory)
$(make-shlib-link)
+# Creates the relative /usr/bin/ld.so symbolic link.
+$(inst_bindir)/ld.so: $(inst_rtlddir)/$(rtld-installed-name)
+ $(make-target-directory)
+ $(make-link)
+
# Special target called by parent to install just the dynamic linker.
.PHONY: ldso_install
ldso_install: $(inst_rtlddir)/$(rtld-installed-name)

View File

@ -1,3 +1,5 @@
Additionally include stdbool.h to fix issues with bool keyword usage.
commit 60854f40ea2d420867ed2f0f052ee7fca661dbff commit 60854f40ea2d420867ed2f0f052ee7fca661dbff
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Oct 15 15:14:22 2020 -0300 Date: Thu Oct 15 15:14:22 2020 -0300

View File

@ -0,0 +1,51 @@
commit c36f64aa6dff13b12a1e03a185e75a50fa9f6a4c
Author: Hans-Peter Nilsson <hp@axis.com>
Date: Fri Dec 17 21:38:00 2021 +0100
timezone: handle truncated timezones from tzcode-2021d and later (BZ #28707)
When using a timezone file with a truncated starting time,
generated by the zic in IANA tzcode-2021d a.k.a. tzlib-2021d
(also in tzlib-2021e; current as of this writing), glibc
asserts in __tzfile_read (on e.g. tzset() for this file) and
you may find lines matching "tzfile.c:435: __tzfile_read:
Assertion `num_types == 1' failed" in your syslog.
One example of such a file is the tzfile for Asuncion
generated by tzlib-2021e as follows, using the tzlib-2021e zic:
"zic -d DEST -r @1546300800 -L /dev/null -b slim
SOURCE/southamerica". Note that in its type 2 header, it has
two entries in its "time-types" array (types), but only one
entry in its "transition types" array (type_idxs).
This is valid and expected already in the published RFC8536, and
not even frowned upon: "Local time for timestamps before the
first transition is specified by the first time type (time type
0)" ... "every nonzero local time type index SHOULD appear at
least once in the transition type array". Note the "nonzero ...
index". Until the 2021d zic, index 0 has been shared by the
first valid transition but with 2021d it's separate, set apart
as a placeholder and only "implicitly" indexed. (A draft update
of the RFC mandates that the entry at index 0 is a placeholder
in this case, hence can no longer be shared.)
* time/tzfile.c (__tzfile_read): Don't assert when no transitions
are found.
Co-authored-by: Christopher Wong <Christopher.Wong@axis.com>
diff --git a/time/tzfile.c b/time/tzfile.c
index 190a777152..8668392ad3 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -431,8 +431,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
if (__tzname[0] == NULL)
{
/* This should only happen if there are no transition rules.
- In this case there should be only one single type. */
- assert (num_types == 1);
+ In this case there's usually only one single type, unless
+ e.g. the data file has a truncated time-range. */
__tzname[0] = __tzstring (zone_names);
}
if (__tzname[1] == NULL)

View File

@ -0,0 +1,126 @@
commit ebe899af0dc3215159a9c896ac6f35b72a18cb6e
Author: Hans-Peter Nilsson <hp@axis.com>
Date: Fri Dec 17 21:45:54 2021 +0100
timezone: test-case for BZ #28707
This test-case is the tzfile for Asuncion generated by
tzlib-2021e as follows, using the tzlib-2021e zic: "zic -d
DEST -r @1546300800 -L /dev/null -b slim
SOURCE/southamerica". Note that in its type 2 header, it
has two entries in its "time-types" array (types), but only
one entry in its "transition types" array (type_idxs).
* timezone/Makefile, timezone/tst-pr28707.c,
timezone/testdata/gen-XT5.sh: New test.
Co-authored-by: Christopher Wong <Christopher.Wong@axis.com>
Reworked due to timezone/Makefile difference.
diff -Nrup a/timezone/Makefile b/timezone/Makefile
--- a/timezone/Makefile 2021-07-06 15:04:00.000000000 -0400
+++ b/timezone/Makefile 2022-01-05 15:03:57.433756574 -0500
@@ -23,7 +23,7 @@ subdir := timezone
include ../Makeconfig
others := zdump zic
-tests := test-tz tst-timezone tst-tzset
+tests := test-tz tst-timezone tst-tzset tst-bz28707
generated-dirs += testdata
@@ -85,10 +85,12 @@ $(objpfx)tst-timezone.out: $(addprefix $
America/Sao_Paulo Asia/Tokyo \
Europe/London)
$(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4)
+$(objpfx)tst-bz28707.out: $(testdata)/XT5
test-tz-ENV = TZDIR=$(testdata)
tst-timezone-ENV = TZDIR=$(testdata)
tst-tzset-ENV = TZDIR=$(testdata)
+tst-bz28707-ENV = TZDIR=$(testdata)
# Note this must come second in the deps list for $(built-program-cmd) to work.
zic-deps = $(objpfx)zic $(leapseconds) yearistype
@@ -122,6 +124,10 @@ $(testdata)/XT%: testdata/XT%
$(make-target-directory)
cp $< $@
+$(testdata)/XT%: testdata/gen-XT%.sh
+ $(SHELL) $< > $@.tmp
+ mv $@.tmp $@
+
$(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
sed -e 's|/bin/bash|$(BASH)|' \
-e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \
diff -Nrup a/timezone/testdata/gen-XT5.sh b/timezone/testdata/gen-XT5.sh
--- a/timezone/testdata/gen-XT5.sh 1969-12-31 19:00:00.000000000 -0500
+++ b/timezone/testdata/gen-XT5.sh 2022-01-05 12:50:01.666972313 -0500
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+# This test-case is the tzfile for America/Asuncion
+# generated by tzlib-2021e as follows, using the tzlib-2021e
+# zic: "zic -d DEST -r @1546300800 -L /dev/null -b slim
+# SOURCE/southamerica". Note that in its type 2 header, it
+# has two entries in its "time-types" array (types), but
+# only one entry in its "transition types" array
+# (type_idxs).
+
+printf \
+'TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'\
+'\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0TZif2\0\0\0\0\0\0\0\0'\
+'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0\b\0'\
+'\0\0\0\*\255\200\1\0\0\0\0\0\0\377\377\325\320\1\4-00\0-03\0\n'\
+'<-04>4<-03>,M10.1.0/0,M3.4.0/0\n'
diff -Nrup a/timezone/tst-bz28707.c b/timezone/tst-bz28707.c
--- a/timezone/tst-bz28707.c 1969-12-31 19:00:00.000000000 -0500
+++ b/timezone/tst-bz28707.c 2022-01-05 12:50:01.666972313 -0500
@@ -0,0 +1,46 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Test that we can use a truncated timezone-file, where the time-type
+ at index 0 is not indexed by the transition-types array (and the
+ transition-types array does not contain at least both one DST and one
+ normal time members). */
+
+static int
+do_test (void)
+{
+ if (setenv ("TZ", "XT5", 1))
+ {
+ puts ("setenv failed.");
+ return 1;
+ }
+
+ tzset ();
+
+ return
+ /* Sanity-check that we got the right timezone-name for DST. For
+ normal time, we're likely to get "-00" (the "unspecified" marker),
+ even though the POSIX timezone string says "-04". Let's not test
+ that. */
+ !(strcmp (tzname[1], "-03") == 0);
+}
+#include <support/test-driver.c>

View File

@ -0,0 +1,185 @@
commit ff012870b2c02a62598c04daa1e54632e020fd7d
Author: Nikita Popov <npv1310@gmail.com>
Date: Tue Nov 2 13:21:42 2021 +0500
gconv: Do not emit spurious NUL character in ISO-2022-JP-3 (bug 28524)
Bugfix 27256 has introduced another issue:
In conversion from ISO-2022-JP-3 encoding, it is possible
to force iconv to emit extra NUL character on internal state reset.
To do this, it is sufficient to feed iconv with escape sequence
which switches active character set.
The simplified check 'data->__statep->__count != ASCII_set'
introduced by the aforementioned bugfix picks that case and
behaves as if '\0' character has been queued thus emitting it.
To eliminate this issue, these steps are taken:
* Restore original condition
'(data->__statep->__count & ~7) != ASCII_set'.
It is necessary since bits 0-2 may contain
number of buffered input characters.
* Check that queued character is not NUL.
Similar step is taken for main conversion loop.
Bundled test case follows following logic:
* Try to convert ISO-2022-JP-3 escape sequence
switching active character set
* Reset internal state by providing NULL as input buffer
* Ensure that nothing has been converted.
Signed-off-by: Nikita Popov <npv1310@gmail.com>
Conflicts:
iconvdata/Makefile
(Copyright header. Usual test backporting differences.)
iconvdata/iso-2022-jp-3.c
(Copyright header.)
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 95e5fb8f722a513b..646e2ccd11478646 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -1,4 +1,5 @@
-# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+# Copyright (C) 1997-2021 Free Software Foundation, Inc.
+# Copyright (C) The GNU Toolchain Authors.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -73,7 +74,8 @@ modules.so := $(addsuffix .so, $(modules))
ifeq (yes,$(build-shared))
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
- bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14
+ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14 \
+ bug-iconv15
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
@@ -321,6 +323,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
+$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh \
$(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c
new file mode 100644
index 0000000000000000..cc04bd0313a68786
--- /dev/null
+++ b/iconvdata/bug-iconv15.c
@@ -0,0 +1,60 @@
+/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv
+ may emit spurious NUL character on state reset.
+ Copyright (C) The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stddef.h>
+#include <iconv.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ char in[] = "\x1b(I";
+ char *inbuf = in;
+ size_t inleft = sizeof (in) - 1;
+ char out[1];
+ char *outbuf = out;
+ size_t outleft = sizeof (out);
+ iconv_t cd;
+
+ cd = iconv_open ("UTF8", "ISO-2022-JP-3");
+ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+ /* First call to iconv should alter internal state.
+ Now, JISX0201_Kana_set is selected and
+ state value != ASCII_set. */
+ TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1);
+
+ /* No bytes should have been added to
+ the output buffer at this point. */
+ TEST_VERIFY (outbuf == out);
+ TEST_VERIFY (outleft == sizeof (out));
+
+ /* Second call shall emit spurious NUL character in unpatched glibc. */
+ TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1);
+
+ /* No characters are expected to be produced. */
+ TEST_VERIFY (outbuf == out);
+ TEST_VERIFY (outleft == sizeof (out));
+
+ TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
index 047fab8e8dfbde7e..a2b33b171e56392a 100644
--- a/iconvdata/iso-2022-jp-3.c
+++ b/iconvdata/iso-2022-jp-3.c
@@ -1,5 +1,6 @@
/* Conversion module for ISO-2022-JP-3.
- Copyright (C) 1998-2018 Free Software Foundation, Inc.
+ Copyright (C) 1998-2021 Free Software Foundation, Inc.
+ Copyright (C) The GNU Toolchain Authors.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
and Bruno Haible <bruno@clisp.org>, 2002.
@@ -81,20 +82,31 @@ enum
the output state to the initial state. This has to be done during the
flushing. */
#define EMIT_SHIFT_TO_INIT \
- if (data->__statep->__count != ASCII_set) \
+ if ((data->__statep->__count & ~7) != ASCII_set) \
{ \
if (FROM_DIRECTION) \
{ \
- if (__glibc_likely (outbuf + 4 <= outend)) \
+ uint32_t ch = data->__statep->__count >> 6; \
+ \
+ if (__glibc_unlikely (ch != 0)) \
{ \
- /* Write out the last character. */ \
- *((uint32_t *) outbuf) = data->__statep->__count >> 6; \
- outbuf += sizeof (uint32_t); \
- data->__statep->__count = ASCII_set; \
+ if (__glibc_likely (outbuf + 4 <= outend)) \
+ { \
+ /* Write out the last character. */ \
+ put32u (outbuf, ch); \
+ outbuf += 4; \
+ data->__statep->__count &= 7; \
+ data->__statep->__count |= ASCII_set; \
+ } \
+ else \
+ /* We don't have enough room in the output buffer. */ \
+ status = __GCONV_FULL_OUTPUT; \
} \
else \
- /* We don't have enough room in the output buffer. */ \
- status = __GCONV_FULL_OUTPUT; \
+ { \
+ data->__statep->__count &= 7; \
+ data->__statep->__count |= ASCII_set; \
+ } \
} \
else \
{ \

View File

@ -0,0 +1,54 @@
commit e5fa62b8db546f8792ec9e5c61e6419f4f8e3f4d
Author: Wilco Dijkstra <wdijkstr@arm.com>
Date: Thu Jan 6 14:36:28 2022 +0000
AArch64: Check for SVE in ifuncs [BZ #28744]
Add a check for SVE in the A64FX ifuncs for memcpy, memset and memmove.
This fixes BZ #28744.
Conflicts:
sysdeps/aarch64/multiarch/memcpy.c
sysdeps/aarch64/multiarch/memmove.c
sysdeps/aarch64/multiarch/memset.c
(IFUNC resolver differences in the backport.)
diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
index e0313c42e82a7b86..a6ebeb06d3bda00f 100644
--- a/sysdeps/aarch64/multiarch/memcpy.c
+++ b/sysdeps/aarch64/multiarch/memcpy.c
@@ -44,7 +44,7 @@ libc_ifunc (__libc_memcpy,
: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
? __memcpy_thunderx2
# if HAVE_AARCH64_SVE_ASM
- : (IS_A64FX (midr)
+ : (IS_A64FX (midr) && sve
? __memcpy_a64fx
: __memcpy_generic)))));
# else
diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c
index d96612b9cf7c3a4e..bea72b3eddde54c0 100644
--- a/sysdeps/aarch64/multiarch/memmove.c
+++ b/sysdeps/aarch64/multiarch/memmove.c
@@ -41,7 +41,7 @@ libc_ifunc (__libc_memmove,
: (IS_FALKOR (midr) || IS_PHECDA (midr)
? __memmove_falkor
# if HAVE_AARCH64_SVE_ASM
- : (IS_A64FX (midr)
+ : (IS_A64FX (midr) && sve
? __memmove_a64fx
: __memmove_generic))));
# else
diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c
index 2c8cc72bb0b18474..e7bd412377533f18 100644
--- a/sysdeps/aarch64/multiarch/memset.c
+++ b/sysdeps/aarch64/multiarch/memset.c
@@ -38,7 +38,7 @@ libc_ifunc (__libc_memset,
((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64
? __memset_falkor
# if HAVE_AARCH64_SVE_ASM
- : (IS_A64FX (midr)
+ : (IS_A64FX (midr) && sve
? __memset_a64fx
: __memset_generic)));
# else

View File

@ -0,0 +1,208 @@
This is a downstream rework of this upstream patch:
[PATCH v2 2/2] nss: Protect against errno changes in function lookup (bug 28953)
<https://sourceware.org/pipermail/libc-alpha/2022-March/137015.html>
The NSS module loading code has been rewritten upstream, which is why
only the test can be reused. NSS_DECLARE_MODULE_FUNCTIONS does not yet
exist downstream, so this part had to be skipped.
diff --git a/nss/Makefile b/nss/Makefile
index d5c28a6b5ed3661c..e8a7d9c7b3cefcdf 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -59,7 +59,8 @@ tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \
tst-nss-test2 \
tst-nss-test3 \
tst-nss-test4 \
- tst-nss-test5
+ tst-nss-test5 \
+ tst-nss-test_errno
xtests = bug-erange
tests-container = \
@@ -130,7 +131,7 @@ routines += $(libnss_files-routines)
static-only-routines += $(libnss_files-routines)
tests-static += tst-nss-static
endif
-extra-test-objs += nss_test1.os nss_test2.os
+extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os
include ../Rules
@@ -166,10 +167,13 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
libof-nss_test1 = extramodules
libof-nss_test2 = extramodules
+libof-nss_test_errno = extramodules
$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
$(build-module)
+$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
+ $(build-module)
$(objpfx)nss_test2.os : nss_test1.c
ifdef libnss_test1.so-version
$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
@@ -179,9 +183,13 @@ ifdef libnss_test2.so-version
$(objpfx)/libnss_test2.so$(libnss_test2.so-version): $(objpfx)/libnss_test2.so
$(make-link)
endif
+$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
+ $(objpfx)/libnss_test_errno.so
+ $(make-link)
$(patsubst %,$(objpfx)%.out,$(tests)) : \
$(objpfx)/libnss_test1.so$(libnss_test1.so-version) \
- $(objpfx)/libnss_test2.so$(libnss_test2.so-version)
+ $(objpfx)/libnss_test2.so$(libnss_test2.so-version) \
+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
ifeq (yes,$(have-thread-library))
$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
diff --git a/nss/nss_test_errno.c b/nss/nss_test_errno.c
new file mode 100644
index 0000000000000000..ca75c890aa057869
--- /dev/null
+++ b/nss/nss_test_errno.c
@@ -0,0 +1,53 @@
+/* NSS service provider with errno clobber.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ /* An arbitrary error code which is otherwise not used. */
+ errno = ELIBBAD;
+}
+
+/* Lookup functions for pwd follow that do not return any data. */
+
+enum nss_status
+_nss_test_errno_setpwent (int stayopen)
+{
+ setenv ("_nss_test_errno_setpwent", "yes", 1);
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_test_errno_getpwent_r (struct passwd *result,
+ char *buffer, size_t size, int *errnop)
+{
+ setenv ("_nss_test_errno_getpwent_r", "yes", 1);
+ return NSS_STATUS_NOTFOUND;
+}
+
+enum nss_status
+_nss_test_errno_endpwent (void)
+{
+ setenv ("_nss_test_errno_endpwent", "yes", 1);
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/nss/nsswitch.c b/nss/nsswitch.c
index 17adf1ef03f93d60..e59ab674e0426b26 100644
--- a/nss/nsswitch.c
+++ b/nss/nsswitch.c
@@ -401,6 +401,7 @@ void *
__nss_lookup_function (service_user *ni, const char *fct_name)
{
void **found, *result;
+ int saved_errno = errno;
/* We now modify global data. Protect it. */
__libc_lock_lock (lock);
@@ -523,6 +524,8 @@ __nss_lookup_function (service_user *ni, const char *fct_name)
/* Remove the lock. */
__libc_lock_unlock (lock);
+ __set_errno (saved_errno);
+
return result;
}
libc_hidden_def (__nss_lookup_function)
diff --git a/nss/tst-nss-test_errno.c b/nss/tst-nss-test_errno.c
new file mode 100644
index 0000000000000000..d2c42dd363a38b0e
--- /dev/null
+++ b/nss/tst-nss-test_errno.c
@@ -0,0 +1,61 @@
+/* getpwent failure when dlopen clobbers errno (bug 28953).
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <nss.h>
+#include <support/check.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <pwd.h>
+#include <string.h>
+
+static int
+do_test (void)
+{
+ __nss_configure_lookup ("passwd", "files test_errno");
+
+ errno = 0;
+ setpwent ();
+ TEST_COMPARE (errno, 0);
+
+ bool root_seen = false;
+ while (true)
+ {
+ errno = 0;
+ struct passwd *e = getpwent ();
+ if (e == NULL)
+ break;
+ if (strcmp (e->pw_name, "root"))
+ root_seen = true;
+ }
+
+ TEST_COMPARE (errno, 0);
+ TEST_VERIFY (root_seen);
+
+ errno = 0;
+ endpwent ();
+ TEST_COMPARE (errno, 0);
+
+ TEST_COMPARE_STRING (getenv ("_nss_test_errno_setpwent"), "yes");
+ TEST_COMPARE_STRING (getenv ("_nss_test_errno_getpwent_r"), "yes");
+ TEST_COMPARE_STRING (getenv ("_nss_test_errno_endpwent"), "yes");
+
+ return 0;
+}
+
+#include <support/test-driver.c>

112
SOURCES/wrap-find-debuginfo.sh Executable file
View File

@ -0,0 +1,112 @@
#!/bin/bash
# Wrapper script for find-debuginfo.sh
#
# Usage:
# wrap-find-debuginfo.sh SYSROOT-PATH SCRIPT-PATH SCRIPT-ARGS...
#
# The wrapper saves the original version of ld.so found in SYSROOT-PATH,
# invokes SCRIPT-PATH with SCRIPT-ARGS, and then restores the
# LDSO-PATH file, followed by note merging and DWZ compression.
# As a result, ld.so has (mostly) unchanged debuginfo even
# after debuginfo extraction.
#
# For libc.so.6 and other shared objects, a set of strategic symbols
# is preserved in .symtab that are frequently used in valgrind
# suppressions and elsewhere.
set -evx
tar_tmp="$(mktemp)"
# Prefer a separately installed debugedit over the RPM-integrated one.
if command -v debugedit >/dev/null ; then
debugedit=debugedit
else
debugedit=/usr/lib/rpm/debugedit
fi
cleanup () {
rm -f "$tar_tmp"
}
trap cleanup 0
sysroot_path="$1"
shift
script_path="$1"
shift
# See run_ldso setting in glibc.spec.
ldso_list=`cd "$sysroot_path"; find . -name 'ld-*.so' -type f`
libc_list=`cd "$sysroot_path"; find . -name 'libc-*.so' -type f`
libdl_list=`cd "$sysroot_path"; find . -name 'libdl-*.so' -type f`
libpthread_list=`cd "$sysroot_path"; find . -name 'libpthread-*.so' -type f`
librt_list=`cd "$sysroot_path"; find . -name 'librt-*.so' -type f`
full_list="$ldso_list $libc_list $libdl_list $libpthread_list $librt_list"
# Preserve the original files.
(cd "$sysroot_path"; ls -l $full_list)
(cd "$sysroot_path"; tar cvf "$tar_tmp" $full_list)
# Run the debuginfo extraction.
"$script_path" "$@"
# Restore the original files.
(cd "$sysroot_path"; tar xf "$tar_tmp")
(cd "$sysroot_path"; ls -l $full_list)
# Reduce the size of notes. Primarily for annobin.
for p in $full_list
do
objcopy --merge-notes "$sysroot_path/$p"
done
# libc.so.6 and other shared objects: Reduce to valuable symbols.
# Eliminate file symbols, annobin symbols, and symbols used by the
# glibc build to implement hidden aliases (__EI_*). We would also
# like to remove __GI_* symbols, but even listing them explicitly (as
# in -K __GI_strlen) still causes strip to remove them, so there is no
# filtering of __GI_* here. (Debuginfo is gone after this, so no need
# to optimize it.)
for p in $libc_list $libdl_list $libpthread_list $librt_list ; do
strip -w \
-K '*' \
-K '!*.c' \
-K '!*.os' \
-K '!.annobin_*' \
-K '!__EI_*' \
-K '!__PRETTY_FUNCTION__*' \
"$sysroot_path/$p"
done
# ld.so: Rewrite the source file paths to match the extracted
# locations. First compute the arguments for invoking debugedit.
# See find-debuginfo.sh.
debug_dest_name="/usr/src/debug"
last_arg=
while true ; do
arg="$1"
shift || break
case "$arg" in
(--unique-debug-src-base)
debug_dest_name="/usr/src/debug/$1"
shift
;;
(-*)
;;
(*)
last_arg="$arg"
;;
esac
done
debug_base_name=${last_arg:-$RPM_BUILD_ROOT}
for p in $ldso_list
do
$debugedit -b "$debug_base_name" -d "$debug_dest_name" -n "$sysroot_path/$p"
done
# Apply single-file DWARF optimization.
for ldso in $ldso_list
do
dwz "$sysroot_path/$p"
done

View File

@ -1,6 +1,6 @@
%define glibcsrcdir glibc-2.28 %define glibcsrcdir glibc-2.28
%define glibcversion 2.28 %define glibcversion 2.28
%define glibcrelease 164%{?dist}.3 %define glibcrelease 189.1%{?dist}
# Pre-release tarballs are pulled in from git using a command that is # Pre-release tarballs are pulled in from git using a command that is
# effectively: # effectively:
# #
@ -85,6 +85,47 @@
# here. If the arch is not listed here then a single core debuginfo package # here. If the arch is not listed here then a single core debuginfo package
# will be created for the architecture. # will be created for the architecture.
%define debuginfocommonarches %{biarcharches} alpha alphaev6 %define debuginfocommonarches %{biarcharches} alpha alphaev6
##############################################################################
# Utility functions for pre/post scripts. Stick them at the beginning of
# any lua %pre, %post, %postun, etc. sections to have them expand into
# those scripts. It only works in lua sections and not anywhere else.
%define glibc_post_funcs() \
-- We use lua posix.exec because there may be no shell that we can \
-- run during glibc upgrade. We used to implement much of %%post as a \
-- C program, but from an overall maintenance perspective the lua in \
-- the spec file was simpler and safer given the operations required. \
-- All lua code will be ignored by rpm-ostree; see: \
-- https://github.com/projectatomic/rpm-ostree/pull/1869 \
-- If we add new lua actions to the %%post code we should coordinate \
-- with rpm-ostree and ensure that their glibc install is functional. \
function post_exec (program, ...) \
local pid = posix.fork () \
if pid == 0 then \
posix.exec (program, ...) \
assert (nil) \
elseif pid > 0 then \
posix.wait (pid) \
end \
end \
\
function update_gconv_modules_cache () \
local iconv_dir = "%{_libdir}/gconv" \
local iconv_cache = iconv_dir .. "/gconv-modules.cache" \
local iconv_modules = iconv_dir .. "/gconv-modules" \
if (posix.utime (iconv_modules) == 0) then \
if (posix.utime (iconv_cache) == 0) then \
post_exec ("%{_prefix}/sbin/iconvconfig", \
"-o", iconv_cache, \
"--nostdlib", \
iconv_dir) \
else \
io.stdout:write ("Error: Missing " .. iconv_cache .. " file.\n") \
end \
end \
end \
%{nil}
############################################################################## ##############################################################################
# %%package glibc - The GNU C Library (glibc) core package. # %%package glibc - The GNU C Library (glibc) core package.
############################################################################## ##############################################################################
@ -135,6 +176,23 @@ Source11: SUPPORTED
# Include in the source RPM for reference. # Include in the source RPM for reference.
Source12: ChangeLog.old Source12: ChangeLog.old
Source13: wrap-find-debuginfo.sh
######################################################################
# Activate the wrapper script for debuginfo generation, by rewriting
# the definition of __debug_install_post.
%{lua:
local wrapper = rpm.expand("%{SOURCE13}")
local sysroot = rpm.expand("%{glibc_sysroot}")
local original = rpm.expand("%{__find_debuginfo}")
rpm.define("__find_debuginfo " .. wrapper .. " " .. sysroot .. " " .. original)
}
# The wrapper script relies on the fact that debugedit does not change
# build IDs.
%define _no_recompute_build_ids 1
%undefine _unique_build_ids
############################################################################## ##############################################################################
# Patches: # Patches:
# - See each individual patch file for origin and upstream status. # - See each individual patch file for origin and upstream status.
@ -719,18 +777,85 @@ Patch582: glibc-rh1966472-1.patch
Patch583: glibc-rh1966472-2.patch Patch583: glibc-rh1966472-2.patch
Patch584: glibc-rh1966472-3.patch Patch584: glibc-rh1966472-3.patch
Patch585: glibc-rh1966472-4.patch Patch585: glibc-rh1966472-4.patch
Patch586: glibc-rh2032280-1.patch Patch586: glibc-rh1971664-1.patch
Patch587: glibc-rh2032280-2.patch Patch587: glibc-rh1971664-2.patch
Patch588: glibc-rh2032280-3.patch Patch588: glibc-rh1971664-3.patch
Patch589: glibc-rh2032280-4.patch Patch589: glibc-rh1971664-4.patch
Patch590: glibc-rh2032280-5.patch Patch590: glibc-rh1971664-5.patch
Patch591: glibc-rh2032280-6.patch Patch591: glibc-rh1971664-6.patch
Patch592: glibc-rh2032280-7.patch Patch592: glibc-rh1971664-7.patch
Patch593: glibc-rh2045062-1.patch Patch593: glibc-rh1971664-8.patch
Patch594: glibc-rh2045062-2.patch Patch594: glibc-rh1971664-9.patch
Patch595: glibc-rh2045062-3.patch Patch595: glibc-rh1971664-10.patch
Patch596: glibc-rh2045062-4.patch Patch596: glibc-rh1971664-11.patch
Patch597: glibc-rh2045062-5.patch Patch597: glibc-rh1971664-12.patch
Patch598: glibc-rh1971664-13.patch
Patch599: glibc-rh1971664-14.patch
Patch600: glibc-rh1971664-15.patch
Patch601: glibc-rh1977614.patch
Patch602: glibc-rh1983203-1.patch
Patch603: glibc-rh1983203-2.patch
Patch604: glibc-rh2021452.patch
Patch605: glibc-rh1937515.patch
Patch606: glibc-rh1934162-1.patch
Patch607: glibc-rh1934162-2.patch
Patch608: glibc-rh2000374.patch
Patch609: glibc-rh1991001-1.patch
Patch610: glibc-rh1991001-2.patch
Patch611: glibc-rh1991001-3.patch
Patch612: glibc-rh1991001-4.patch
Patch613: glibc-rh1991001-5.patch
Patch614: glibc-rh1991001-6.patch
Patch615: glibc-rh1991001-7.patch
Patch616: glibc-rh1991001-8.patch
Patch617: glibc-rh1991001-9.patch
Patch618: glibc-rh1991001-10.patch
Patch619: glibc-rh1991001-11.patch
Patch620: glibc-rh1991001-12.patch
Patch621: glibc-rh1991001-13.patch
Patch622: glibc-rh1991001-14.patch
Patch623: glibc-rh1991001-15.patch
Patch624: glibc-rh1991001-16.patch
Patch625: glibc-rh1991001-17.patch
Patch626: glibc-rh1991001-18.patch
Patch627: glibc-rh1991001-19.patch
Patch628: glibc-rh1991001-20.patch
Patch629: glibc-rh1991001-21.patch
Patch630: glibc-rh1991001-22.patch
Patch631: glibc-rh1929928-1.patch
Patch632: glibc-rh1929928-2.patch
Patch633: glibc-rh1929928-3.patch
Patch634: glibc-rh1929928-4.patch
Patch635: glibc-rh1929928-5.patch
Patch636: glibc-rh1984802-1.patch
Patch637: glibc-rh1984802-2.patch
Patch638: glibc-rh1984802-3.patch
Patch639: glibc-rh2023420-1.patch
Patch640: glibc-rh2023420-2.patch
Patch641: glibc-rh2023420-3.patch
Patch642: glibc-rh2023420-4.patch
Patch643: glibc-rh2023420-5.patch
Patch644: glibc-rh2023420-6.patch
Patch645: glibc-rh2023420-7.patch
Patch646: glibc-rh2033648-1.patch
Patch647: glibc-rh2033648-2.patch
Patch648: glibc-rh2036955.patch
Patch649: glibc-rh2033655.patch
Patch650: glibc-rh2007327-1.patch
Patch651: glibc-rh2007327-2.patch
Patch652: glibc-rh2032281-1.patch
Patch653: glibc-rh2032281-2.patch
Patch654: glibc-rh2032281-3.patch
Patch655: glibc-rh2032281-4.patch
Patch656: glibc-rh2032281-5.patch
Patch657: glibc-rh2032281-6.patch
Patch658: glibc-rh2032281-7.patch
Patch659: glibc-rh2045063-1.patch
Patch660: glibc-rh2045063-2.patch
Patch661: glibc-rh2045063-3.patch
Patch662: glibc-rh2045063-4.patch
Patch663: glibc-rh2045063-5.patch
Patch664: glibc-rh2061727.patch
############################################################################## ##############################################################################
# Continued list of core "glibc" package information: # Continued list of core "glibc" package information:
@ -760,11 +885,6 @@ Recommends: (nss_db(x86-32) if nss_db(x86-64))
BuildRequires: gd-devel libpng-devel zlib-devel BuildRequires: gd-devel libpng-devel zlib-devel
%endif %endif
%if %{with docs} %if %{with docs}
# Removing texinfo will cause check-safety.sh test to fail because it seems to
# trigger documentation generation based on dependencies. We need to fix this
# upstream in some way that doesn't depend on generating docs to validate the
# texinfo. I expect it's simply the wrong dependency for that target.
BuildRequires: texinfo >= 5.0
%endif %endif
%if %{without bootstrap} %if %{without bootstrap}
BuildRequires: libselinux-devel >= 1.33.4-3 BuildRequires: libselinux-devel >= 1.33.4-3
@ -825,7 +945,8 @@ Conflicts: prelink < 0.4.2
%if 0%{?_enable_debug_packages} %if 0%{?_enable_debug_packages}
BuildRequires: elfutils >= 0.72 BuildRequires: elfutils >= 0.72
BuildRequires: rpm >= 4.2-0.56 # -20 adds __find_debuginfo macro
BuildRequires: rpm >= 4.14.3-20
%endif %endif
%if %{without bootstrap} %if %{without bootstrap}
@ -861,6 +982,10 @@ BuildRequires: libidn2
Requires: glibc-langpack = %{version}-%{release} Requires: glibc-langpack = %{version}-%{release}
Suggests: glibc-all-langpacks = %{version}-%{release} Suggests: glibc-all-langpacks = %{version}-%{release}
# Suggest extra gconv modules so that they are installed by default but can be
# removed if needed to build a minimal OS image.
Recommends: glibc-gconv-extra%{_isa} = %{version}-%{release}
%description %description
The glibc package contains standard libraries which are used by The glibc package contains standard libraries which are used by
multiple programs on the system. In order to save disk space and multiple programs on the system. In order to save disk space and
@ -908,6 +1033,26 @@ executables.
Install glibc-devel if you are going to develop programs which will Install glibc-devel if you are going to develop programs which will
use the standard C libraries. use the standard C libraries.
##############################################################################
# glibc "doc" sub-package
##############################################################################
%if %{with docs}
%package doc
Summary: Documentation for GNU libc
BuildArch: noarch
Requires: %{name} = %{version}-%{release}
# Removing texinfo will cause check-safety.sh test to fail because it seems to
# trigger documentation generation based on dependencies. We need to fix this
# upstream in some way that doesn't depend on generating docs to validate the
# texinfo. I expect it's simply the wrong dependency for that target.
BuildRequires: texinfo >= 5.0
%description doc
The glibc-doc package contains The GNU C Library Reference Manual in info
format. Additional package documentation is also provided.
%endif
############################################################################## ##############################################################################
# glibc "static" sub-package # glibc "static" sub-package
############################################################################## ##############################################################################
@ -1110,6 +1255,15 @@ nothing else. It is designed for assembling a minimal system.
%files minimal-langpack %files minimal-langpack
%endif %endif
# Infrequently used iconv converter modules.
%package gconv-extra
Summary: All iconv converter modules for %{name}.
Requires: %{name}%{_isa} = %{version}-%{release}
Requires: %{name}-common = %{version}-%{release}
%description gconv-extra
This package contains all iconv converter modules built in %{name}.
############################################################################## ##############################################################################
# glibc "nscd" sub-package # glibc "nscd" sub-package
############################################################################## ##############################################################################
@ -1192,62 +1346,6 @@ which can be helpful during program debugging.
If unsure if you need this, don't install this package. If unsure if you need this, don't install this package.
##############################################################################
# glibc core "debuginfo" sub-package
##############################################################################
%if 0%{?_enable_debug_packages}
%define debug_package %{nil}
%define __debug_install_post %{nil}
%global __debug_package 1
# Disable thew new features that glibc packages don't use.
%undefine _debugsource_packages
%undefine _debuginfo_subpackages
%undefine _unique_debug_names
%undefine _unique_debug_srcs
%package debuginfo
Summary: Debug information for package %{name}
AutoReqProv: no
%ifarch %{debuginfocommonarches}
Requires: glibc-debuginfo-common = %{version}-%{release}
%else
%ifarch %{ix86} %{sparc}
Obsoletes: glibc-debuginfo-common
%endif
%endif
%description debuginfo
This package provides debug information for package %{name}.
Debug information is useful when developing applications that use this
package or when debugging this package.
This package also contains static standard C libraries with
debugging information. You need this only if you want to step into
C library routines during debugging programs statically linked against
one or more of the standard C libraries.
To use this debugging information, you need to link binaries
with -static -L%{_prefix}/lib/debug%{_libdir} compiler options.
##############################################################################
# glibc common "debuginfo-common" sub-package
##############################################################################
%ifarch %{debuginfocommonarches}
%package debuginfo-common
Summary: Debug information for package %{name}
AutoReqProv: no
%description debuginfo-common
This package provides debug information for package %{name}.
Debug information is useful when developing applications that use this
package or when debugging this package.
%comment Matches: %ifarch %{debuginfocommonarches}
%endif
%comment Matches: %if 0%{?_enable_debug_packages}
%endif
%if %{with benchtests} %if %{with benchtests}
%package benchtests %package benchtests
Summary: Benchmarking binaries and scripts for %{name} Summary: Benchmarking binaries and scripts for %{name}
@ -1614,6 +1712,9 @@ fi
# Compress all of the info files. # Compress all of the info files.
gzip -9nvf %{glibc_sysroot}%{_infodir}/libc* gzip -9nvf %{glibc_sysroot}%{_infodir}/libc*
# Copy the debugger interface documentation over to the right location
mkdir -p %{glibc_sysroot}%{_docdir}/glibc
cp elf/rtld-debugger-interface.txt %{glibc_sysroot}%{_docdir}/glibc
%else %else
rm -f %{glibc_sysroot}%{_infodir}/dir rm -f %{glibc_sysroot}%{_infodir}/dir
rm -f %{glibc_sysroot}%{_infodir}/libc.info* rm -f %{glibc_sysroot}%{_infodir}/libc.info*
@ -1705,15 +1806,6 @@ chmod 644 %{glibc_sysroot}%{_libdir}/gconv/gconv-modules.cache
# archives we might have added. # archives we might have added.
############################################################################## ##############################################################################
# If we are building a debug package then copy all of the static archives
# into the debug directory to keep them as unstripped copies.
%if 0%{?_enable_debug_packages}
mkdir -p %{glibc_sysroot}%{_prefix}/lib/debug%{_libdir}
cp -a %{glibc_sysroot}%{_libdir}/*.a \
%{glibc_sysroot}%{_prefix}/lib/debug%{_libdir}/
rm -f %{glibc_sysroot}%{_prefix}/lib/debug%{_libdir}/*_p.a
%endif
# Remove any zoneinfo files; they are maintained by tzdata. # Remove any zoneinfo files; they are maintained by tzdata.
rm -rf %{glibc_sysroot}%{_prefix}/share/zoneinfo rm -rf %{glibc_sysroot}%{_prefix}/share/zoneinfo
@ -1727,7 +1819,14 @@ touch -r %{SOURCE0} %{glibc_sysroot}/etc/ld.so.conf
touch -r sunrpc/etc.rpc %{glibc_sysroot}/etc/rpc touch -r sunrpc/etc.rpc %{glibc_sysroot}/etc/rpc
pushd build-%{target} pushd build-%{target}
$GCC -Os -g -static -o build-locale-archive %{SOURCE1} \ $GCC -Os -g \
%ifarch %{pie_arches}
-fPIE \
-static-pie \
%else
-static \
%endif
-o build-locale-archive %{SOURCE1} \
../build-%{target}/locale/locarchive.o \ ../build-%{target}/locale/locarchive.o \
../build-%{target}/locale/md5.o \ ../build-%{target}/locale/md5.o \
../build-%{target}/locale/record-status.o \ ../build-%{target}/locale/record-status.o \
@ -1737,12 +1836,6 @@ $GCC -Os -g -static -o build-locale-archive %{SOURCE1} \
install -m 700 build-locale-archive %{glibc_sysroot}%{_prefix}/sbin/build-locale-archive install -m 700 build-locale-archive %{glibc_sysroot}%{_prefix}/sbin/build-locale-archive
popd popd
# Lastly copy some additional documentation for the packages.
rm -rf documentation
mkdir documentation
cp timezone/README documentation/README.timezone
cp posix/gai.conf documentation/
%ifarch s390x %ifarch s390x
# Compatibility symlink # Compatibility symlink
mkdir -p %{glibc_sysroot}/lib mkdir -p %{glibc_sysroot}/lib
@ -1767,6 +1860,7 @@ cp benchtests/scripts/benchout.schema.json %{glibc_sysroot}%{_prefix}/libexec/gl
cp benchtests/scripts/compare_bench.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ cp benchtests/scripts/compare_bench.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/
cp benchtests/scripts/import_bench.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ cp benchtests/scripts/import_bench.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/
cp benchtests/scripts/validate_benchout.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/ cp benchtests/scripts/validate_benchout.py %{glibc_sysroot}%{_prefix}/libexec/glibc-benchtests/
%endif
%if 0%{?_enable_debug_packages} %if 0%{?_enable_debug_packages}
# The #line directives gperf generates do not give the proper # The #line directives gperf generates do not give the proper
@ -1777,6 +1871,7 @@ popd
pushd iconv pushd iconv
ln -s ../locale/programs/charmap-kw.gperf . ln -s ../locale/programs/charmap-kw.gperf .
popd popd
%endif
%if %{with docs} %if %{with docs}
# Remove the `dir' info-heirarchy file which will be maintained # Remove the `dir' info-heirarchy file which will be maintained
@ -1861,6 +1956,8 @@ ar cr %{glibc_sysroot}%{_prefix}/%{_lib}/libpthread_nonshared.a
# - Files for the nscd subpackage. # - Files for the nscd subpackage.
# * devel.filelist # * devel.filelist
# - Files for the devel subpackage. # - Files for the devel subpackage.
# * doc.filelist
# - Files for the documentation subpackage.
# * headers.filelist # * headers.filelist
# - Files for the headers subpackage. # - Files for the headers subpackage.
# * static.filelist # * static.filelist
@ -1874,11 +1971,6 @@ ar cr %{glibc_sysroot}%{_prefix}/%{_lib}/libpthread_nonshared.a
# - File list with the .so symbolic links for NSS packages. # - File list with the .so symbolic links for NSS packages.
# * compat-libpthread-nonshared.filelist. # * compat-libpthread-nonshared.filelist.
# - File list for compat-libpthread-nonshared subpackage. # - File list for compat-libpthread-nonshared subpackage.
# * debuginfo.filelist
# - Files for the glibc debuginfo package.
# * debuginfocommon.filelist
# - Files for the glibc common debuginfo package.
#
# Create the main file lists. This way we can append to any one of them later # Create the main file lists. This way we can append to any one of them later
# wihtout having to create it. Note these are removed at the start of the # wihtout having to create it. Note these are removed at the start of the
@ -1887,8 +1979,10 @@ touch master.filelist
touch glibc.filelist touch glibc.filelist
touch common.filelist touch common.filelist
touch utils.filelist touch utils.filelist
touch gconv.filelist
touch nscd.filelist touch nscd.filelist
touch devel.filelist touch devel.filelist
touch doc.filelist
touch headers.filelist touch headers.filelist
touch static.filelist touch static.filelist
touch libnsl.filelist touch libnsl.filelist
@ -1896,8 +1990,6 @@ touch nss_db.filelist
touch nss_hesiod.filelist touch nss_hesiod.filelist
touch nss-devel.filelist touch nss-devel.filelist
touch compat-libpthread-nonshared.filelist touch compat-libpthread-nonshared.filelist
touch debuginfo.filelist
touch debuginfocommon.filelist
############################################################################### ###############################################################################
# Master file list, excluding a few things. # Master file list, excluding a few things.
@ -1909,10 +2001,10 @@ touch debuginfocommon.filelist
find %{glibc_sysroot} \( -type f -o -type l \) \ find %{glibc_sysroot} \( -type f -o -type l \) \
\( \ \( \
-name etc -printf "%%%%config " -o \ -name etc -printf "%%%%config " -o \
-name gconv-modules \ -name gconv-modules.cache \
-printf "%%%%verify(not md5 size mtime) %%%%config(noreplace) " -o \ -printf "%%%%verify(not md5 size mtime) " -o \
-name gconv-modules.cache \ -name gconv-modules* \
-printf "%%%%verify(not md5 size mtime) " \ -printf "%%%%verify(not md5 size mtime) %%%%config(noreplace) " \
, \ , \
! -path "*/lib/debug/*" -printf "/%%P\n" \) ! -path "*/lib/debug/*" -printf "/%%P\n" \)
# List all directories with a %%dir prefix. We omit the info directory and # List all directories with a %%dir prefix. We omit the info directory and
@ -1964,6 +2056,7 @@ chmod 0444 master.filelist
# - All bench test binaries. # - All bench test binaries.
# - The aux-cache, since it's handled specially in the files section. # - The aux-cache, since it's handled specially in the files section.
# - The build-locale-archive binary since it's in the common package. # - The build-locale-archive binary since it's in the common package.
# - Extra gconv modules. We add the required modules later.
cat master.filelist \ cat master.filelist \
| grep -v \ | grep -v \
-e '%{_infodir}' \ -e '%{_infodir}' \
@ -1972,6 +2065,8 @@ cat master.filelist \
-e '%{_libdir}/lib.*\.a' \ -e '%{_libdir}/lib.*\.a' \
-e '%{_libdir}/.*\.o' \ -e '%{_libdir}/.*\.o' \
-e '%{_libdir}/lib.*\.so' \ -e '%{_libdir}/lib.*\.so' \
-e '%{_libdir}/gconv/.*\.so$' \
-e '%{_libdir}/gconv/gconv-modules.d/gconv-modules-extra\.conf$' \
-e 'nscd' \ -e 'nscd' \
-e '%{_prefix}/bin' \ -e '%{_prefix}/bin' \
-e '%{_prefix}/lib/locale' \ -e '%{_prefix}/lib/locale' \
@ -1997,18 +2092,41 @@ done
grep -e "libmemusage.so" -e "libpcprofile.so" master.filelist >> glibc.filelist grep -e "libmemusage.so" -e "libpcprofile.so" master.filelist >> glibc.filelist
############################################################################### ###############################################################################
# glibc-devel # glibc-gconv-extra
############################################################################### ###############################################################################
%if %{with docs} grep -e "gconv-modules-extra.conf" master.filelist > gconv.filelist
# Put the info files into the devel file list, but exclude the generated dir.
grep '%{_infodir}' master.filelist | grep -v '%{_infodir}/dir' > devel.filelist # Put the essential gconv modules into the main package.
GconvBaseModules="ANSI_X3.110 ISO8859-15 ISO8859-1 CP1252"
GconvBaseModules="$GconvBaseModules UNICODE UTF-16 UTF-32 UTF-7"
%ifarch s390 s390x
GconvBaseModules="$GconvBaseModules ISO-8859-1_CP037_Z900 UTF8_UTF16_Z9"
GconvBaseModules="$GconvBaseModules UTF16_UTF32_Z9 UTF8_UTF32_Z9"
%endif %endif
GconvAllModules=$(cat master.filelist |
sed -n 's|%{_libdir}/gconv/\(.*\)\.so|\1|p')
# Put the base modules into glibc and the rest into glibc-gconv-extra
for conv in $GconvAllModules; do
if echo $GconvBaseModules | grep -q $conv; then
grep -E -e "%{_libdir}/gconv/$conv.so$" \
master.filelist >> glibc.filelist
else
grep -E -e "%{_libdir}/gconv/$conv.so$" \
master.filelist >> gconv.filelist
fi
done
###############################################################################
# glibc-devel
###############################################################################
# Put some static files into the devel package. # Put some static files into the devel package.
grep '%{_libdir}/lib.*\.a' master.filelist \ grep '%{_libdir}/lib.*\.a' master.filelist \
| grep '/lib\(\(c\|pthread\|nldbl\|mvec\)_nonshared\|g\|ieee\|mcheck\)\.a$' \ | grep '/lib\(\(c\|pthread\|nldbl\|mvec\)_nonshared\|g\|ieee\|mcheck\)\.a$' \
>> devel.filelist > devel.filelist
# Put all of the object files and *.so (not the versioned ones) into the # Put all of the object files and *.so (not the versioned ones) into the
# devel package. # devel package.
@ -2022,6 +2140,16 @@ sed -i -e '\,libmemusage.so,d' \
-e '\,/libnss_[a-z]*\.so$,d' \ -e '\,/libnss_[a-z]*\.so$,d' \
devel.filelist devel.filelist
###############################################################################
# glibc-doc
###############################################################################
%if %{with docs}
# Put the info files into the doc file list, but exclude the generated dir.
grep '%{_infodir}' master.filelist | grep -v '%{_infodir}/dir' > doc.filelist
grep '%{_docdir}' master.filelist >> doc.filelist
%endif
############################################################################### ###############################################################################
# glibc-headers # glibc-headers
############################################################################### ###############################################################################
@ -2064,12 +2192,14 @@ grep '%{_prefix}/sbin' master.filelist \
# multilib-independent. # multilib-independent.
# Exceptions: # Exceptions:
# - The actual share directory, not owned by us. # - The actual share directory, not owned by us.
# - The info files which go in devel, and the info directory. # - The info files which go into doc, and the info directory.
# - All documentation files, which go into doc.
grep '%{_prefix}/share' master.filelist \ grep '%{_prefix}/share' master.filelist \
| grep -v \ | grep -v \
-e '%{_prefix}/share/info/libc.info.*' \ -e '%{_prefix}/share/info/libc.info.*' \
-e '%%dir %{prefix}/share/info' \ -e '%%dir %{prefix}/share/info' \
-e '%%dir %{prefix}/share' \ -e '%%dir %{prefix}/share' \
-e '%{_docdir}' \
>> common.filelist >> common.filelist
# Add the binary to build locales to the common subpackage. # Add the binary to build locales to the common subpackage.
@ -2091,8 +2221,8 @@ cat > utils.filelist <<EOF
%if %{without bootstrap} %if %{without bootstrap}
%{_prefix}/bin/memusage %{_prefix}/bin/memusage
%{_prefix}/bin/memusagestat %{_prefix}/bin/memusagestat
%endif
%{_prefix}/bin/mtrace %{_prefix}/bin/mtrace
%endif
%{_prefix}/bin/pcprofiledump %{_prefix}/bin/pcprofiledump
%{_prefix}/bin/xtrace %{_prefix}/bin/xtrace
EOF EOF
@ -2124,6 +2254,7 @@ grep '/libnss_[a-z]*\.so$' master.filelist > nss-devel.filelist
grep '/libnsl-[0-9.]*.so$' master.filelist > libnsl.filelist grep '/libnsl-[0-9.]*.so$' master.filelist > libnsl.filelist
test $(wc -l < libnsl.filelist) -eq 1 test $(wc -l < libnsl.filelist) -eq 1
%if %{with benchtests}
############################################################################### ###############################################################################
# glibc-benchtests # glibc-benchtests
############################################################################### ###############################################################################
@ -2148,101 +2279,6 @@ echo "%{_prefix}/libexec/glibc-benchtests/validate_benchout.py*" >> benchtests.f
############################################################################### ###############################################################################
echo "%{_libdir}/libpthread_nonshared.a" >> compat-libpthread-nonshared.filelist echo "%{_libdir}/libpthread_nonshared.a" >> compat-libpthread-nonshared.filelist
###############################################################################
# glibc-debuginfocommon, and glibc-debuginfo
###############################################################################
find_debuginfo_args='--strict-build-id -g -i'
%ifarch %{debuginfocommonarches}
find_debuginfo_args="$find_debuginfo_args \
-l common.filelist \
-l utils.filelist \
-l nscd.filelist \
-p '.*/(sbin|libexec)/.*' \
-o debuginfocommon.filelist \
-l nss_db.filelist -l nss_hesiod.filelist \
-l libnsl.filelist -l glibc.filelist \
%if %{with benchtests}
-l benchtests.filelist
%endif
"
%endif
/usr/lib/rpm/find-debuginfo.sh $find_debuginfo_args -o debuginfo.filelist
# List all of the *.a archives in the debug directory.
list_debug_archives()
{
local dir=%{_prefix}/lib/debug%{_libdir}
find %{glibc_sysroot}$dir -name "*.a" -printf "$dir/%%P\n"
}
%ifarch %{debuginfocommonarches}
# Remove the source files from the common package debuginfo.
sed -i '\#^%{glibc_sysroot}%{_prefix}/src/debug/#d' debuginfocommon.filelist
# Create a list of all of the source files we copied to the debug directory.
find %{glibc_sysroot}%{_prefix}/src/debug \
\( -type d -printf '%%%%dir ' \) , \
-printf '%{_prefix}/src/debug/%%P\n' > debuginfocommon.sources
%ifarch %{biarcharches}
# Add the source files to the core debuginfo package.
cat debuginfocommon.sources >> debuginfo.filelist
%else
%ifarch %{ix86}
%define basearch i686
%endif
%ifarch sparc sparcv9
%define basearch sparc
%endif
# The auxarches get only these few source files.
auxarches_debugsources=\
'/(generic|linux|%{basearch}|nptl(_db)?)/|/%{glibcsrcdir}/build|/dl-osinfo\.h'
# Place the source files into the core debuginfo pakcage.
egrep "$auxarches_debugsources" debuginfocommon.sources >> debuginfo.filelist
# Remove the source files from the common debuginfo package.
egrep -v "$auxarches_debugsources" \
debuginfocommon.sources >> debuginfocommon.filelist
%comment Matches: %ifarch %{biarcharches}
%endif
# Add the list of *.a archives in the debug directory to
# the common debuginfo package.
list_debug_archives >> debuginfocommon.filelist
%comment Matches: %ifarch %{debuginfocommonarches}
%endif
# Remove some common directories from the common package debuginfo so that we
# don't end up owning them.
exclude_common_dirs()
{
exclude_dirs="%{_prefix}/src/debug"
exclude_dirs="$exclude_dirs $(echo %{_prefix}/lib/debug{,/%{_lib},/bin,/sbin})"
exclude_dirs="$exclude_dirs $(echo %{_prefix}/lib/debug%{_prefix}{,/%{_lib},/libexec,/bin,/sbin})"
for d in $(echo $exclude_dirs | sed 's/ /\n/g'); do
sed -i "\|^%%dir $d/\?$|d" $1
done
}
%ifarch %{debuginfocommonarches}
exclude_common_dirs debuginfocommon.filelist
%endif
exclude_common_dirs debuginfo.filelist
%comment Matches: %if 0%{?_enable_debug_packages}
%endif
############################################################################## ##############################################################################
# Delete files that we do not intended to ship with the auxarch. # Delete files that we do not intended to ship with the auxarch.
# This is the only place where we touch the installed files after generating # This is the only place where we touch the installed files after generating
@ -2332,6 +2368,15 @@ echo ====================PLT RELOCS LIBC.SO==============
readelf -Wr %{glibc_sysroot}/%{_lib}/libc-*.so | sed -n -e "$PLTCMD" readelf -Wr %{glibc_sysroot}/%{_lib}/libc-*.so | sed -n -e "$PLTCMD"
echo ====================PLT RELOCS END================== echo ====================PLT RELOCS END==================
# Obtain a way to run the dynamic loader. Avoid matching the symbolic
# link and then pick the first loader (although there should be only
# one).
run_ldso="$(find %{glibc_sysroot}/%{_lib}/ld-*.so -type f | LC_ALL=C sort | head -n1) --library-path %{glibc_sysroot}/%{_lib}"
# Show the auxiliary vector as seen by the new library
# (even if we do not perform the valgrind test).
LD_SHOW_AUXV=1 $run_ldso /bin/true
# Finally, check if valgrind runs with the new glibc. # Finally, check if valgrind runs with the new glibc.
# We want to fail building if valgrind is not able to run with this glibc so # We want to fail building if valgrind is not able to run with this glibc so
# that we can then coordinate with valgrind to get it fixed before we update # that we can then coordinate with valgrind to get it fixed before we update
@ -2340,16 +2385,15 @@ pushd build-%{target}
# Show the auxiliary vector as seen by the new library # Show the auxiliary vector as seen by the new library
# (even if we do not perform the valgrind test). # (even if we do not perform the valgrind test).
LD_SHOW_AUXV=1 elf/ld.so --library-path .:elf:nptl:dlfcn /bin/true LD_SHOW_AUXV=1 $run_ldso /bin/true
%if %{with valgrind} %if %{with valgrind}
elf/ld.so --library-path .:elf:nptl:dlfcn \ $run_ldso /usr/bin/valgrind --error-exitcode=1 \
/usr/bin/valgrind --error-exitcode=1 \ $run_ldso /usr/bin/true
elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/true
%endif %endif
popd popd
%comment Matches: %if %{run_glibc_tests} %comment Matches: %if %{with testsuite}
%endif %endif
@ -2362,17 +2406,7 @@ if rpm.vercmp(rel, required) < 0 then
end end
%post -p <lua> %post -p <lua>
-- We use lua's posix.exec because there may be no shell that we can %glibc_post_funcs
-- run during glibc upgrade.
function post_exec (program, ...)
local pid = posix.fork ()
if pid == 0 then
assert (posix.exec (program, ...))
elseif pid > 0 then
posix.wait (pid)
end
end
-- (1) Remove multilib libraries from previous installs. -- (1) Remove multilib libraries from previous installs.
-- In order to support in-place upgrades, we must immediately remove -- In order to support in-place upgrades, we must immediately remove
-- obsolete platform directories after installing a new glibc -- obsolete platform directories after installing a new glibc
@ -2481,16 +2515,7 @@ post_exec ("%{_prefix}/sbin/ldconfig")
-- We assume that the cache is in _libdir/gconv and called -- We assume that the cache is in _libdir/gconv and called
-- "gconv-modules.cache". -- "gconv-modules.cache".
local iconv_dir = "%{_libdir}/gconv" update_gconv_modules_cache()
local iconv_cache = iconv_dir .. "/gconv-modules.cache"
if (posix.utime (iconv_cache) == 0) then
post_exec ("%{_prefix}/sbin/iconvconfig",
"-o", iconv_cache,
"--nostdlib",
iconv_dir)
else
io.stdout:write ("Error: Missing " .. iconv_cache .. " file.\n")
end
%posttrans all-langpacks -e -p <lua> %posttrans all-langpacks -e -p <lua>
-- If at the end of the transaction we are still installed -- If at the end of the transaction we are still installed
@ -2531,6 +2556,14 @@ if [ "$1" = 0 ]; then
fi fi
%endif %endif
%post gconv-extra -p <lua>
%glibc_post_funcs
update_gconv_modules_cache ()
%postun gconv-extra -p <lua>
%glibc_post_funcs
update_gconv_modules_cache ()
%pre -n nscd %pre -n nscd
getent group nscd >/dev/null || /usr/sbin/groupadd -g 28 -r nscd getent group nscd >/dev/null || /usr/sbin/groupadd -g 28 -r nscd
getent passwd nscd >/dev/null || getent passwd nscd >/dev/null ||
@ -2563,11 +2596,11 @@ fi
%dir /etc/ld.so.conf.d %dir /etc/ld.so.conf.d
%dir %{_prefix}/libexec/getconf %dir %{_prefix}/libexec/getconf
%dir %{_libdir}/gconv %dir %{_libdir}/gconv
%dir %{_libdir}/gconv/gconv-modules.d
%dir %attr(0700,root,root) /var/cache/ldconfig %dir %attr(0700,root,root) /var/cache/ldconfig
%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/cache/ldconfig/aux-cache %attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/cache/ldconfig/aux-cache
%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/ld.so.cache %attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/ld.so.cache
%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/gai.conf %attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /etc/gai.conf
%doc README NEWS INSTALL elf/rtld-debugger-interface.txt
# If rpm doesn't support %license, then use %doc instead. # If rpm doesn't support %license, then use %doc instead.
%{!?_licensedir:%global license %%doc} %{!?_licensedir:%global license %%doc}
%license COPYING COPYING.LIB LICENSES %license COPYING COPYING.LIB LICENSES
@ -2577,8 +2610,6 @@ fi
%dir %{_prefix}/lib/locale %dir %{_prefix}/lib/locale
%dir %{_prefix}/lib/locale/C.utf8 %dir %{_prefix}/lib/locale/C.utf8
%{_prefix}/lib/locale/C.utf8/* %{_prefix}/lib/locale/C.utf8/*
%doc documentation/README.timezone
%doc documentation/gai.conf
%files all-langpacks %files all-langpacks
%attr(0644,root,root) %verify(not md5 size mtime) %{_prefix}/lib/locale/locale-archive.tmpl %attr(0644,root,root) %verify(not md5 size mtime) %{_prefix}/lib/locale/locale-archive.tmpl
@ -2592,12 +2623,18 @@ fi
%files -f devel.filelist devel %files -f devel.filelist devel
%if %{with docs}
%files -f doc.filelist doc
%endif
%files -f static.filelist static %files -f static.filelist static
%files -f headers.filelist headers %files -f headers.filelist headers
%files -f utils.filelist utils %files -f utils.filelist utils
%files -f gconv.filelist gconv-extra
%files -f nscd.filelist -n nscd %files -f nscd.filelist -n nscd
%config(noreplace) /etc/nscd.conf %config(noreplace) /etc/nscd.conf
%dir %attr(0755,root,root) /var/run/nscd %dir %attr(0755,root,root) /var/run/nscd
@ -2627,15 +2664,6 @@ fi
%files -f libnsl.filelist -n libnsl %files -f libnsl.filelist -n libnsl
/%{_lib}/libnsl.so.1 /%{_lib}/libnsl.so.1
%if 0%{?_enable_debug_packages}
%files debuginfo -f debuginfo.filelist
%ifarch %{debuginfocommonarches}
%ifnarch %{auxarches}
%files debuginfo-common -f debuginfocommon.filelist
%endif
%endif
%endif
%if %{with benchtests} %if %{with benchtests}
%files benchtests -f benchtests.filelist %files benchtests -f benchtests.filelist
%endif %endif
@ -2643,16 +2671,91 @@ fi
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
%changelog %changelog
* Thu Jan 27 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-164.3 * Thu Mar 10 2022 Florian Weimer <fweimer@redhat.com> - 2.28-189.1
- nss: Avoid clobbering errno in get*ent via dlopen (#2061727)
* Thu Jan 27 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-189
- CVE-2021-3999: getcwd: align stack on clone in aarch64 and fix a memory leak - CVE-2021-3999: getcwd: align stack on clone in aarch64 and fix a memory leak
(#2032280) (#2032281)
* Wed Jan 26 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-164.2 * Tue Jan 25 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-188
- CVE-2022-23218, CVE-2022-23219: Fix buffer overflows in sunrpc clnt_create - CVE-2022-23218, CVE-2022-23219: Fix buffer overflows in sunrpc clnt_create
for "unix" and svcunix_create (#2045062). for "unix" and svcunix_create (#2045063).
* Mon Jan 24 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-164.1 * Mon Jan 24 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-187
- CVE-2021-3999: getcwd: Set errno to ERANGE for size == 1 (#2032280) - CVE-2021-3999: getcwd: Set errno to ERANGE for size == 1 (#2032281)
* Fri Jan 21 2022 Carlos O'Donell <carlos@redhat.com> - 2.28-186
- Fix pthread_once regression with C++ exceptions (#2007327)
* Thu Jan 20 2022 DJ Delorie <dj@redhat.com> - 2.28-185
- Adjust to rpm's find-debuginfo.sh changes, to keep stripping binaries (#1661513)
* Fri Jan 7 2022 Florian Weimer <fweimer@redhat.com> - 2.28-184
- Conversion from ISO-2022-JP-3 may emit spurious NUL character (#2033655)
* Fri Jan 7 2022 Florian Weimer <fweimer@redhat.com> - 2.28-183
- aarch64: A64FX optimizations break "sve=off" guest mode (#2036955)
* Fri Jan 7 2022 Patsy Griffin <patsy@redhat.com> - 2.28-182
- Handle truncated timezones from tzcode-2021d and later. (#2033648)
* Tue Jan 4 2022 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-181
- Weaken dependency of glibc on glibc-gconv-extra (#2015768)
* Mon Dec 13 2021 Florian Weimer <fweimer@redhat.com> - 2.28-180
- Do not install /usr/lib/debug/usr/bin/ld.so.debug (#2023420)
* Fri Dec 10 2021 Florian Weimer <fweimer@redhat.com> - 2.28-179
- Add /usr/bin/ld.so --list-diagnostics (#2023420)
* Fri Dec 10 2021 Carlos O'Donell <carlos@redhat.com> - 2.28-178
- Preliminary support for new IBM zSeries hardware (#1984802)
* Fri Dec 10 2021 Carlos O'Donell <carlos@redhat.com> - 2.28-177
- Fix --with and --without builds for benchtests and bootstrap (#2020989)
* Wed Dec 1 2021 Florian Weimer <fweimer@redhat.com> - 2.28-176
- A64FX memcpy/memmove/memset optimizations (#1929928)
* Tue Nov 30 2021 Florian Weimer <fweimer@redhat.com> - 2.28-175
- Fix dl-tls.c assert failure with pthread_create & dlopen (#1991001)
- Fix x86_64 TLS lazy binding with auditors (#1950056)
* Thu Nov 25 2021 Arjun Shankar <arjun@redhat.com> - 2.28-174
- Introduce new glibc-doc.noarch subpackage (#2021671)
- Move the reference manual info pages from glibc-devel to glibc-doc
- Move debugger interface documentation from glibc to glibc-doc
- Remove unnecessary README, INSTALL, NEWS files from glibc
- Remove unnecessary README.timezone and gai.conf files from glibc-common
* Wed Nov 17 2021 Patsy Griffin <patsy@redhat.com> - 2.28-173
- Add new English-language 12 hour time locale en_US@ampm.UTF-8 (#2000374)
* Tue Nov 16 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-172
- Build build-locale-archive with -static-pie when supported (#1965377)
* Wed Nov 10 2021 DJ Delorie <dj@redhat.com> - 2.28-171
- elf: Always set link map in _dl_init_paths (#1934162)
* Wed Nov 10 2021 Arjun Shankar <arjun@redhat.com> - 2.28-170
- x86: Properly disable XSAVE related features when its use is disabled via
tunables (#1937515)
* Wed Nov 10 2021 Arjun Shankar <arjun@redhat.com> - 2.28-169
- s390: Use long branches across object boundaries (#2021452)
* Fri Oct 29 2021 Arjun Shankar <arjun@redhat.com> - 2.28-168
- Optimize memcmp, strcpy, and stpcpy for IBM POWER10 (#1983203)
* Wed Oct 13 2021 Arjun Shankar <arjun@redhat.com> - 2.28-167
- malloc: Initiate tcache shutdown even without allocations (#1977614)
* Wed Oct 13 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-166
- Fix debuginfo location for gconv-extra and make glibc Require it (#1971664).
* Wed Oct 6 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-165
- Split extra gconv modules into a separate package (#1971664).
* Mon Aug 9 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-164 * Mon Aug 9 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-164
- librt: fix NULL pointer dereference (#1966472). - librt: fix NULL pointer dereference (#1966472).