parent
59dbe2e5a4
commit
c7ca62b055
@ -0,0 +1,117 @@
|
||||
commit 4f5704ea347e52ac3f272d1341da10aed6e9973e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Dec 10 16:17:06 2024 +0100
|
||||
|
||||
powerpc: Use correct procedure call standard for getrandom vDSO call (bug 32440)
|
||||
|
||||
A plain indirect function call does not work on POWER because
|
||||
success and failure are signaled through a flag register, and
|
||||
not via the usual Linux negative return value convention.
|
||||
|
||||
This has potential security impact, in two ways: the return value
|
||||
could be out of bounds (EAGAIN is 11 on powerpc6le), and no
|
||||
random bytes have been written despite the non-error return value.
|
||||
|
||||
Fixes commit 461cab1de747f3842f27a5d24977d78d561d45f9 ("linux: Add
|
||||
support for getrandom vDSO").
|
||||
|
||||
Reported-by: Ján Stanček <jstancek@redhat.com>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||
index 44a118da59f96c17..d3f55249434cc3e8 100644
|
||||
--- a/stdlib/Makefile
|
||||
+++ b/stdlib/Makefile
|
||||
@@ -276,6 +276,7 @@ tests := \
|
||||
tst-cxa_atexit \
|
||||
tst-environ \
|
||||
tst-getrandom \
|
||||
+ tst-getrandom-errno \
|
||||
tst-getrandom2 \
|
||||
tst-labs \
|
||||
tst-limits \
|
||||
diff --git a/stdlib/tst-getrandom-errno.c b/stdlib/tst-getrandom-errno.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..75a60e53ad4e7350
|
||||
--- /dev/null
|
||||
+++ b/stdlib/tst-getrandom-errno.c
|
||||
@@ -0,0 +1,37 @@
|
||||
+/* Test errno handling in getrandom (bug 32440).
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 <stdlib.h>
|
||||
+#include <support/check.h>
|
||||
+#include <sys/random.h>
|
||||
+
|
||||
+static
|
||||
+int do_test (void)
|
||||
+{
|
||||
+ errno = -1181968554; /* Just a random value. */
|
||||
+ char buf[4];
|
||||
+ int ret = getrandom (buf, sizeof (buf), -1); /* All flags set. */
|
||||
+ if (errno != ENOSYS)
|
||||
+ TEST_COMPARE (errno, EINVAL);
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
|
||||
index c8c578263da456b2..0dc8fa6e65b9ef6a 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getrandom.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getrandom.c
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sysdep-cancel.h>
|
||||
+#include <sysdep.h>
|
||||
+#include <sysdep-vdso.h>
|
||||
|
||||
static inline ssize_t
|
||||
getrandom_syscall (void *buffer, size_t length, unsigned int flags,
|
||||
@@ -201,11 +203,12 @@ getrandom_vdso (void *buffer, size_t length, unsigned int flags, bool cancel)
|
||||
cancellation bridge (__syscall_cancel_arch), use GRND_NONBLOCK so there
|
||||
is no potential unbounded blocking in the kernel. It should be a rare
|
||||
situation, only at system startup when RNG is not initialized. */
|
||||
- ssize_t ret = GLRO (dl_vdso_getrandom) (buffer,
|
||||
- length,
|
||||
- flags | GRND_NONBLOCK,
|
||||
- state,
|
||||
- state_size);
|
||||
+ long int ret = INTERNAL_VSYSCALL_CALL (GLRO (dl_vdso_getrandom), 5,
|
||||
+ buffer,
|
||||
+ length,
|
||||
+ flags | GRND_NONBLOCK,
|
||||
+ state,
|
||||
+ state_size);
|
||||
if (INTERNAL_SYSCALL_ERROR_P (ret))
|
||||
{
|
||||
/* Fallback to the syscall if the kernel would block. */
|
||||
@@ -241,7 +244,9 @@ __getrandom_early_init (_Bool initial)
|
||||
uint32_t mmap_flags;
|
||||
uint32_t reserved[13];
|
||||
} params;
|
||||
- if (GLRO(dl_vdso_getrandom) (NULL, 0, 0, ¶ms, ~0UL) == 0)
|
||||
+ long int ret = INTERNAL_VSYSCALL_CALL (GLRO(dl_vdso_getrandom),
|
||||
+ 5, NULL, 0, 0, ¶ms, ~0UL);
|
||||
+ if (! INTERNAL_SYSCALL_ERROR_P (ret))
|
||||
{
|
||||
/* Align each opaque state to L1 data cache size to avoid false
|
||||
sharing. If the size can not be obtained, use the kernel
|
@ -0,0 +1,32 @@
|
||||
commit b933e5cef63a6c136fe57de29eba7abc51b678de
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sun Dec 15 17:05:25 2024 +0100
|
||||
|
||||
Linux: Check for 0 return value from vDSO getrandom probe
|
||||
|
||||
As of Linux 6.13, there is no code in the vDSO that declines this
|
||||
initialization request with the special ~0UL state size. If the vDSO
|
||||
has the function, the call succeeds and returns 0. It's expected
|
||||
that the code would follow the “a negative value indicating an error”
|
||||
convention, as indicated in the __cvdso_getrandom_data function
|
||||
comment, so that INTERNAL_SYSCALL_ERROR_P on glibc's side would return
|
||||
true. This commit changes the commit to check for zero to indicate
|
||||
success instead, which covers potential future non-zero success
|
||||
return values and error returns.
|
||||
|
||||
Fixes commit 4f5704ea347e52ac3f272d1341da10aed6e9973e ("powerpc: Use
|
||||
correct procedure call standard for getrandom vDSO call (bug 32440)").
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
|
||||
index 0dc8fa6e65b9ef6a..d3eab66a1af6229e 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getrandom.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getrandom.c
|
||||
@@ -246,7 +246,7 @@ __getrandom_early_init (_Bool initial)
|
||||
} params;
|
||||
long int ret = INTERNAL_VSYSCALL_CALL (GLRO(dl_vdso_getrandom),
|
||||
5, NULL, 0, 0, ¶ms, ~0UL);
|
||||
- if (! INTERNAL_SYSCALL_ERROR_P (ret))
|
||||
+ if (ret == 0)
|
||||
{
|
||||
/* Align each opaque state to L1 data cache size to avoid false
|
||||
sharing. If the size can not be obtained, use the kernel
|
@ -0,0 +1,811 @@
|
||||
commit 461cab1de747f3842f27a5d24977d78d561d45f9
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Wed Sep 18 16:01:22 2024 +0200
|
||||
|
||||
linux: Add support for getrandom vDSO
|
||||
|
||||
Linux 6.11 has getrandom() in vDSO. It operates on a thread-local opaque
|
||||
state allocated with mmap using flags specified by the vDSO.
|
||||
|
||||
Multiple states are allocated at once, as many as fit into a page, and
|
||||
these are held in an array of available states to be doled out to each
|
||||
thread upon first use, and recycled when a thread terminates. As these
|
||||
states run low, more are allocated.
|
||||
|
||||
To make this procedure async-signal-safe, a simple guard is used in the
|
||||
LSB of the opaque state address, falling back to the syscall if there's
|
||||
reentrancy contention.
|
||||
|
||||
Also, _Fork() is handled by blocking signals on opaque state allocation
|
||||
(so _Fork() always sees a consistent state even if it interrupts a
|
||||
getrandom() call) and by iterating over the thread stack cache on
|
||||
reclaim_stack. Each opaque state will be in the free states list
|
||||
(grnd_alloc.states) or allocated to a running thread.
|
||||
|
||||
The cancellation is handled by always using GRND_NONBLOCK flags while
|
||||
calling the vDSO, and falling back to the cancellable syscall if the
|
||||
kernel returns EAGAIN (would block). Since getrandom is not defined by
|
||||
POSIX and cancellation is supported as an extension, the cancellation is
|
||||
handled as 'may occur' instead of 'shall occur' [1], meaning that if
|
||||
vDSO does not block (the expected behavior) getrandom will not act as a
|
||||
cancellation entrypoint. It avoids a pthread_testcancel call on the fast
|
||||
path (different than 'shall occur' functions, like sem_wait()).
|
||||
|
||||
It is currently enabled for x86_64, which is available in Linux 6.11,
|
||||
and aarch64, powerpc32, powerpc64, loongarch64, and s390x, which are
|
||||
available in Linux 6.12.
|
||||
|
||||
Link: https://pubs.opengroup.org/onlinepubs/9799919799/nframe.html [1]
|
||||
Co-developed-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Tested-by: Jason A. Donenfeld <Jason@zx2c4.com> # x86_64
|
||||
Tested-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> # x86_64, aarch64
|
||||
Tested-by: Xi Ruoyao <xry111@xry111.site> # x86_64, aarch64, loongarch64
|
||||
Tested-by: Stefan Liebler <stli@linux.ibm.com> # s390x
|
||||
|
||||
Conflicts:
|
||||
stdlib/Makefile
|
||||
(usual test differences)
|
||||
sysdeps/unix/sysv/linux/dl-vdso-setup.h
|
||||
(glibc-2.39 does not have riscv hwprobe vdso support)
|
||||
|
||||
diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c
|
||||
index 575b837f8f43cb75..20c71fd48b5bd604 100644
|
||||
--- a/elf/libc_early_init.c
|
||||
+++ b/elf/libc_early_init.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <lowlevellock.h>
|
||||
#include <pthread_early_init.h>
|
||||
#include <sys/single_threaded.h>
|
||||
+#include <getrandom-internal.h>
|
||||
|
||||
#ifdef SHARED
|
||||
_Bool __libc_initial;
|
||||
@@ -43,6 +44,8 @@ __libc_early_init (_Bool initial)
|
||||
|
||||
__pthread_early_init ();
|
||||
|
||||
+ __getrandom_early_init (initial);
|
||||
+
|
||||
#if ENABLE_ELISION_SUPPORT
|
||||
__lll_elision_init ();
|
||||
#endif
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index bcb6e5b83ca9777d..9e577ab90010a0f1 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -3140,8 +3140,8 @@ static void
|
||||
tcache_key_initialize (void)
|
||||
{
|
||||
/* We need to use the _nostatus version here, see BZ 29624. */
|
||||
- if (__getrandom_nocancel_nostatus (&tcache_key, sizeof(tcache_key),
|
||||
- GRND_NONBLOCK)
|
||||
+ if (__getrandom_nocancel_nostatus_direct (&tcache_key, sizeof(tcache_key),
|
||||
+ GRND_NONBLOCK)
|
||||
!= sizeof (tcache_key))
|
||||
{
|
||||
tcache_key = random_bits ();
|
||||
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
|
||||
index f35a8369bd5d197a..9ed886573fdc3b7d 100644
|
||||
--- a/nptl/allocatestack.c
|
||||
+++ b/nptl/allocatestack.c
|
||||
@@ -132,6 +132,8 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
__libc_lock_init (result->exit_lock);
|
||||
memset (&result->tls_state, 0, sizeof result->tls_state);
|
||||
|
||||
+ result->getrandom_buf = NULL;
|
||||
+
|
||||
/* Clear the DTV. */
|
||||
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
diff --git a/nptl/descr.h b/nptl/descr.h
|
||||
index 8cef95810c81eb3b..4697f633e16c7359 100644
|
||||
--- a/nptl/descr.h
|
||||
+++ b/nptl/descr.h
|
||||
@@ -404,6 +404,9 @@ struct pthread
|
||||
/* Used on strsignal. */
|
||||
struct tls_internal_t tls_state;
|
||||
|
||||
+ /* getrandom vDSO per-thread opaque state. */
|
||||
+ void *getrandom_buf;
|
||||
+
|
||||
/* rseq area registered with the kernel. Use a custom definition
|
||||
here to isolate from kernel struct rseq changes. The
|
||||
implementation of sched_getcpu needs acccess to the cpu_id field;
|
||||
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
|
||||
index 1d3665d5edb684e3..ef3ec3329027ac9f 100644
|
||||
--- a/nptl/pthread_create.c
|
||||
+++ b/nptl/pthread_create.c
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <version.h>
|
||||
#include <clone_internal.h>
|
||||
#include <futex-internal.h>
|
||||
+#include <getrandom-internal.h>
|
||||
|
||||
#include <shlib-compat.h>
|
||||
|
||||
@@ -549,6 +550,10 @@ start_thread (void *arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
+ /* Release the vDSO getrandom per-thread buffer with all signal blocked,
|
||||
+ to avoid creating a new free-state block during thread release. */
|
||||
+ __getrandom_vdso_release (pd);
|
||||
+
|
||||
if (!pd->user_stack)
|
||||
advise_stack_range (pd->stackblock, pd->stackblock_size, (uintptr_t) pd,
|
||||
pd->guardsize);
|
||||
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||
index 9898cc5d8a560625..44a118da59f96c17 100644
|
||||
--- a/stdlib/Makefile
|
||||
+++ b/stdlib/Makefile
|
||||
@@ -276,6 +276,7 @@ tests := \
|
||||
tst-cxa_atexit \
|
||||
tst-environ \
|
||||
tst-getrandom \
|
||||
+ tst-getrandom2 \
|
||||
tst-labs \
|
||||
tst-limits \
|
||||
tst-llabs \
|
||||
@@ -622,3 +623,4 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-qsort5: $(libm)
|
||||
+$(objpfx)tst-getrandom2: $(shared-thread-library)
|
||||
diff --git a/stdlib/tst-getrandom2.c b/stdlib/tst-getrandom2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..f085b4b74fcf1a28
|
||||
--- /dev/null
|
||||
+++ b/stdlib/tst-getrandom2.c
|
||||
@@ -0,0 +1,47 @@
|
||||
+/* Tests for the getrandom functions.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <sys/random.h>
|
||||
+
|
||||
+static __typeof (getrandom) *getrandom_ptr;
|
||||
+
|
||||
+static void *
|
||||
+threadfunc (void *ignored)
|
||||
+{
|
||||
+ char buffer;
|
||||
+ TEST_COMPARE (getrandom_ptr (&buffer, 1, 0), 1);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Check if issuing getrandom in the secondary libc.so works when
|
||||
+ the vDSO might be potentially used. */
|
||||
+ void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
|
||||
+ getrandom_ptr = xdlsym (handle, "getrandom");
|
||||
+ for (int i = 0; i < 1000; ++i)
|
||||
+ xpthread_join (xpthread_create (NULL, threadfunc, NULL));
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/generic/getrandom-internal.h b/sysdeps/generic/getrandom-internal.h
|
||||
new file mode 100644
|
||||
index 0000000000000000..3fe46532a0ed3834
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/generic/getrandom-internal.h
|
||||
@@ -0,0 +1,26 @@
|
||||
+/* Internal definitions for getrandom implementation.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 _GETRANDOM_INTERNAL_H
|
||||
+#define _GETRANDOM_INTERNAL_H
|
||||
+
|
||||
+static inline void __getrandom_early_init (_Bool)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
diff --git a/sysdeps/generic/not-cancel.h b/sysdeps/generic/not-cancel.h
|
||||
index 2dd10646004611cf..8e3f49cc07c85d76 100644
|
||||
--- a/sysdeps/generic/not-cancel.h
|
||||
+++ b/sysdeps/generic/not-cancel.h
|
||||
@@ -51,7 +51,9 @@
|
||||
__fcntl64 (fd, cmd, __VA_ARGS__)
|
||||
#define __getrandom_nocancel(buf, size, flags) \
|
||||
__getrandom (buf, size, flags)
|
||||
-#define __getrandom_nocancel_nostatus(buf, size, flags) \
|
||||
+#define __getrandom_nocancel_direct(buf, size, flags) \
|
||||
+ __getrandom (buf, size, flags)
|
||||
+#define __getrandom_nocancel_nostatus_direct(buf, size, flags) \
|
||||
__getrandom (buf, size, flags)
|
||||
#define __poll_infinity_nocancel(fds, nfds) \
|
||||
__poll (fds, nfds, -1)
|
||||
diff --git a/sysdeps/mach/hurd/not-cancel.h b/sysdeps/mach/hurd/not-cancel.h
|
||||
index 69fb3c00ef774d00..ec5f5aa8954baa4d 100644
|
||||
--- a/sysdeps/mach/hurd/not-cancel.h
|
||||
+++ b/sysdeps/mach/hurd/not-cancel.h
|
||||
@@ -79,7 +79,7 @@ __typeof (__fcntl) __fcntl_nocancel;
|
||||
/* Non cancellable getrandom syscall that does not also set errno in case of
|
||||
failure. */
|
||||
static inline ssize_t
|
||||
-__getrandom_nocancel_nostatus (void *buf, size_t buflen, unsigned int flags)
|
||||
+__getrandom_nocancel_nostatus_direct (void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
int save_errno = errno;
|
||||
ssize_t r = __getrandom (buf, buflen, flags);
|
||||
@@ -90,6 +90,8 @@ __getrandom_nocancel_nostatus (void *buf, size_t buflen, unsigned int flags)
|
||||
|
||||
#define __getrandom_nocancel(buf, size, flags) \
|
||||
__getrandom (buf, size, flags)
|
||||
+#define __getrandom_nocancel_direct(buf, size, flags) \
|
||||
+ __getrandom (buf, size, flags)
|
||||
|
||||
#define __poll_infinity_nocancel(fds, nfds) \
|
||||
__poll (fds, nfds, -1)
|
||||
diff --git a/sysdeps/nptl/_Fork.c b/sysdeps/nptl/_Fork.c
|
||||
index ef199ddbc37e556c..c82fd50649c427c9 100644
|
||||
--- a/sysdeps/nptl/_Fork.c
|
||||
+++ b/sysdeps/nptl/_Fork.c
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <arch-fork.h>
|
||||
#include <pthreadP.h>
|
||||
+#include <getrandom-internal.h>
|
||||
|
||||
pid_t
|
||||
_Fork (void)
|
||||
@@ -43,6 +44,7 @@ _Fork (void)
|
||||
self->robust_head.list = &self->robust_head;
|
||||
INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
|
||||
sizeof (struct robust_list_head));
|
||||
+ call_function_static_weak (__getrandom_fork_subprocess);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
|
||||
index 7643926df9e3a22e..eabf3c81b0127b34 100644
|
||||
--- a/sysdeps/nptl/fork.h
|
||||
+++ b/sysdeps/nptl/fork.h
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <mqueue.h>
|
||||
#include <pthreadP.h>
|
||||
#include <sysdep.h>
|
||||
+#include <getrandom-internal.h>
|
||||
|
||||
static inline void
|
||||
fork_system_setup (void)
|
||||
@@ -46,6 +47,7 @@ fork_system_setup_after_fork (void)
|
||||
|
||||
call_function_static_weak (__mq_notify_fork_subprocess);
|
||||
call_function_static_weak (__timer_fork_subprocess);
|
||||
+ call_function_static_weak (__getrandom_fork_subprocess);
|
||||
}
|
||||
|
||||
/* In case of a fork() call the memory allocation in the child will be
|
||||
@@ -128,9 +130,19 @@ reclaim_stacks (void)
|
||||
curp->specific_used = true;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ call_function_static_weak (__getrandom_reset_state, curp);
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Also reset stale getrandom states for user stack threads. */
|
||||
+ list_for_each (runp, &GL (dl_stack_user))
|
||||
+ {
|
||||
+ struct pthread *curp = list_entry (runp, struct pthread, list);
|
||||
+ if (curp != self)
|
||||
+ call_function_static_weak (__getrandom_reset_state, curp);
|
||||
+ }
|
||||
+
|
||||
/* Add the stack of all running threads to the cache. */
|
||||
list_splice (&GL (dl_stack_used), &GL (dl_stack_cache));
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.h b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||||
index bbbe35723cac80ef..974b503b2f93511d 100644
|
||||
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||||
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||||
@@ -164,6 +164,7 @@
|
||||
# define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres"
|
||||
# define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime"
|
||||
# define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday"
|
||||
+# define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom"
|
||||
|
||||
# define HAVE_CLONE3_WRAPPER 1
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.c b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
|
||||
index 5dd7ed9d126feedc..9afde3d589199e7a 100644
|
||||
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.c
|
||||
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
|
||||
@@ -66,6 +66,11 @@ PROCINFO_CLASS int (*_dl_vdso_clock_getres) (clockid_t,
|
||||
PROCINFO_CLASS int (*_dl_vdso_clock_getres_time64) (clockid_t,
|
||||
struct __timespec64 *) RELRO;
|
||||
# endif
|
||||
+# ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+PROCINFO_CLASS ssize_t (*_dl_vdso_getrandom) (void *buffer, size_t len,
|
||||
+ unsigned int flags, void *state,
|
||||
+ size_t state_len) RELRO;
|
||||
+# endif
|
||||
|
||||
/* PowerPC specific ones. */
|
||||
# ifdef HAVE_GET_TBFREQ
|
||||
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.h b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
|
||||
index e87d88694098588e..e8faeaef7d2c127a 100644
|
||||
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.h
|
||||
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
|
||||
@@ -47,6 +47,9 @@ setup_vdso_pointers (void)
|
||||
#ifdef HAVE_GET_TBFREQ
|
||||
GLRO(dl_vdso_get_tbfreq) = dl_vdso_vsym (HAVE_GET_TBFREQ);
|
||||
#endif
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ GLRO(dl_vdso_getrandom) = dl_vdso_vsym (HAVE_GETRANDOM_VSYSCALL);
|
||||
+#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
diff --git a/sysdeps/unix/sysv/linux/getrandom-internal.h b/sysdeps/unix/sysv/linux/getrandom-internal.h
|
||||
new file mode 100644
|
||||
index 0000000000000000..37e6c9bc150ba061
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/getrandom-internal.h
|
||||
@@ -0,0 +1,29 @@
|
||||
+/* Internal definitions for Linux getrandom implementation.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 _GETRANDOM_INTERNAL_H
|
||||
+#define _GETRANDOM_INTERNAL_H
|
||||
+
|
||||
+#include <pthreadP.h>
|
||||
+
|
||||
+extern void __getrandom_early_init (_Bool) attribute_hidden;
|
||||
+
|
||||
+extern void __getrandom_fork_subprocess (void) attribute_hidden;
|
||||
+extern void __getrandom_vdso_release (struct pthread *curp) attribute_hidden;
|
||||
+extern void __getrandom_reset_state (struct pthread *curp) attribute_hidden;
|
||||
+#endif
|
||||
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
|
||||
index 777d1decf0fa50ea..c8c578263da456b2 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getrandom.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getrandom.c
|
||||
@@ -21,12 +21,314 @@
|
||||
#include <unistd.h>
|
||||
#include <sysdep-cancel.h>
|
||||
|
||||
+static inline ssize_t
|
||||
+getrandom_syscall (void *buffer, size_t length, unsigned int flags,
|
||||
+ bool cancel)
|
||||
+{
|
||||
+ return cancel
|
||||
+ ? SYSCALL_CANCEL (getrandom, buffer, length, flags)
|
||||
+ : INLINE_SYSCALL_CALL (getrandom, buffer, length, flags);
|
||||
+}
|
||||
+
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+# include <assert.h>
|
||||
+# include <ldsodefs.h>
|
||||
+# include <libc-lock.h>
|
||||
+# include <list.h>
|
||||
+# include <setvmaname.h>
|
||||
+# include <sys/mman.h>
|
||||
+# include <sys/sysinfo.h>
|
||||
+# include <tls-internal.h>
|
||||
+
|
||||
+/* These values will be initialized at loading time by calling the
|
||||
+ _dl_vdso_getrandom with a special value. The 'state_size' is the opaque
|
||||
+ state size per-thread allocated with a mmap using 'mmap_prot' and
|
||||
+ 'mmap_flags' argument. */
|
||||
+static uint32_t state_size;
|
||||
+static uint32_t state_size_cache_aligned;
|
||||
+static uint32_t mmap_prot;
|
||||
+static uint32_t mmap_flags;
|
||||
+
|
||||
+/* The function below are used on reentracy handling with (i.e. SA_NODEFER).
|
||||
+ Before allocating a new state or issue the vDSO, atomically read the
|
||||
+ current thread buffer, and if this is already reserved (is_reserved_ptr)
|
||||
+ fallback to the syscall. Otherwise, reserve the buffer by atomically
|
||||
+ setting the LSB of the opaque state pointer. The bit is cleared after the
|
||||
+ vDSO is called, or before issuing the fallback syscall. */
|
||||
+
|
||||
+static inline void *reserve_ptr (void *p)
|
||||
+{
|
||||
+ return (void *) ((uintptr_t) (p) | 1UL);
|
||||
+}
|
||||
+
|
||||
+static inline void *release_ptr (void *p)
|
||||
+{
|
||||
+ return (void *) ((uintptr_t) (p) & ~1UL);
|
||||
+}
|
||||
+
|
||||
+static inline bool is_reserved_ptr (void *p)
|
||||
+{
|
||||
+ return (uintptr_t) (p) & 1UL;
|
||||
+}
|
||||
+
|
||||
+static struct
|
||||
+{
|
||||
+ __libc_lock_define (, lock);
|
||||
+
|
||||
+ void **states; /* Queue of opaque states allocated with the kernel
|
||||
+ provided flags and used on getrandom vDSO call. */
|
||||
+ size_t len; /* Number of available free states in the queue. */
|
||||
+ size_t total; /* Number of states allocated from the kernel. */
|
||||
+ size_t cap; /* Total number of states that 'states' can hold before
|
||||
+ needed to be resized. */
|
||||
+} grnd_alloc = {
|
||||
+ .lock = LLL_LOCK_INITIALIZER
|
||||
+};
|
||||
+
|
||||
+static bool
|
||||
+vgetrandom_get_state_alloc (void)
|
||||
+{
|
||||
+ /* Start by allocating one page for the opaque states. */
|
||||
+ size_t block_size = ALIGN_UP (state_size_cache_aligned, GLRO(dl_pagesize));
|
||||
+ size_t states_per_page = GLRO (dl_pagesize) / state_size_cache_aligned;
|
||||
+ void *block = __mmap (NULL, GLRO(dl_pagesize), mmap_prot, mmap_flags, -1, 0);
|
||||
+ if (block == MAP_FAILED)
|
||||
+ return false;
|
||||
+ __set_vma_name (block, block_size, " glibc: getrandom");
|
||||
+
|
||||
+ if (grnd_alloc.total + states_per_page > grnd_alloc.cap)
|
||||
+ {
|
||||
+ /* Use a new mmap instead of trying to mremap. It avoids a
|
||||
+ potential multithread fork issue where fork is called just after
|
||||
+ mremap returns but before assigning to the grnd_alloc.states,
|
||||
+ thus making the its value invalid in the child. */
|
||||
+ void *old_states = grnd_alloc.states;
|
||||
+ size_t new_states_size = ALIGN_UP ((grnd_alloc.total + states_per_page)
|
||||
+ * sizeof (*grnd_alloc.states),
|
||||
+ GLRO(dl_pagesize));
|
||||
+
|
||||
+ /* There is no need to memcpy any opaque state information because
|
||||
+ all the allocated opaque states are assigned to running threads
|
||||
+ (meaning that if we iterate over them we can reconstruct the state
|
||||
+ list). */
|
||||
+ void **states = __mmap (NULL, new_states_size, PROT_READ | PROT_WRITE,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
+ if (states == MAP_FAILED)
|
||||
+ {
|
||||
+ __munmap (block, block_size);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Atomically replace the old state, so if a fork happens the child
|
||||
+ process will see a consistent free state buffer. The size might
|
||||
+ not be updated, but it does not really matter since the buffer is
|
||||
+ always increased. */
|
||||
+ grnd_alloc.states = states;
|
||||
+ atomic_thread_fence_seq_cst ();
|
||||
+ if (old_states != NULL)
|
||||
+ __munmap (old_states, grnd_alloc.cap * sizeof (*grnd_alloc.states));
|
||||
+
|
||||
+ __set_vma_name (states, new_states_size, " glibc: getrandom states");
|
||||
+ grnd_alloc.cap = new_states_size / sizeof (*grnd_alloc.states);
|
||||
+ atomic_thread_fence_seq_cst ();
|
||||
+ }
|
||||
+
|
||||
+ for (size_t i = 0; i < states_per_page; ++i)
|
||||
+ {
|
||||
+ /* There is no need to handle states that straddle a page because
|
||||
+ we allocate only one page. */
|
||||
+ grnd_alloc.states[i] = block;
|
||||
+ block += state_size_cache_aligned;
|
||||
+ }
|
||||
+ /* Concurrent fork should not observe the previous pointer value. */
|
||||
+ grnd_alloc.len = states_per_page;
|
||||
+ grnd_alloc.total += states_per_page;
|
||||
+ atomic_thread_fence_seq_cst ();
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+/* Allocate an opaque state for vgetrandom. If the grnd_alloc does not have
|
||||
+ any, mmap() another page of them using the vgetrandom parameters. */
|
||||
+static void *
|
||||
+vgetrandom_get_state (void)
|
||||
+{
|
||||
+ void *state = NULL;
|
||||
+
|
||||
+ /* The signal blocking avoid the potential issue where _Fork() (which is
|
||||
+ async-signal-safe) is called with the lock taken. The function is
|
||||
+ called only once during thread lifetime, so the overhead should be
|
||||
+ minimal. */
|
||||
+ internal_sigset_t set;
|
||||
+ internal_signal_block_all (&set);
|
||||
+ __libc_lock_lock (grnd_alloc.lock);
|
||||
+
|
||||
+ if (grnd_alloc.len > 0 || vgetrandom_get_state_alloc ())
|
||||
+ state = grnd_alloc.states[--grnd_alloc.len];
|
||||
+
|
||||
+ __libc_lock_unlock (grnd_alloc.lock);
|
||||
+ internal_signal_restore_set (&set);
|
||||
+
|
||||
+ return state;
|
||||
+}
|
||||
+
|
||||
+/* Returns true when vgetrandom is used successfully. Returns false if the
|
||||
+ syscall fallback should be issued in the case the vDSO is not present, in
|
||||
+ the case of reentrancy, or if any memory allocation fails. */
|
||||
+static ssize_t
|
||||
+getrandom_vdso (void *buffer, size_t length, unsigned int flags, bool cancel)
|
||||
+{
|
||||
+ if (__glibc_unlikely (state_size == 0))
|
||||
+ return getrandom_syscall (buffer, length, flags, cancel);
|
||||
+
|
||||
+ struct pthread *self = THREAD_SELF;
|
||||
+
|
||||
+ void *state = atomic_load_relaxed (&self->getrandom_buf);
|
||||
+ if (is_reserved_ptr (state))
|
||||
+ return getrandom_syscall (buffer, length, flags, cancel);
|
||||
+ atomic_store_relaxed (&self->getrandom_buf, reserve_ptr (state));
|
||||
+ __atomic_signal_fence (__ATOMIC_ACQ_REL);
|
||||
+
|
||||
+ bool r = false;
|
||||
+ if (state == NULL)
|
||||
+ {
|
||||
+ state = vgetrandom_get_state ();
|
||||
+ if (state == NULL)
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* Since the vDSO implementation does not issue the syscall with the
|
||||
+ cancellation bridge (__syscall_cancel_arch), use GRND_NONBLOCK so there
|
||||
+ is no potential unbounded blocking in the kernel. It should be a rare
|
||||
+ situation, only at system startup when RNG is not initialized. */
|
||||
+ ssize_t ret = GLRO (dl_vdso_getrandom) (buffer,
|
||||
+ length,
|
||||
+ flags | GRND_NONBLOCK,
|
||||
+ state,
|
||||
+ state_size);
|
||||
+ if (INTERNAL_SYSCALL_ERROR_P (ret))
|
||||
+ {
|
||||
+ /* Fallback to the syscall if the kernel would block. */
|
||||
+ int err = INTERNAL_SYSCALL_ERRNO (ret);
|
||||
+ if (err == EAGAIN && !(flags & GRND_NONBLOCK))
|
||||
+ goto out;
|
||||
+
|
||||
+ __set_errno (err);
|
||||
+ ret = -1;
|
||||
+ }
|
||||
+ r = true;
|
||||
+
|
||||
+out:
|
||||
+ __atomic_signal_fence (__ATOMIC_ACQ_REL);
|
||||
+ atomic_store_relaxed (&self->getrandom_buf, state);
|
||||
+ return r ? ret : getrandom_syscall (buffer, length, flags, cancel);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+void
|
||||
+__getrandom_early_init (_Bool initial)
|
||||
+{
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ /* libcs loaded for audit modules, dlmopen, etc. fallback to syscall. */
|
||||
+ if (initial && (GLRO (dl_vdso_getrandom) != NULL))
|
||||
+ {
|
||||
+ /* Used to query the vDSO for the required mmap flags and the opaque
|
||||
+ per-thread state size. Defined by linux/random.h. */
|
||||
+ struct vgetrandom_opaque_params
|
||||
+ {
|
||||
+ uint32_t size_of_opaque_state;
|
||||
+ uint32_t mmap_prot;
|
||||
+ uint32_t mmap_flags;
|
||||
+ uint32_t reserved[13];
|
||||
+ } params;
|
||||
+ if (GLRO(dl_vdso_getrandom) (NULL, 0, 0, ¶ms, ~0UL) == 0)
|
||||
+ {
|
||||
+ /* Align each opaque state to L1 data cache size to avoid false
|
||||
+ sharing. If the size can not be obtained, use the kernel
|
||||
+ provided one. */
|
||||
+ state_size = params.size_of_opaque_state;
|
||||
+
|
||||
+ long int ld1sz = __sysconf (_SC_LEVEL1_DCACHE_LINESIZE);
|
||||
+ if (ld1sz <= 0)
|
||||
+ ld1sz = 1;
|
||||
+ state_size_cache_aligned = ALIGN_UP (state_size, ld1sz);
|
||||
+ /* Do not enable vDSO if the required opaque state size is larger
|
||||
+ than a page because we only allocate one page per time to hold
|
||||
+ the states. */
|
||||
+ if (state_size_cache_aligned > GLRO(dl_pagesize))
|
||||
+ {
|
||||
+ state_size = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+ mmap_prot = params.mmap_prot;
|
||||
+ mmap_flags = params.mmap_flags;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+/* Re-add the state state from CURP on the free list. This function is
|
||||
+ called after fork returns in the child, so no locking is required. */
|
||||
+void
|
||||
+__getrandom_reset_state (struct pthread *curp)
|
||||
+{
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ if (grnd_alloc.states == NULL || curp->getrandom_buf == NULL)
|
||||
+ return;
|
||||
+ assert (grnd_alloc.len < grnd_alloc.cap);
|
||||
+ grnd_alloc.states[grnd_alloc.len++] = release_ptr (curp->getrandom_buf);
|
||||
+ curp->getrandom_buf = NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+/* Called when a thread terminates, and adds its random buffer back into the
|
||||
+ allocator pool for use in a future thread. This is called by
|
||||
+ pthread_create during thread termination, and after signal has been
|
||||
+ blocked. */
|
||||
+void
|
||||
+__getrandom_vdso_release (struct pthread *curp)
|
||||
+{
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ if (curp->getrandom_buf == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ __libc_lock_lock (grnd_alloc.lock);
|
||||
+ grnd_alloc.states[grnd_alloc.len++] = curp->getrandom_buf;
|
||||
+ __libc_lock_unlock (grnd_alloc.lock);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+/* Reset the internal lock state in case another thread has locked while
|
||||
+ this thread calls fork. The stale thread states will be handled by
|
||||
+ reclaim_stacks which calls __getrandom_reset_state on each thread. */
|
||||
+void
|
||||
+__getrandom_fork_subprocess (void)
|
||||
+{
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ grnd_alloc.lock = LLL_LOCK_INITIALIZER;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+ssize_t
|
||||
+__getrandom_nocancel (void *buffer, size_t length, unsigned int flags)
|
||||
+{
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ return getrandom_vdso (buffer, length, flags, false);
|
||||
+#else
|
||||
+ return getrandom_syscall (buffer, length, flags, false);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
/* Write up to LENGTH bytes of randomness starting at BUFFER.
|
||||
Return the number of bytes written, or -1 on error. */
|
||||
ssize_t
|
||||
__getrandom (void *buffer, size_t length, unsigned int flags)
|
||||
{
|
||||
- return SYSCALL_CANCEL (getrandom, buffer, length, flags);
|
||||
+#ifdef HAVE_GETRANDOM_VSYSCALL
|
||||
+ return getrandom_vdso (buffer, length, flags, true);
|
||||
+#else
|
||||
+ return getrandom_syscall (buffer, length, flags, true);
|
||||
+#endif
|
||||
}
|
||||
libc_hidden_def (__getrandom)
|
||||
weak_alias (__getrandom, getrandom)
|
||||
diff --git a/sysdeps/unix/sysv/linux/loongarch/sysdep.h b/sysdeps/unix/sysv/linux/loongarch/sysdep.h
|
||||
index eb0ba790daa6e27c..e2d853ae3e3c77fb 100644
|
||||
--- a/sysdeps/unix/sysv/linux/loongarch/sysdep.h
|
||||
+++ b/sysdeps/unix/sysv/linux/loongarch/sysdep.h
|
||||
@@ -119,6 +119,7 @@
|
||||
#define HAVE_CLOCK_GETTIME64_VSYSCALL "__vdso_clock_gettime"
|
||||
#define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday"
|
||||
#define HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
|
||||
+#define HAVE_GETRANDOM_VSYSCALL "__vdso_getrandom"
|
||||
|
||||
#define HAVE_CLONE3_WRAPPER 1
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
|
||||
index 2a7585b73f2b23f7..12f26912d3f03640 100644
|
||||
--- a/sysdeps/unix/sysv/linux/not-cancel.h
|
||||
+++ b/sysdeps/unix/sysv/linux/not-cancel.h
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
+#include <sys/random.h>
|
||||
|
||||
/* Non cancellable open syscall. */
|
||||
__typeof (open) __open_nocancel;
|
||||
@@ -84,15 +85,17 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
|
||||
}
|
||||
|
||||
static inline ssize_t
|
||||
-__getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
|
||||
+__getrandom_nocancel_direct (void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags);
|
||||
}
|
||||
|
||||
+__typeof (getrandom) __getrandom_nocancel attribute_hidden;
|
||||
+
|
||||
/* Non cancellable getrandom syscall that does not also set errno in case of
|
||||
failure. */
|
||||
static inline ssize_t
|
||||
-__getrandom_nocancel_nostatus (void *buf, size_t buflen, unsigned int flags)
|
||||
+__getrandom_nocancel_nostatus_direct (void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
return INTERNAL_SYSCALL_CALL (getrandom, buf, buflen, flags);
|
||||
}
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/sysdep.h
|
||||
index a69b7db33843d488..48f3d0d1b2c271cf 100644
|
||||
--- a/sysdeps/unix/sysv/linux/powerpc/sysdep.h
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.h
|
||||
@@ -223,5 +223,6 @@
|
||||
#define HAVE_TIME_VSYSCALL "__kernel_time"
|
||||
#define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday"
|
||||
#define HAVE_GET_TBFREQ "__kernel_get_tbfreq"
|
||||
+#define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom"
|
||||
|
||||
#endif /* _LINUX_POWERPC_SYSDEP_H */
|
||||
diff --git a/sysdeps/unix/sysv/linux/s390/sysdep.h b/sysdeps/unix/sysv/linux/s390/sysdep.h
|
||||
index 9b3000ca62a0e00d..9698c57a03d19607 100644
|
||||
--- a/sysdeps/unix/sysv/linux/s390/sysdep.h
|
||||
+++ b/sysdeps/unix/sysv/linux/s390/sysdep.h
|
||||
@@ -72,6 +72,7 @@
|
||||
#ifdef __s390x__
|
||||
#define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres"
|
||||
#define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime"
|
||||
+#define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom"
|
||||
#else
|
||||
#define HAVE_CLOCK_GETRES_VSYSCALL "__kernel_clock_getres"
|
||||
#define HAVE_CLOCK_GETTIME_VSYSCALL "__kernel_clock_gettime"
|
||||
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
|
||||
index a2b021bd86f5d472..7dc072ae2da8f7c3 100644
|
||||
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
|
||||
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
|
||||
@@ -376,6 +376,7 @@
|
||||
# define HAVE_TIME_VSYSCALL "__vdso_time"
|
||||
# define HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
|
||||
# define HAVE_CLOCK_GETRES64_VSYSCALL "__vdso_clock_getres"
|
||||
+# define HAVE_GETRANDOM_VSYSCALL "__vdso_getrandom"
|
||||
|
||||
# define HAVE_CLONE3_WRAPPER 1
|
||||
|
@ -0,0 +1,28 @@
|
||||
commit 734e7f91e752f44984fe42c2384c23a0290b6e56
|
||||
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
Date: Tue Aug 20 16:22:07 2024 +0200
|
||||
|
||||
Rules: Also build memcheck tests even when not running them
|
||||
|
||||
This will avoid in the future cases like a57cbbd85379 ("malloc: Link
|
||||
threading tests with $(shared-thread-library") missing the memcheck
|
||||
cases added in 251843e16fce ("malloc: Link threading tests with
|
||||
$(shared-thread-library)")
|
||||
|
||||
diff --git a/Rules b/Rules
|
||||
index 9010c5d5b269a805..27846abf82b65f60 100644
|
||||
--- a/Rules
|
||||
+++ b/Rules
|
||||
@@ -145,7 +145,11 @@ others: $(py-const)
|
||||
ifeq ($(run-built-tests),no)
|
||||
tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
|
||||
$(tests) $(tests-internal) \
|
||||
- $(tests-container)) \
|
||||
+ $(tests-container) \
|
||||
+ $(tests-mcheck:%=%-mcheck) \
|
||||
+ $(tests-malloc-check:%=%-malloc-check) \
|
||||
+ $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \
|
||||
+ $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2)) \
|
||||
$(test-srcs)) $(tests-special) \
|
||||
$(tests-printers-programs)
|
||||
xtests: tests $(xtests-special)
|
@ -0,0 +1,82 @@
|
||||
commit d5a3ca4061f7adc59196fa58e34eacebbebcbcfe
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Sep 19 15:40:05 2024 +0200
|
||||
|
||||
Implement run-built-tests=no for make xcheck, always build xtests
|
||||
|
||||
Previously, the second occurrence of the xtests target
|
||||
expected all xtests to run (as the result of specifying
|
||||
$(xtests)), but these tests have not been run due to
|
||||
the the first xtests target is set up for run-built-tests=no:
|
||||
it only runs tests in $(xtests-special). Consequently,
|
||||
xtests are reported as UNSUPPORTED with “make xcheck
|
||||
run-built-tests=no”. The xtests were not built, either.
|
||||
|
||||
After this change always, xtests are built regardless
|
||||
of the $(run-built-tests) variable (except for xtests listed
|
||||
in $(tests-unsupported)). To fix the UNSUPPORTED issue,
|
||||
introduce xtests-expected and use that manage test
|
||||
expectations in the second xtests target.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/Rules b/Rules
|
||||
index 27846abf82b65f60..713c225d2ebf5506 100644
|
||||
--- a/Rules
|
||||
+++ b/Rules
|
||||
@@ -143,8 +143,9 @@ endif
|
||||
others: $(py-const)
|
||||
|
||||
ifeq ($(run-built-tests),no)
|
||||
+# The $(xtests) dependency ensures that xtests are always built.
|
||||
tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
|
||||
- $(tests) $(tests-internal) \
|
||||
+ $(tests) $(tests-internal) $(xtests) \
|
||||
$(tests-container) \
|
||||
$(tests-mcheck:%=%-mcheck) \
|
||||
$(tests-malloc-check:%=%-malloc-check) \
|
||||
@@ -153,8 +154,10 @@ tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
|
||||
$(test-srcs)) $(tests-special) \
|
||||
$(tests-printers-programs)
|
||||
xtests: tests $(xtests-special)
|
||||
-else
|
||||
+else # $(run-built-tests) != no
|
||||
+# The $(xtests) dependency ensures that xtests are always built.
|
||||
tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
|
||||
+ $(addprefix $(objpfx),$(filter-out $(tests-unsupported), $(xtests))) \
|
||||
$(tests-container:%=$(objpfx)%.out) \
|
||||
$(tests-mcheck:%=$(objpfx)%-mcheck.out) \
|
||||
$(tests-malloc-check:%=$(objpfx)%-malloc-check.out) \
|
||||
@@ -162,26 +165,28 @@ tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
|
||||
$(tests-malloc-hugetlb2:%=$(objpfx)%-malloc-hugetlb2.out) \
|
||||
$(tests-special) $(tests-printers-out)
|
||||
xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special)
|
||||
-endif
|
||||
+endif # $(run-built-tests) != no
|
||||
|
||||
tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
|
||||
xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special))
|
||||
ifeq ($(run-built-tests),no)
|
||||
tests-expected =
|
||||
-else
|
||||
+xtests-expected =
|
||||
+else # $(run-built-tests) != no
|
||||
tests-expected = $(tests) $(tests-internal) $(tests-printers) \
|
||||
$(tests-container) $(tests-malloc-check:%=%-malloc-check) \
|
||||
$(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \
|
||||
$(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) \
|
||||
$(tests-mcheck:%=%-mcheck)
|
||||
-endif
|
||||
+xtests-expected = $(xtests)
|
||||
+endif # $(run-built-tests) != no
|
||||
tests:
|
||||
$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
|
||||
$(sort $(tests-expected) $(tests-special-notdir:.out=)) \
|
||||
> $(objpfx)subdir-tests.sum
|
||||
xtests:
|
||||
$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
|
||||
- $(sort $(xtests) $(xtests-special-notdir:.out=)) \
|
||||
+ $(sort $(xtests-expected) $(xtests-special-notdir:.out=)) \
|
||||
> $(objpfx)subdir-xtests.sum
|
||||
|
||||
ifeq ($(build-programs),yes)
|
@ -0,0 +1,29 @@
|
||||
commit 5a5eb72d8ee4783c28fead080143d53cac993e1d
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Aug 1 10:46:10 2024 +0200
|
||||
|
||||
resolv: Fix tst-resolv-short-response for older GCC (bug 32042)
|
||||
|
||||
Previous GCC versions do not support the C23 change that
|
||||
allows labels on declarations.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit ec119972cb2598c04ec7d4219e20506006836f64)
|
||||
|
||||
diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c
|
||||
index be354ae1c7f2a81a..9b06b0c1762f860c 100644
|
||||
--- a/resolv/tst-resolv-short-response.c
|
||||
+++ b/resolv/tst-resolv-short-response.c
|
||||
@@ -33,8 +33,10 @@ response (const struct resolv_response_context *ctx,
|
||||
{
|
||||
case 0:
|
||||
/* First server times out. */
|
||||
- struct resolv_response_flags flags = {.rcode = rcode};
|
||||
- resolv_response_init (b, flags);
|
||||
+ {
|
||||
+ struct resolv_response_flags flags = {.rcode = rcode};
|
||||
+ resolv_response_init (b, flags);
|
||||
+ }
|
||||
break;
|
||||
case 1:
|
||||
/* Second server sends reply. */
|
@ -0,0 +1,277 @@
|
||||
commit afc15c2044cb9449ba506fe910fa8ab77394833c
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Mon Aug 5 10:55:51 2024 +0200
|
||||
|
||||
Fix name space violation in fortify wrappers (bug 32052)
|
||||
|
||||
Rename the identifier sz to __sz everywhere.
|
||||
|
||||
Fixes: a643f60c53 ("Make sure that the fortified function conditionals are constant")
|
||||
(cherry picked from commit 39ca997ab378990d5ac1aadbaa52aaf1db6d526f)
|
||||
(redone from scratch because of many conflicts)
|
||||
|
||||
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
|
||||
index f9e8d37610d720aa..0dc4e87c652471f6 100644
|
||||
--- a/libio/bits/stdio2.h
|
||||
+++ b/libio/bits/stdio2.h
|
||||
@@ -195,24 +195,24 @@ __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2)
|
||||
__nonnull ((3)) char *
|
||||
fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __fgets_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __fgets_chk_warn (__s, sz, __n, __stream);
|
||||
- return __fgets_chk (__s, sz, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __fgets_chk_warn (__s, __sz, __n, __stream);
|
||||
+ return __fgets_chk (__s, __sz, __n, __stream);
|
||||
}
|
||||
|
||||
__fortify_function __wur __nonnull ((4)) size_t
|
||||
fread (void *__restrict __ptr, size_t __size, size_t __n,
|
||||
FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__ptr);
|
||||
- if (__glibc_safe_or_unknown_len (__n, __size, sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__ptr);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, __size, __sz))
|
||||
return __fread_alias (__ptr, __size, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, __size, sz))
|
||||
- return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
|
||||
- return __fread_chk (__ptr, sz, __size, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, __size, __sz))
|
||||
+ return __fread_chk_warn (__ptr, __sz, __size, __n, __stream);
|
||||
+ return __fread_chk (__ptr, __sz, __size, __n, __stream);
|
||||
}
|
||||
|
||||
#ifdef __USE_GNU
|
||||
@@ -220,12 +220,12 @@ __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2)
|
||||
__nonnull ((3)) char *
|
||||
fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __fgets_unlocked_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
|
||||
- return __fgets_unlocked_chk (__s, sz, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __fgets_unlocked_chk_warn (__s, __sz, __n, __stream);
|
||||
+ return __fgets_unlocked_chk (__s, __sz, __n, __stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -235,8 +235,8 @@ __fortify_function __wur __nonnull ((4)) size_t
|
||||
fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
|
||||
FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__ptr);
|
||||
- if (__glibc_safe_or_unknown_len (__n, __size, sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__ptr);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, __size, __sz))
|
||||
{
|
||||
# ifdef __USE_EXTERN_INLINES
|
||||
if (__builtin_constant_p (__size)
|
||||
@@ -261,9 +261,9 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
|
||||
# endif
|
||||
return __fread_unlocked_alias (__ptr, __size, __n, __stream);
|
||||
}
|
||||
- if (__glibc_unsafe_len (__n, __size, sz))
|
||||
- return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
|
||||
- return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, __size, __sz))
|
||||
+ return __fread_unlocked_chk_warn (__ptr, __sz, __size, __n, __stream);
|
||||
+ return __fread_unlocked_chk (__ptr, __sz, __size, __n, __stream);
|
||||
|
||||
}
|
||||
#endif
|
||||
diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
|
||||
index a88cb643703a4008..71f8d9c741049afd 100644
|
||||
--- a/socket/bits/socket2.h
|
||||
+++ b/socket/bits/socket2.h
|
||||
@@ -33,12 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
|
||||
__fortify_function ssize_t
|
||||
recv (int __fd, void *__buf, size_t __n, int __flags)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__buf);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__buf);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __recv_alias (__fd, __buf, __n, __flags);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __recv_chk_warn (__fd, __buf, __n, sz, __flags);
|
||||
- return __recv_chk (__fd, __buf, __n, sz, __flags);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __recv_chk_warn (__fd, __buf, __n, __sz, __flags);
|
||||
+ return __recv_chk (__fd, __buf, __n, __sz, __flags);
|
||||
}
|
||||
|
||||
extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
|
||||
@@ -61,11 +61,11 @@ __fortify_function ssize_t
|
||||
recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
|
||||
__SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
|
||||
{
|
||||
- size_t sz = __glibc_objsize0 (__buf);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
|
||||
+ size_t __sz = __glibc_objsize0 (__buf);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
|
||||
return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
|
||||
- return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr,
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
|
||||
+ return __recvfrom_chk_warn (__fd, __buf, __n, __sz, __flags, __addr,
|
||||
__addr_len);
|
||||
- return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
|
||||
+ return __recvfrom_chk (__fd, __buf, __n, __sz, __flags, __addr, __addr_len);
|
||||
}
|
||||
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
|
||||
index 1c7191ba574946ef..32f7ef5020eadc4c 100644
|
||||
--- a/stdlib/bits/stdlib.h
|
||||
+++ b/stdlib/bits/stdlib.h
|
||||
@@ -36,16 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
|
||||
__fortify_function __wur char *
|
||||
__NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__resolved);
|
||||
+ size_t __sz = __glibc_objsize (__resolved);
|
||||
|
||||
- if (sz == (size_t) -1)
|
||||
+ if (__sz == (size_t) -1)
|
||||
return __realpath_alias (__name, __resolved);
|
||||
|
||||
#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
|
||||
- if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
|
||||
- return __realpath_chk_warn (__name, __resolved, sz);
|
||||
+ if (__glibc_unsafe_len (PATH_MAX, sizeof (char), __sz))
|
||||
+ return __realpath_chk_warn (__name, __resolved, __sz);
|
||||
#endif
|
||||
- return __realpath_chk (__name, __resolved, sz);
|
||||
+ return __realpath_chk (__name, __resolved, __sz);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
|
||||
index 49f19bca194fd601..c863b60ec203495e 100644
|
||||
--- a/wcsmbs/bits/wchar2.h
|
||||
+++ b/wcsmbs/bits/wchar2.h
|
||||
@@ -59,18 +59,18 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
|
||||
__fortify_function wchar_t *
|
||||
__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcscpy_chk (__dest, __src, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcscpy_chk (__dest, __src, __sz / sizeof (wchar_t));
|
||||
return __wcscpy_alias (__dest, __src);
|
||||
}
|
||||
|
||||
__fortify_function wchar_t *
|
||||
__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcpcpy_chk (__dest, __src, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcpcpy_chk (__dest, __src, __sz / sizeof (wchar_t));
|
||||
return __wcpcpy_alias (__dest, __src);
|
||||
}
|
||||
|
||||
@@ -95,9 +95,9 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
|
||||
__fortify_function wchar_t *
|
||||
__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcscat_chk (__dest, __src, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcscat_chk (__dest, __src, __sz / sizeof (wchar_t));
|
||||
return __wcscat_alias (__dest, __src);
|
||||
}
|
||||
|
||||
@@ -105,9 +105,9 @@ __fortify_function wchar_t *
|
||||
__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
|
||||
size_t __n))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__dest);
|
||||
- if (sz != (size_t) -1)
|
||||
- return __wcsncat_chk (__dest, __src, __n, sz / sizeof (wchar_t));
|
||||
+ size_t __sz = __glibc_objsize (__dest);
|
||||
+ if (__sz != (size_t) -1)
|
||||
+ return __wcsncat_chk (__dest, __src, __n, __sz / sizeof (wchar_t));
|
||||
return __wcsncat_alias (__dest, __src, __n);
|
||||
}
|
||||
|
||||
@@ -144,10 +144,10 @@ __fortify_function int
|
||||
__NTH (swprintf (wchar_t *__restrict __s, size_t __n,
|
||||
const wchar_t *__restrict __fmt, ...))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
|
||||
- sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
|
||||
+ __sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
|
||||
return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
|
||||
}
|
||||
#elif !defined __cplusplus
|
||||
@@ -163,10 +163,10 @@ __fortify_function int
|
||||
__NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
|
||||
const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
|
||||
return __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
|
||||
- sz / sizeof (wchar_t), __fmt, __ap);
|
||||
+ __sz / sizeof (wchar_t), __fmt, __ap);
|
||||
return __vswprintf_alias (__s, __n, __fmt, __ap);
|
||||
}
|
||||
|
||||
@@ -210,25 +210,25 @@ vfwprintf (__FILE *__restrict __stream,
|
||||
__fortify_function __wur wchar_t *
|
||||
fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
|
||||
return __fgetws_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
|
||||
- return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
|
||||
- return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
|
||||
+ return __fgetws_chk_warn (__s, __sz / sizeof (wchar_t), __n, __stream);
|
||||
+ return __fgetws_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
|
||||
}
|
||||
|
||||
#ifdef __USE_GNU
|
||||
__fortify_function __wur wchar_t *
|
||||
fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
|
||||
{
|
||||
- size_t sz = __glibc_objsize (__s);
|
||||
- if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
|
||||
+ size_t __sz = __glibc_objsize (__s);
|
||||
+ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
|
||||
return __fgetws_unlocked_alias (__s, __n, __stream);
|
||||
- if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
|
||||
- return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
|
||||
+ if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
|
||||
+ return __fgetws_unlocked_chk_warn (__s, __sz / sizeof (wchar_t), __n,
|
||||
__stream);
|
||||
- return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
|
||||
+ return __fgetws_unlocked_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
|
||||
}
|
||||
#endif
|
||||
|
@ -0,0 +1,73 @@
|
||||
commit 6eebc92cb290bed20dfb5726a88bafa02f6a2ba7
|
||||
Author: Arjun Shankar <arjun@redhat.com>
|
||||
Date: Tue Jul 30 11:37:57 2024 +0200
|
||||
|
||||
manual/stdio: Further clarify putc, putwc, getc, and getwc
|
||||
|
||||
This is a follow-up to 10de4a47ef3f481592e3c62eb07bcda23e9fde4d that
|
||||
reworded the manual entries for putc and putwc and removed any
|
||||
performance claims.
|
||||
|
||||
This commit further clarifies these entries and brings getc and getwc in
|
||||
line with the descriptions of putc and putwc, removing any performance
|
||||
claims from them as well.
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
(cherry picked from commit 942670c81dc8071dd75d6213e771daa5d2084cb6)
|
||||
|
||||
diff --git a/manual/stdio.texi b/manual/stdio.texi
|
||||
index c11d37b363385531..0b31aeff958528c6 100644
|
||||
--- a/manual/stdio.texi
|
||||
+++ b/manual/stdio.texi
|
||||
@@ -904,20 +904,16 @@ This function is a GNU extension.
|
||||
@standards{ISO, stdio.h}
|
||||
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{} @aculock{}}}
|
||||
This is just like @code{fputc}, except that it may be implemented as
|
||||
-a macro, making it faster. One consequence is that it may evaluate the
|
||||
-@var{stream} argument more than once, which is an exception to the
|
||||
-general rule for macros. Therefore, @var{stream} should never be an
|
||||
-expression with side-effects.
|
||||
+a macro and may evaluate the @var{stream} argument more than once.
|
||||
+Therefore, @var{stream} should never be an expression with side-effects.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun wint_t putwc (wchar_t @var{wc}, FILE *@var{stream})
|
||||
@standards{ISO, wchar.h}
|
||||
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{} @aculock{}}}
|
||||
This is just like @code{fputwc}, except that it may be implemented as
|
||||
-a macro, making it faster. One consequence is that it may evaluate the
|
||||
-@var{stream} argument more than once, which is an exception to the
|
||||
-general rule for macros. Therefore, @var{stream} should never be an
|
||||
-expression with side-effects.
|
||||
+a macro and may evaluate the @var{stream} argument more than once.
|
||||
+Therefore, @var{stream} should never be an expression with side-effects.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun int putc_unlocked (int @var{c}, FILE *@var{stream})
|
||||
@@ -1110,20 +1106,17 @@ This function is a GNU extension.
|
||||
@deftypefun int getc (FILE *@var{stream})
|
||||
@standards{ISO, stdio.h}
|
||||
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}}
|
||||
-This is just like @code{fgetc}, except that it is permissible (and
|
||||
-typical) for it to be implemented as a macro that evaluates the
|
||||
-@var{stream} argument more than once. @code{getc} is often highly
|
||||
-optimized, so it is usually the best function to use to read a single
|
||||
-character.
|
||||
+This is just like @code{fgetc}, except that it may be implemented as
|
||||
+a macro and may evaluate the @var{stream} argument more than once.
|
||||
+Therefore, @var{stream} should never be an expression with side-effects.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun wint_t getwc (FILE *@var{stream})
|
||||
@standards{ISO, wchar.h}
|
||||
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}}
|
||||
-This is just like @code{fgetwc}, except that it is permissible for it to
|
||||
-be implemented as a macro that evaluates the @var{stream} argument more
|
||||
-than once. @code{getwc} can be highly optimized, so it is usually the
|
||||
-best function to use to read a single wide character.
|
||||
+This is just like @code{fgetwc}, except that it may be implemented as
|
||||
+a macro and may evaluate the @var{stream} argument more than once.
|
||||
+Therefore, @var{stream} should never be an expression with side-effects.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun int getc_unlocked (FILE *@var{stream})
|
@ -0,0 +1,23 @@
|
||||
commit 1ab7faf86db2f6ebe76e6e077cc7899cd9edc518
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Aug 9 17:01:17 2024 +0200
|
||||
|
||||
support: Add options list terminator to the test driver
|
||||
|
||||
This avoids crashes if a test is passed unknown options.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit c2a474f4617ede7a8bf56b7257acb37dc757b2d1)
|
||||
|
||||
diff --git a/support/test-driver.c b/support/test-driver.c
|
||||
index f4c3e4d666918270..04ceebc08f320b8b 100644
|
||||
--- a/support/test-driver.c
|
||||
+++ b/support/test-driver.c
|
||||
@@ -155,6 +155,7 @@ main (int argc, char **argv)
|
||||
{
|
||||
CMDLINE_OPTIONS
|
||||
TEST_DEFAULT_OPTIONS
|
||||
+ { 0, }
|
||||
};
|
||||
test_config.options = &options;
|
||||
#endif
|
@ -0,0 +1,174 @@
|
||||
commit eeff407b196f2ffaadb5d41142688482e4a2a761
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Mon Jul 22 17:47:21 2024 -0700
|
||||
|
||||
x86-64: Remove sysdeps/x86_64/x32/dl-machine.h
|
||||
|
||||
Remove sysdeps/x86_64/x32/dl-machine.h by folding x32 ARCH_LA_PLTENTER,
|
||||
ARCH_LA_PLTEXIT and RTLD_START into sysdeps/x86_64/dl-machine.h. There
|
||||
are no regressions on x86-64 nor x32. There are no changes in x86-64
|
||||
_dl_start_user. On x32, _dl_start_user changes are
|
||||
|
||||
<_dl_start_user>:
|
||||
mov %eax,%r12d
|
||||
+ mov %esp,%r13d
|
||||
mov (%rsp),%edx
|
||||
mov %edx,%esi
|
||||
- mov %esp,%r13d
|
||||
and $0xfffffff0,%esp
|
||||
mov 0x0(%rip),%edi # <_dl_start_user+0x14>
|
||||
lea 0x8(%r13,%rdx,4),%ecx
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||
(cherry picked from commit 652c6cf26927352fc0e37e4e60c6fc98ddf6d3b4)
|
||||
|
||||
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
|
||||
index ff5d45f7cb7cd81d..899f56576f245a3f 100644
|
||||
--- a/sysdeps/x86_64/dl-machine.h
|
||||
+++ b/sysdeps/x86_64/dl-machine.h
|
||||
@@ -139,37 +139,37 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
|
||||
.globl _start\n\
|
||||
.globl _dl_start_user\n\
|
||||
_start:\n\
|
||||
- movq %rsp, %rdi\n\
|
||||
+ mov %" RSP_LP ", %" RDI_LP "\n\
|
||||
call _dl_start\n\
|
||||
_dl_start_user:\n\
|
||||
# Save the user entry point address in %r12.\n\
|
||||
- movq %rax, %r12\n\
|
||||
+ mov %" RAX_LP ", %" R12_LP "\n\
|
||||
# Save %rsp value in %r13.\n\
|
||||
- movq %rsp, %r13\n\
|
||||
+ mov %" RSP_LP ", % " R13_LP "\n\
|
||||
"\
|
||||
RTLD_START_ENABLE_X86_FEATURES \
|
||||
"\
|
||||
# Read the original argument count.\n\
|
||||
- movq (%rsp), %rdx\n\
|
||||
+ mov (%rsp), %" RDX_LP "\n\
|
||||
# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
|
||||
# argc -> rsi\n\
|
||||
- movq %rdx, %rsi\n\
|
||||
+ mov %" RDX_LP ", %" RSI_LP "\n\
|
||||
# And align stack for the _dl_init call. \n\
|
||||
- andq $-16, %rsp\n\
|
||||
+ and $-16, %" RSP_LP "\n\
|
||||
# _dl_loaded -> rdi\n\
|
||||
- movq _rtld_local(%rip), %rdi\n\
|
||||
+ mov _rtld_local(%rip), %" RDI_LP "\n\
|
||||
# env -> rcx\n\
|
||||
- leaq 16(%r13,%rdx,8), %rcx\n\
|
||||
+ lea 2*" LP_SIZE "(%r13,%rdx," LP_SIZE "), %" RCX_LP "\n\
|
||||
# argv -> rdx\n\
|
||||
- leaq 8(%r13), %rdx\n\
|
||||
+ lea " LP_SIZE "(%r13), %" RDX_LP "\n\
|
||||
# Clear %rbp to mark outermost frame obviously even for constructors.\n\
|
||||
xorl %ebp, %ebp\n\
|
||||
# Call the function to run the initializers.\n\
|
||||
call _dl_init\n\
|
||||
# Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\
|
||||
- leaq _dl_fini(%rip), %rdx\n\
|
||||
+ lea _dl_fini(%rip), %" RDX_LP "\n\
|
||||
# And make sure %rsp points to argc stored on the stack.\n\
|
||||
- movq %r13, %rsp\n\
|
||||
+ mov %" R13_LP ", %" RSP_LP "\n\
|
||||
# Jump to the user's entry point.\n\
|
||||
jmp *%r12\n\
|
||||
.previous\n\
|
||||
@@ -234,8 +234,13 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc,
|
||||
|
||||
|
||||
/* Names of the architecture-specific auditing callback functions. */
|
||||
+#ifdef __LP64__
|
||||
#define ARCH_LA_PLTENTER x86_64_gnu_pltenter
|
||||
#define ARCH_LA_PLTEXIT x86_64_gnu_pltexit
|
||||
+#else
|
||||
+#define ARCH_LA_PLTENTER x32_gnu_pltenter
|
||||
+#define ARCH_LA_PLTEXIT x32_gnu_pltexit
|
||||
+#endif
|
||||
|
||||
#endif /* !dl_machine_h */
|
||||
|
||||
diff --git a/sysdeps/x86_64/x32/dl-machine.h b/sysdeps/x86_64/x32/dl-machine.h
|
||||
deleted file mode 100644
|
||||
index c35cee92619923a2..0000000000000000
|
||||
--- a/sysdeps/x86_64/x32/dl-machine.h
|
||||
+++ /dev/null
|
||||
@@ -1,76 +0,0 @@
|
||||
-/* Machine-dependent ELF dynamic relocation inline functions. x32 version.
|
||||
- Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
- This file is part of the GNU C Library.
|
||||
-
|
||||
- The GNU C Library is free software; you can redistribute it and/or
|
||||
- modify it under the terms of the GNU Lesser General Public
|
||||
- License as published by the Free Software Foundation; either
|
||||
- version 2.1 of the License, or (at your option) any later version.
|
||||
-
|
||||
- The GNU C Library is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
- Lesser General Public License for 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/>. */
|
||||
-
|
||||
-/* Must allow <sysdeps/x86_64/dl-machine.h> to be included more than once.
|
||||
- See #ifdef RESOLVE_MAP in sysdeps/x86_64/dl-machine.h. */
|
||||
-#include <sysdeps/x86_64/dl-machine.h>
|
||||
-
|
||||
-#ifndef _X32_DL_MACHINE_H
|
||||
-#define _X32_DL_MACHINE_H
|
||||
-
|
||||
-#undef ARCH_LA_PLTENTER
|
||||
-#undef ARCH_LA_PLTEXIT
|
||||
-#undef RTLD_START
|
||||
-
|
||||
-/* Names of the architecture-specific auditing callback functions. */
|
||||
-#define ARCH_LA_PLTENTER x32_gnu_pltenter
|
||||
-#define ARCH_LA_PLTEXIT x32_gnu_pltexit
|
||||
-
|
||||
-/* Initial entry point code for the dynamic linker.
|
||||
- The C function `_dl_start' is the real entry point;
|
||||
- its return value is the user program's entry point. */
|
||||
-#define RTLD_START asm ("\n\
|
||||
-.text\n\
|
||||
- .p2align 4\n\
|
||||
-.globl _start\n\
|
||||
-.globl _dl_start_user\n\
|
||||
-_start:\n\
|
||||
- movl %esp, %edi\n\
|
||||
- call _dl_start\n\
|
||||
-_dl_start_user:\n\
|
||||
- # Save the user entry point address in %r12.\n\
|
||||
- movl %eax, %r12d\n\
|
||||
- # Read the original argument count.\n\
|
||||
- movl (%rsp), %edx\n\
|
||||
- # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
|
||||
- # argc -> rsi\n\
|
||||
- movl %edx, %esi\n\
|
||||
- # Save %rsp value in %r13.\n\
|
||||
- movl %esp, %r13d\n\
|
||||
- # And align stack for the _dl_init call.\n\
|
||||
- and $-16, %esp\n\
|
||||
- # _dl_loaded -> rdi\n\
|
||||
- movl _rtld_local(%rip), %edi\n\
|
||||
- # env -> rcx\n\
|
||||
- lea 8(%r13,%rdx,4), %ecx\n\
|
||||
- # argv -> rdx\n\
|
||||
- lea 4(%r13), %edx\n\
|
||||
- # Clear %rbp to mark outermost frame obviously even for constructors.\n\
|
||||
- xorl %ebp, %ebp\n\
|
||||
- # Call the function to run the initializers.\n\
|
||||
- call _dl_init\n\
|
||||
- # Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\
|
||||
- lea _dl_fini(%rip), %edx\n\
|
||||
- # And make sure %rsp points to argc stored on the stack.\n\
|
||||
- movl %r13d, %esp\n\
|
||||
- # Jump to the user's entry point.\n\
|
||||
- jmp *%r12\n\
|
||||
-.previous\n\
|
||||
-");
|
||||
-
|
||||
-#endif /* !_X32_DL_MACHINE_H */
|
@ -0,0 +1,72 @@
|
||||
commit 9fbbe86f7c6ab19356cfa7ca15b4b7c29b72e8cb
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Mon Jul 22 17:47:22 2024 -0700
|
||||
|
||||
x32/cet: Support shadow stack during startup for Linux 6.10
|
||||
|
||||
Use RXX_LP in RTLD_START_ENABLE_X86_FEATURES. Support shadow stack during
|
||||
startup for Linux 6.10:
|
||||
|
||||
commit 2883f01ec37dd8668e7222dfdb5980c86fdfe277
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Fri Mar 15 07:04:33 2024 -0700
|
||||
|
||||
x86/shstk: Enable shadow stacks for x32
|
||||
|
||||
1. Add shadow stack support to x32 signal.
|
||||
2. Use the 64-bit map_shadow_stack syscall for x32.
|
||||
3. Set up shadow stack for x32.
|
||||
|
||||
Add the map_shadow_stack system call to <fixup-asm-unistd.h> and regenerate
|
||||
arch-syscall.h. Tested on Intel Tiger Lake with CET enabled x32. There
|
||||
are no regressions with CET enabled x86-64. There are no changes in CET
|
||||
enabled x86-64 _dl_start_user.
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||
(cherry picked from commit 8344c1f5514b1b5b1c8c6e48f4b802653bd23b71)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-cet.h b/sysdeps/unix/sysv/linux/x86_64/dl-cet.h
|
||||
index 1fe313340611d9c5..b4f7e6c9cd7548a2 100644
|
||||
--- a/sysdeps/unix/sysv/linux/x86_64/dl-cet.h
|
||||
+++ b/sysdeps/unix/sysv/linux/x86_64/dl-cet.h
|
||||
@@ -92,9 +92,9 @@ dl_cet_ibt_enabled (void)
|
||||
# Pass GL(dl_x86_feature_1) to _dl_cet_setup_features.\n\
|
||||
movl %edx, %edi\n\
|
||||
# Align stack for the _dl_cet_setup_features call.\n\
|
||||
- andq $-16, %rsp\n\
|
||||
+ and $-16, %" RSP_LP "\n\
|
||||
call _dl_cet_setup_features\n\
|
||||
# Restore %rax and %rsp from %r12 and %r13.\n\
|
||||
- movq %r12, %rax\n\
|
||||
- movq %r13, %rsp\n\
|
||||
+ mov %" R12_LP ", %" RAX_LP "\n\
|
||||
+ mov %" R13_LP ", %" RSP_LP "\n\
|
||||
"
|
||||
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
|
||||
index b9db8bc5be05eed8..645e85802f95a78c 100644
|
||||
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
|
||||
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
|
||||
@@ -151,6 +151,7 @@
|
||||
#define __NR_lsetxattr 1073742013
|
||||
#define __NR_lstat 1073741830
|
||||
#define __NR_madvise 1073741852
|
||||
+#define __NR_map_shadow_stack 1073742277
|
||||
#define __NR_mbind 1073742061
|
||||
#define __NR_membarrier 1073742148
|
||||
#define __NR_memfd_create 1073742143
|
||||
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h
|
||||
index 98124169e6035ea8..47fa8af4ce9af68e 100644
|
||||
--- a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h
|
||||
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h
|
||||
@@ -15,6 +15,10 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
+#ifndef __NR_map_shadow_stack
|
||||
+# define __NR_map_shadow_stack 1073742277
|
||||
+#endif
|
||||
+
|
||||
/* X32 uses the same 64-bit syscall interface for set_thread_area. */
|
||||
#ifndef __NR_set_thread_area
|
||||
# define __NR_set_thread_area 1073742029
|
@ -0,0 +1,24 @@
|
||||
commit 81631a0dd1b76e6fe8e0ffcd9ee411676031b1bb
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jul 19 15:57:46 2024 +0200
|
||||
|
||||
Adjust check-local-headers test for libaudit 4.0
|
||||
|
||||
The new version introduces /usr/include/audit_logging.h and
|
||||
/usr/include/audit-records.h.
|
||||
|
||||
(cherry picked from commit 91eb62d63887a959e43aafb6fc022a87614dc7c9)
|
||||
|
||||
diff --git a/scripts/check-local-headers.sh b/scripts/check-local-headers.sh
|
||||
index 5d3e61f8894b600e..ad23840333f7c7e5 100755
|
||||
--- a/scripts/check-local-headers.sh
|
||||
+++ b/scripts/check-local-headers.sh
|
||||
@@ -33,7 +33,7 @@ exec ${AWK} -v includedir="$includedir" '
|
||||
BEGIN {
|
||||
status = 0
|
||||
exclude = "^" includedir \
|
||||
- "/(.*-.*-.*/|.*-.*/|)(asm[-/]|arch|linux/|selinux/|mach/|mach_debug/|device/|hurd/(((hurd|ioctl)_types|paths)\\.h|ioctls\\.defs|ihash\\.h|version\\.h)|gd|nss3/|nspr4?/|c\\+\\+/|sys/(capability|sdt(|-config))\\.h|libaudit\\.h)"
|
||||
+ "/(.*-.*-.*/|.*-.*/|)(asm[-/]|arch|linux/|selinux/|mach/|mach_debug/|device/|hurd/(((hurd|ioctl)_types|paths)\\.h|ioctls\\.defs|ihash\\.h|version\\.h)|gd|nss3/|nspr4?/|c\\+\\+/|sys/(capability|sdt(|-config))\\.h|libaudit\\.h|audit(_logging|-records)\\.h)"
|
||||
}
|
||||
/^[^ ]/ && $1 ~ /.*:/ { obj = $1 }
|
||||
{
|
@ -0,0 +1,156 @@
|
||||
commit 49953727d1768baeef2914f709f35cb4acad2d0b
|
||||
Author: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||
Date: Tue Aug 13 23:29:14 2024 +0800
|
||||
|
||||
x86: Fix bug in strchrnul-evex512 [BZ #32078]
|
||||
|
||||
Issue was we were expecting not matches with CHAR before the start of
|
||||
the string in the page cross case.
|
||||
|
||||
The check code in the page cross case:
|
||||
```
|
||||
and $0xffffffffffffffc0,%rax
|
||||
vmovdqa64 (%rax),%zmm17
|
||||
vpcmpneqb %zmm17,%zmm16,%k1
|
||||
vptestmb %zmm17,%zmm17,%k0{%k1}
|
||||
kmovq %k0,%rax
|
||||
inc %rax
|
||||
shr %cl,%rax
|
||||
je L(continue)
|
||||
```
|
||||
|
||||
expects that all characters that neither match null nor CHAR will be
|
||||
1s in `rax` prior to the `inc`. Then the `inc` will overflow all of
|
||||
the 1s where no relevant match was found.
|
||||
|
||||
This is incorrect in the page-cross case, as the
|
||||
`vmovdqa64 (%rax),%zmm17` loads from before the start of the input
|
||||
string.
|
||||
|
||||
If there are matches with CHAR before the start of the string, `rax`
|
||||
won't properly overflow.
|
||||
|
||||
The fix is quite simple. Just replace:
|
||||
|
||||
```
|
||||
inc %rax
|
||||
shr %cl,%rax
|
||||
```
|
||||
With:
|
||||
```
|
||||
sar %cl,%rax
|
||||
inc %rax
|
||||
```
|
||||
|
||||
The arithmetic shift will clear any matches prior to the start of the
|
||||
string while maintaining the signbit so the 1s can properly overflow
|
||||
to zero in the case of no matches.
|
||||
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
|
||||
(cherry picked from commit 7da08862471dfec6fdae731c2a5f351ad485c71f)
|
||||
|
||||
diff --git a/string/test-strchr.c b/string/test-strchr.c
|
||||
index c795eac6fa7b93b9..72b17af687f6ad0e 100644
|
||||
--- a/string/test-strchr.c
|
||||
+++ b/string/test-strchr.c
|
||||
@@ -255,6 +255,69 @@ check1 (void)
|
||||
check_result (impl, s, c, exp_result);
|
||||
}
|
||||
|
||||
+static void
|
||||
+check2 (void)
|
||||
+{
|
||||
+ CHAR *s = (CHAR *) (buf1 + getpagesize () - 4 * sizeof (CHAR));
|
||||
+ CHAR *s_begin = (CHAR *) (buf1 + getpagesize () - 64);
|
||||
+#ifndef USE_FOR_STRCHRNUL
|
||||
+ CHAR *exp_result = NULL;
|
||||
+#else
|
||||
+ CHAR *exp_result = s + 1;
|
||||
+#endif
|
||||
+ CHAR val = 0x12;
|
||||
+ for (; s_begin != s; ++s_begin)
|
||||
+ *s_begin = val;
|
||||
+
|
||||
+ s[0] = val + 1;
|
||||
+ s[1] = 0;
|
||||
+ s[2] = val + 1;
|
||||
+ s[3] = val + 1;
|
||||
+
|
||||
+ {
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, s, val, exp_result);
|
||||
+ }
|
||||
+ s[3] = val;
|
||||
+ {
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, s, val, exp_result);
|
||||
+ }
|
||||
+ exp_result = s;
|
||||
+ s[0] = val;
|
||||
+ {
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, s, val, exp_result);
|
||||
+ }
|
||||
+
|
||||
+ s[3] = val + 1;
|
||||
+ {
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, s, val, exp_result);
|
||||
+ }
|
||||
+
|
||||
+ s[0] = val + 1;
|
||||
+ s[1] = val + 1;
|
||||
+ s[2] = val + 1;
|
||||
+ s[3] = val + 1;
|
||||
+ s[4] = val;
|
||||
+ exp_result = s + 4;
|
||||
+ {
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, s, val, exp_result);
|
||||
+ }
|
||||
+ s[4] = 0;
|
||||
+#ifndef USE_FOR_STRCHRNUL
|
||||
+ exp_result = NULL;
|
||||
+#else
|
||||
+ exp_result = s + 4;
|
||||
+#endif
|
||||
+ {
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, s, val, exp_result);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
int
|
||||
test_main (void)
|
||||
{
|
||||
@@ -263,7 +326,7 @@ test_main (void)
|
||||
test_init ();
|
||||
|
||||
check1 ();
|
||||
-
|
||||
+ check2 ();
|
||||
printf ("%20s", "");
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
printf ("\t%s", impl->name);
|
||||
diff --git a/sysdeps/x86_64/multiarch/strchr-evex-base.S b/sysdeps/x86_64/multiarch/strchr-evex-base.S
|
||||
index 04e2c0e79e381691..3a0b7c9d6429fb20 100644
|
||||
--- a/sysdeps/x86_64/multiarch/strchr-evex-base.S
|
||||
+++ b/sysdeps/x86_64/multiarch/strchr-evex-base.S
|
||||
@@ -124,13 +124,13 @@ L(page_cross):
|
||||
VPCMPNE %VMM(1), %VMM(0), %k1
|
||||
VPTEST %VMM(1), %VMM(1), %k0{%k1}
|
||||
KMOV %k0, %VRAX
|
||||
-# ifdef USE_AS_WCSCHR
|
||||
+ sar %cl, %VRAX
|
||||
+#ifdef USE_AS_WCSCHR
|
||||
sub $VEC_MATCH_MASK, %VRAX
|
||||
-# else
|
||||
+#else
|
||||
inc %VRAX
|
||||
-# endif
|
||||
+#endif
|
||||
/* Ignore number of character for alignment adjustment. */
|
||||
- shr %cl, %VRAX
|
||||
jz L(align_more)
|
||||
|
||||
bsf %VRAX, %VRAX
|
@ -0,0 +1,23 @@
|
||||
commit 37c2aa4eaa0adc4193bc0e1f520b677ad30c9e4d
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Aug 9 16:17:14 2024 +0200
|
||||
|
||||
Define __libc_initial for the static libc
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit eb0e50e9a1cf80a2ba6f33f990a08ef37a3267fb)
|
||||
|
||||
diff --git a/include/libc-internal.h b/include/libc-internal.h
|
||||
index 87ac591835637e4d..1ef43ffe673907a0 100644
|
||||
--- a/include/libc-internal.h
|
||||
+++ b/include/libc-internal.h
|
||||
@@ -53,6 +53,9 @@ extern __typeof (__profile_frequency) __profile_frequency attribute_hidden;
|
||||
is not for an audit module, not loaded via dlmopen, and not loaded
|
||||
via static dlopen either). */
|
||||
extern _Bool __libc_initial attribute_hidden;
|
||||
+#else
|
||||
+/* The static libc is always the initial namespace. */
|
||||
+# define __libc_initial ((_Bool) 1)
|
||||
#endif
|
||||
|
||||
#endif /* _LIBC_INTERNAL */
|
@ -0,0 +1,139 @@
|
||||
commit e73fd06b7f12d6ddaae4f91f9c5088a621a82ce4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Aug 19 15:48:03 2024 +0200
|
||||
|
||||
string: strerror, strsignal cannot use buffer after dlmopen (bug 32026)
|
||||
|
||||
Secondary namespaces have a different malloc. Allocating the
|
||||
buffer in one namespace and freeing it another results in
|
||||
heap corruption. Fix this by using a static string (potentially
|
||||
translated) in secondary namespaces. It would also be possible
|
||||
to use the malloc from the initial namespace to manage the
|
||||
buffer, but these functions would still not be safe to use in
|
||||
auditors etc. because a call to strerror could still free a
|
||||
buffer while it is used by the application. Another approach
|
||||
could use proper initial-exec TLS, duplicated in secondary
|
||||
namespaces, but that would need a callback interface for freeing
|
||||
libc resources in namespaces on thread exit, which does not exist
|
||||
today.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit 25a5eb4010df94b412c67db9e346029de316d06b)
|
||||
|
||||
diff --git a/string/strerror_l.c b/string/strerror_l.c
|
||||
index 15cce261e6b406a7..70456e5bb45e5b52 100644
|
||||
--- a/string/strerror_l.c
|
||||
+++ b/string/strerror_l.c
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <tls-internal.h>
|
||||
-
|
||||
+#include <libc-internal.h>
|
||||
|
||||
static const char *
|
||||
translate (const char *str, locale_t loc)
|
||||
@@ -31,6 +31,12 @@ translate (const char *str, locale_t loc)
|
||||
return res;
|
||||
}
|
||||
|
||||
+static char *
|
||||
+unknown_error (locale_t loc)
|
||||
+{
|
||||
+ return (char *) translate ("Unknown error", loc);
|
||||
+}
|
||||
+
|
||||
|
||||
/* Return a string describing the errno code in ERRNUM. */
|
||||
char *
|
||||
@@ -40,18 +46,25 @@ __strerror_l (int errnum, locale_t loc)
|
||||
char *err = (char *) __get_errlist (errnum);
|
||||
if (__glibc_unlikely (err == NULL))
|
||||
{
|
||||
- struct tls_internal_t *tls_internal = __glibc_tls_internal ();
|
||||
- free (tls_internal->strerror_l_buf);
|
||||
- if (__asprintf (&tls_internal->strerror_l_buf, "%s%d",
|
||||
- translate ("Unknown error ", loc), errnum) > 0)
|
||||
- err = tls_internal->strerror_l_buf;
|
||||
- else
|
||||
+ if (__libc_initial)
|
||||
{
|
||||
- /* The memory was freed above. */
|
||||
- tls_internal->strerror_l_buf = NULL;
|
||||
- /* Provide a fallback translation. */
|
||||
- err = (char *) translate ("Unknown error", loc);
|
||||
+ struct tls_internal_t *tls_internal = __glibc_tls_internal ();
|
||||
+ free (tls_internal->strerror_l_buf);
|
||||
+ if (__asprintf (&tls_internal->strerror_l_buf, "%s%d",
|
||||
+ translate ("Unknown error ", loc), errnum) > 0)
|
||||
+ err = tls_internal->strerror_l_buf;
|
||||
+ else
|
||||
+ {
|
||||
+ /* The memory was freed above. */
|
||||
+ tls_internal->strerror_l_buf = NULL;
|
||||
+ /* Provide a fallback translation. */
|
||||
+ err = unknown_error (loc);
|
||||
+ }
|
||||
}
|
||||
+ else
|
||||
+ /* Secondary namespaces use a different malloc, so cannot
|
||||
+ participate in the buffer management. */
|
||||
+ err = unknown_error (loc);
|
||||
}
|
||||
else
|
||||
err = (char *) translate (err, loc);
|
||||
diff --git a/string/strsignal.c b/string/strsignal.c
|
||||
index 31146015647c1d4a..d9b03654683a6805 100644
|
||||
--- a/string/strsignal.c
|
||||
+++ b/string/strsignal.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#include <tls-internal.h>
|
||||
+#include <libc-internal.h>
|
||||
|
||||
/* Return a string describing the meaning of the signal number SIGNUM. */
|
||||
char *
|
||||
@@ -30,21 +31,28 @@ strsignal (int signum)
|
||||
if (desc != NULL)
|
||||
return _(desc);
|
||||
|
||||
- struct tls_internal_t *tls_internal = __glibc_tls_internal ();
|
||||
- free (tls_internal->strsignal_buf);
|
||||
+ if (__libc_initial)
|
||||
+ {
|
||||
+ struct tls_internal_t *tls_internal = __glibc_tls_internal ();
|
||||
+ free (tls_internal->strsignal_buf);
|
||||
|
||||
- int r;
|
||||
+ int r;
|
||||
#ifdef SIGRTMIN
|
||||
- if (signum >= SIGRTMIN && signum <= SIGRTMAX)
|
||||
- r = __asprintf (&tls_internal->strsignal_buf, _("Real-time signal %d"),
|
||||
- signum - SIGRTMIN);
|
||||
- else
|
||||
+ if (signum >= SIGRTMIN && signum <= SIGRTMAX)
|
||||
+ r = __asprintf (&tls_internal->strsignal_buf, _("Real-time signal %d"),
|
||||
+ signum - SIGRTMIN);
|
||||
+ else
|
||||
#endif
|
||||
- r = __asprintf (&tls_internal->strsignal_buf, _("Unknown signal %d"),
|
||||
- signum);
|
||||
-
|
||||
- if (r == -1)
|
||||
- tls_internal->strsignal_buf = NULL;
|
||||
-
|
||||
- return tls_internal->strsignal_buf;
|
||||
+ r = __asprintf (&tls_internal->strsignal_buf, _("Unknown signal %d"),
|
||||
+ signum);
|
||||
+
|
||||
+ if (r >= 0)
|
||||
+ return tls_internal->strsignal_buf;
|
||||
+ else
|
||||
+ tls_internal->strsignal_buf = NULL;
|
||||
+ }
|
||||
+ /* Fall through on asprintf error, and for !__libc_initial:
|
||||
+ secondary namespaces use a different malloc and cannot
|
||||
+ participate in the buffer management. */
|
||||
+ return _("Unknown signal");
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
commit 98de2f2baebeeac13748f064017b7bd2b94fafee
|
||||
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||
Date: Fri Jul 26 13:21:34 2024 +0100
|
||||
|
||||
support: Add FAIL test failure helper
|
||||
|
||||
Add a FAIL test failure helper analogous to FAIL_RET, that does not
|
||||
cause the current function to return, providing a standardized way to
|
||||
report a test failure with a message supplied while permitting the
|
||||
caller to continue executing, for further reporting, cleaning up, etc.
|
||||
|
||||
Update existing test cases that provide a conflicting definition of FAIL
|
||||
by removing the local FAIL definition and then as follows:
|
||||
|
||||
- tst-fortify-syslog: provide a meaningful message in addition to the
|
||||
file name already added by <support/check.h>; 'support_record_failure'
|
||||
is already called by 'support_print_failure_impl' invoked by the new
|
||||
FAIL test failure helper.
|
||||
|
||||
- tst-ctype: no update to FAIL calls required, with the name of the file
|
||||
and the line number within of the failure site additionally included
|
||||
by the new FAIL test failure helper, and error counting plus count
|
||||
reporting upon test program termination also already provided by
|
||||
'support_record_failure' and 'support_report_failure' respectively,
|
||||
called by 'support_print_failure_impl' and 'adjust_exit_status' also
|
||||
respectively. However in a number of places 'printf' is called and
|
||||
the error count adjusted by hand, so update these places to make use
|
||||
of FAIL instead. And last but not least adjust the final summary just
|
||||
to report completion, with any error count following as reported by
|
||||
the test driver.
|
||||
|
||||
- test-tgmath2: no update to FAIL calls required, with the name of the
|
||||
file of the failure site additionally included by the new FAIL test
|
||||
failure helper. Also there is no need to track the return status by
|
||||
hand as any call to FAIL will eventually cause the test case to return
|
||||
an unsuccesful exit status regardless of the return status from the
|
||||
test function, via a call to 'adjust_exit_status' made by the test
|
||||
driver.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
(cherry picked from commit 1b97a9f23bf605ca608162089c94187573fb2a9e)
|
||||
|
||||
diff --git a/debug/tst-fortify-syslog.c b/debug/tst-fortify-syslog.c
|
||||
index a7ddbf7c6b6d33c9..2712acf689ff5af2 100644
|
||||
--- a/debug/tst-fortify-syslog.c
|
||||
+++ b/debug/tst-fortify-syslog.c
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
-#include <stdio.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
@@ -46,18 +45,13 @@ handler (int sig)
|
||||
_exit (127);
|
||||
}
|
||||
|
||||
-#define FAIL() \
|
||||
- do { \
|
||||
- printf ("Failure on line %d\n", __LINE__); \
|
||||
- support_record_failure (); \
|
||||
- } while (0)
|
||||
#define CHK_FAIL_START \
|
||||
chk_fail_ok = 1; \
|
||||
if (! setjmp (chk_fail_buf)) \
|
||||
{
|
||||
#define CHK_FAIL_END \
|
||||
chk_fail_ok = 0; \
|
||||
- FAIL (); \
|
||||
+ FAIL ("not supposed to reach here"); \
|
||||
}
|
||||
|
||||
static void
|
||||
diff --git a/localedata/tst-ctype.c b/localedata/tst-ctype.c
|
||||
index 9de979a2d7592789..a23689719c173711 100644
|
||||
--- a/localedata/tst-ctype.c
|
||||
+++ b/localedata/tst-ctype.c
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
+#include <support/check.h>
|
||||
+
|
||||
|
||||
static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
@@ -53,19 +55,11 @@ static struct classes
|
||||
#define nclasses (sizeof (classes) / sizeof (classes[0]))
|
||||
|
||||
|
||||
-#define FAIL(str, args...) \
|
||||
- { \
|
||||
- printf (" " str "\n", ##args); \
|
||||
- ++errors; \
|
||||
- }
|
||||
-
|
||||
-
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
const char *cp;
|
||||
const char *cp2;
|
||||
- int errors = 0;
|
||||
char *inpline = NULL;
|
||||
size_t inplinelen = 0;
|
||||
char *resline = NULL;
|
||||
@@ -394,11 +388,8 @@ punct = %04x alnum = %04x\n",
|
||||
{
|
||||
if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
|
||||
!= (*resp != '0'))
|
||||
- {
|
||||
- printf (" is%s('%c' = '\\x%02x') %s true\n", inpline,
|
||||
- *inp, *inp, *resp == '1' ? "not" : "is");
|
||||
- ++errors;
|
||||
- }
|
||||
+ FAIL (" is%s('%c' = '\\x%02x') %s true\n", inpline,
|
||||
+ *inp, *inp, *resp == '1' ? "not" : "is");
|
||||
++inp;
|
||||
++resp;
|
||||
}
|
||||
@@ -408,11 +399,8 @@ punct = %04x alnum = %04x\n",
|
||||
while (*inp != '\0')
|
||||
{
|
||||
if (tolower (*inp) != *resp)
|
||||
- {
|
||||
- printf (" tolower('%c' = '\\x%02x') != '%c'\n",
|
||||
- *inp, *inp, *resp);
|
||||
- ++errors;
|
||||
- }
|
||||
+ FAIL (" tolower('%c' = '\\x%02x') != '%c'\n",
|
||||
+ *inp, *inp, *resp);
|
||||
++inp;
|
||||
++resp;
|
||||
}
|
||||
@@ -422,11 +410,8 @@ punct = %04x alnum = %04x\n",
|
||||
while (*inp != '\0')
|
||||
{
|
||||
if (toupper (*inp) != *resp)
|
||||
- {
|
||||
- printf (" toupper('%c' = '\\x%02x') != '%c'\n",
|
||||
- *inp, *inp, *resp);
|
||||
- ++errors;
|
||||
- }
|
||||
+ FAIL (" toupper('%c' = '\\x%02x') != '%c'\n",
|
||||
+ *inp, *inp, *resp);
|
||||
++inp;
|
||||
++resp;
|
||||
}
|
||||
@@ -436,14 +421,7 @@ punct = %04x alnum = %04x\n",
|
||||
}
|
||||
|
||||
|
||||
- if (errors != 0)
|
||||
- {
|
||||
- printf (" %d error%s for `%s' locale\n\n\n", errors,
|
||||
- errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
- printf (" No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
|
||||
+ printf ("Completed testing for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/math/test-tgmath2.c b/math/test-tgmath2.c
|
||||
index 37afa8a08a5a4a9c..4aeb877b8e54c0a4 100644
|
||||
--- a/math/test-tgmath2.c
|
||||
+++ b/math/test-tgmath2.c
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <string.h>
|
||||
#include <tgmath.h>
|
||||
|
||||
+#include <support/check.h>
|
||||
+
|
||||
//#define DEBUG
|
||||
|
||||
typedef complex float cfloat;
|
||||
@@ -87,13 +89,6 @@ enum
|
||||
int count;
|
||||
int counts[Tlast][C_last];
|
||||
|
||||
-#define FAIL(str) \
|
||||
- do \
|
||||
- { \
|
||||
- printf ("%s failure on line %d\n", (str), __LINE__); \
|
||||
- result = 1; \
|
||||
- } \
|
||||
- while (0)
|
||||
#define TEST_TYPE_ONLY(expr, rettype) \
|
||||
do \
|
||||
{ \
|
||||
@@ -133,8 +128,6 @@ int counts[Tlast][C_last];
|
||||
int
|
||||
test_cos (const int Vint4, const long long int Vllong4)
|
||||
{
|
||||
- int result = 0;
|
||||
-
|
||||
TEST (cos (vfloat1), float, cos);
|
||||
TEST (cos (vdouble1), double, cos);
|
||||
TEST (cos (vldouble1), ldouble, cos);
|
||||
@@ -152,7 +145,7 @@ test_cos (const int Vint4, const long long int Vllong4)
|
||||
TEST (cos (Vcdouble1), cdouble, cos);
|
||||
TEST (cos (Vcldouble1), cldouble, cos);
|
||||
|
||||
- return result;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
int
|
||||
diff --git a/support/check.h b/support/check.h
|
||||
index 711f34b83b95b594..7ea22c7a2cba5cfd 100644
|
||||
--- a/support/check.h
|
||||
+++ b/support/check.h
|
||||
@@ -24,6 +24,11 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
+/* Record a test failure, print the failure message to standard output
|
||||
+ and pass the result of 1 through. */
|
||||
+#define FAIL(...) \
|
||||
+ support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
|
||||
+
|
||||
/* Record a test failure, print the failure message to standard output
|
||||
and return 1. */
|
||||
#define FAIL_RET(...) \
|
@ -0,0 +1,168 @@
|
||||
commit 3c5f493d871c11de9d8358b8ac84c144a0d848fa
|
||||
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||
Date: Fri Jul 26 13:21:34 2024 +0100
|
||||
|
||||
stdio-common: Add test for vfscanf with matches longer than INT_MAX [BZ #27650]
|
||||
|
||||
Complement commit b03e4d7bd25b ("stdio: fix vfscanf with matches longer
|
||||
than INT_MAX (bug 27650)") and add a test case for the issue, inspired
|
||||
by the reproducer provided with the bug report.
|
||||
|
||||
This has been verified to succeed as from the commit referred and fail
|
||||
beforehand.
|
||||
|
||||
As the test requires 2GiB of data to be passed around its performance
|
||||
has been evaluated using a choice of systems and the execution time
|
||||
determined to be respectively in the range of 9s for POWER9@2.166GHz,
|
||||
24s for FU740@1.2GHz, and 40s for 74Kf@950MHz. As this is on the verge
|
||||
of and beyond the default timeout it has been increased by the factor of
|
||||
8. Regardless, following recent practice the test has been added to the
|
||||
standard rather than extended set.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
(cherry picked from commit 89cddc8a7096f3d9225868304d2bc0a1aaf07d63)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index e312565f3b671463..159dc472e4c76b9a 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -243,6 +243,7 @@ tests := \
|
||||
tst-scanf-binary-c2x \
|
||||
tst-scanf-binary-gnu11 \
|
||||
tst-scanf-binary-gnu89 \
|
||||
+ tst-scanf-bz27650 \
|
||||
tst-scanf-intn \
|
||||
tst-scanf-round \
|
||||
tst-scanf-to_inpunct \
|
||||
@@ -313,6 +314,7 @@ generated += \
|
||||
tst-printf-fp-free.mtrace \
|
||||
tst-printf-fp-leak-mem.out \
|
||||
tst-printf-fp-leak.mtrace \
|
||||
+ tst-scanf-bz27650.mtrace \
|
||||
tst-vfprintf-width-prec-mem.out \
|
||||
tst-vfprintf-width-prec.mtrace \
|
||||
# generated
|
||||
@@ -402,6 +404,9 @@ tst-printf-fp-free-ENV = \
|
||||
tst-printf-fp-leak-ENV = \
|
||||
MALLOC_TRACE=$(objpfx)tst-printf-fp-leak.mtrace \
|
||||
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
|
||||
+tst-scanf-bz27650-ENV = \
|
||||
+ MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \
|
||||
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
|
||||
|
||||
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
|
||||
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
|
||||
diff --git a/stdio-common/tst-scanf-bz27650.c b/stdio-common/tst-scanf-bz27650.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..3a742bc86556908c
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-scanf-bz27650.c
|
||||
@@ -0,0 +1,108 @@
|
||||
+/* Test for BZ #27650, formatted input matching beyond INT_MAX.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <error.h>
|
||||
+#include <errno.h>
|
||||
+#include <limits.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <sys/types.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/test-driver.h>
|
||||
+
|
||||
+/* Produce a stream of more than INT_MAX characters via buffer BUF of
|
||||
+ size SIZE according to bookkeeping in COOKIE and then return EOF. */
|
||||
+
|
||||
+static ssize_t
|
||||
+io_read (void *cookie, char *buf, size_t size)
|
||||
+{
|
||||
+ unsigned int *written = cookie;
|
||||
+ unsigned int w = *written;
|
||||
+
|
||||
+ if (w > INT_MAX)
|
||||
+ return 0;
|
||||
+
|
||||
+ memset (buf, 'a', size);
|
||||
+ *written = w + size;
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+/* Consume a stream of more than INT_MAX characters from an artificial
|
||||
+ input stream of which none is the new line character. The call to
|
||||
+ fscanf is supposed to complete upon the EOF condition of input,
|
||||
+ however in the presence of BZ #27650 it will terminate prematurely
|
||||
+ with characters still outstanding in input. Diagnose the condition
|
||||
+ and return status accordingly. */
|
||||
+
|
||||
+int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ static cookie_io_functions_t io_funcs = { .read = io_read };
|
||||
+ unsigned int written = 0;
|
||||
+ FILE *in;
|
||||
+ int v;
|
||||
+
|
||||
+ mtrace ();
|
||||
+
|
||||
+ in = fopencookie (&written, "r", io_funcs);
|
||||
+ if (in == NULL)
|
||||
+ {
|
||||
+ FAIL ("fopencookie: %m");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ v = fscanf (in, "%*[^\n]");
|
||||
+ if (ferror (in))
|
||||
+ {
|
||||
+ FAIL ("fscanf: input failure, at %u: %m", written);
|
||||
+ goto out_close;
|
||||
+ }
|
||||
+ else if (v == EOF)
|
||||
+ {
|
||||
+ FAIL ("fscanf: unexpected end of file, at %u", written);
|
||||
+ goto out_close;
|
||||
+ }
|
||||
+
|
||||
+ if (!feof (in))
|
||||
+ {
|
||||
+ v = fgetc (in);
|
||||
+ if (ferror (in))
|
||||
+ FAIL ("fgetc: input failure: %m");
|
||||
+ else if (v == EOF)
|
||||
+ FAIL ("fgetc: unexpected end of file after missing end of file");
|
||||
+ else if (v == '\n')
|
||||
+ FAIL ("unexpected new line character received");
|
||||
+ else
|
||||
+ FAIL ("character received after end of file expected: \\x%02x", v);
|
||||
+ }
|
||||
+
|
||||
+out_close:
|
||||
+ if (fclose (in) != 0)
|
||||
+ FAIL ("fclose: %m");
|
||||
+
|
||||
+out:
|
||||
+ return EXIT_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+#define TIMEOUT (DEFAULT_TIMEOUT * 8)
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,142 @@
|
||||
commit f0c308ab239340190f5ca9a226e43f3041d487f7
|
||||
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Date: Wed Aug 14 19:20:04 2024 -0400
|
||||
|
||||
Make tst-ungetc use libsupport
|
||||
|
||||
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit 3f7df7e757f4efec38e45d4068e5492efcac4856)
|
||||
|
||||
diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c
|
||||
index 1344b2b591e3d6b1..5c808f073419f00b 100644
|
||||
--- a/stdio-common/tst-ungetc.c
|
||||
+++ b/stdio-common/tst-ungetc.c
|
||||
@@ -1,70 +1,72 @@
|
||||
-/* Test for ungetc bugs. */
|
||||
+/* Test for ungetc bugs.
|
||||
+ Copyright (C) 1996-2024 Free Software Foundation, Inc.
|
||||
+ Copyright The GNU Toolchain Authors.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
-#include <unistd.h>
|
||||
-
|
||||
-#undef assert
|
||||
-#define assert(x) \
|
||||
- if (!(x)) \
|
||||
- { \
|
||||
- fputs ("test failed: " #x "\n", stderr); \
|
||||
- retval = 1; \
|
||||
- goto the_end; \
|
||||
- }
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <support/xunistd.h>
|
||||
|
||||
-int
|
||||
-main (int argc, char *argv[])
|
||||
+static int
|
||||
+do_test (void)
|
||||
{
|
||||
- char name[] = "/tmp/tst-ungetc.XXXXXX";
|
||||
+ char *name = NULL;
|
||||
FILE *fp = NULL;
|
||||
- int retval = 0;
|
||||
int c;
|
||||
char buffer[64];
|
||||
|
||||
- int fd = mkstemp (name);
|
||||
+ int fd = create_temp_file ("tst-ungetc.", &name);
|
||||
if (fd == -1)
|
||||
- {
|
||||
- printf ("mkstemp failed: %m\n");
|
||||
- return 1;
|
||||
- }
|
||||
- close (fd);
|
||||
- fp = fopen (name, "w");
|
||||
- assert (fp != NULL)
|
||||
- fputs ("bla", fp);
|
||||
- fclose (fp);
|
||||
- fp = NULL;
|
||||
+ FAIL_EXIT1 ("cannot create temporary file: %m");
|
||||
+ xclose (fd);
|
||||
|
||||
- fp = fopen (name, "r");
|
||||
- assert (fp != NULL);
|
||||
- assert (ungetc ('z', fp) == 'z');
|
||||
- assert (getc (fp) == 'z');
|
||||
- assert (getc (fp) == 'b');
|
||||
- assert (getc (fp) == 'l');
|
||||
- assert (ungetc ('m', fp) == 'm');
|
||||
- assert (getc (fp) == 'm');
|
||||
- assert ((c = getc (fp)) == 'a');
|
||||
- assert (getc (fp) == EOF);
|
||||
- assert (ungetc (c, fp) == c);
|
||||
- assert (feof (fp) == 0);
|
||||
- assert (getc (fp) == c);
|
||||
- assert (getc (fp) == EOF);
|
||||
- fclose (fp);
|
||||
- fp = NULL;
|
||||
+ fp = xfopen (name, "w");
|
||||
+ fputs ("bla", fp);
|
||||
+ xfclose (fp);
|
||||
|
||||
- fp = fopen (name, "r");
|
||||
- assert (fp != NULL);
|
||||
- assert (getc (fp) == 'b');
|
||||
- assert (getc (fp) == 'l');
|
||||
- assert (ungetc ('b', fp) == 'b');
|
||||
- assert (fread (buffer, 1, 64, fp) == 2);
|
||||
- assert (buffer[0] == 'b');
|
||||
- assert (buffer[1] == 'a');
|
||||
+ fp = xfopen (name, "r");
|
||||
+ TEST_VERIFY_EXIT (ungetc ('z', fp) == 'z');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'z');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'b');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'l');
|
||||
+ TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'm');
|
||||
+ TEST_VERIFY_EXIT ((c = getc (fp)) == 'a');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == EOF);
|
||||
+ TEST_VERIFY_EXIT (ungetc (c, fp) == c);
|
||||
+ TEST_VERIFY_EXIT (feof (fp) == 0);
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == c);
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == EOF);
|
||||
+ xfclose (fp);
|
||||
|
||||
-the_end:
|
||||
- if (fp != NULL)
|
||||
- fclose (fp);
|
||||
- unlink (name);
|
||||
+ fp = xfopen (name, "r");
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'b');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'l');
|
||||
+ TEST_VERIFY_EXIT (ungetc ('b', fp) == 'b');
|
||||
+ TEST_VERIFY_EXIT (fread (buffer, 1, 64, fp) == 2);
|
||||
+ TEST_VERIFY_EXIT (buffer[0] == 'b');
|
||||
+ TEST_VERIFY_EXIT (buffer[1] == 'a');
|
||||
+ xfclose (fp);
|
||||
|
||||
- return retval;
|
||||
+ return 0;
|
||||
}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,70 @@
|
||||
commit 70939528c67507f12d6d41423b7fac25153a6dce
|
||||
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Date: Tue Aug 13 21:00:06 2024 -0400
|
||||
|
||||
ungetc: Fix uninitialized read when putting into unused streams [BZ #27821]
|
||||
|
||||
When ungetc is called on an unused stream, the backup buffer is
|
||||
allocated without the main get area being present. This results in
|
||||
every subsequent ungetc (as the stream remains in the backup area)
|
||||
checking uninitialized memory in the backup buffer when trying to put a
|
||||
character back into the stream.
|
||||
|
||||
Avoid comparing the input character with buffer contents when in backup
|
||||
to avoid this uninitialized read. The uninitialized read is harmless in
|
||||
this context since the location is promptly overwritten with the input
|
||||
character, thus fulfilling ungetc functionality.
|
||||
|
||||
Also adjust wording in the manual to drop the paragraph that says glibc
|
||||
cannot do multiple ungetc back to back since with this change, ungetc
|
||||
can actually do this.
|
||||
|
||||
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit cdf0f88f97b0aaceb894cc02b21159d148d7065c)
|
||||
|
||||
diff --git a/libio/genops.c b/libio/genops.c
|
||||
index bc45e60a09437ae5..4f5c6136f3ef1b88 100644
|
||||
--- a/libio/genops.c
|
||||
+++ b/libio/genops.c
|
||||
@@ -635,7 +635,7 @@ _IO_sputbackc (FILE *fp, int c)
|
||||
{
|
||||
int result;
|
||||
|
||||
- if (fp->_IO_read_ptr > fp->_IO_read_base
|
||||
+ if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
|
||||
&& (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
|
||||
{
|
||||
fp->_IO_read_ptr--;
|
||||
diff --git a/manual/stdio.texi b/manual/stdio.texi
|
||||
index 0b31aeff958528c6..393ed9c665792609 100644
|
||||
--- a/manual/stdio.texi
|
||||
+++ b/manual/stdio.texi
|
||||
@@ -1467,11 +1467,9 @@ program; usually @code{ungetc} is used only to unread a character that
|
||||
was just read from the same stream. @Theglibc{} supports this
|
||||
even on files opened in binary mode, but other systems might not.
|
||||
|
||||
-@Theglibc{} only supports one character of pushback---in other
|
||||
-words, it does not work to call @code{ungetc} twice without doing input
|
||||
-in between. Other systems might let you push back multiple characters;
|
||||
-then reading from the stream retrieves the characters in the reverse
|
||||
-order that they were pushed.
|
||||
+@Theglibc{} supports pushing back multiple characters; subsequently
|
||||
+reading from the stream retrieves the characters in the reverse order
|
||||
+that they were pushed.
|
||||
|
||||
Pushing back characters doesn't alter the file; only the internal
|
||||
buffering for the stream is affected. If a file positioning function
|
||||
diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c
|
||||
index 5c808f073419f00b..388b202493ddd586 100644
|
||||
--- a/stdio-common/tst-ungetc.c
|
||||
+++ b/stdio-common/tst-ungetc.c
|
||||
@@ -48,6 +48,8 @@ do_test (void)
|
||||
TEST_VERIFY_EXIT (getc (fp) == 'b');
|
||||
TEST_VERIFY_EXIT (getc (fp) == 'l');
|
||||
TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm');
|
||||
+ TEST_VERIFY_EXIT (ungetc ('n', fp) == 'n');
|
||||
+ TEST_VERIFY_EXIT (getc (fp) == 'n');
|
||||
TEST_VERIFY_EXIT (getc (fp) == 'm');
|
||||
TEST_VERIFY_EXIT ((c = getc (fp)) == 'a');
|
||||
TEST_VERIFY_EXIT (getc (fp) == EOF);
|
@ -0,0 +1,135 @@
|
||||
commit a500b48bd2a6401de442c00f433079d24331dbb6
|
||||
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Date: Tue Aug 13 21:08:49 2024 -0400
|
||||
|
||||
ungetc: Fix backup buffer leak on program exit [BZ #27821]
|
||||
|
||||
If a file descriptor is left unclosed and is cleaned up by _IO_cleanup
|
||||
on exit, its backup buffer remains unfreed, registering as a leak in
|
||||
valgrind. This is not strictly an issue since (1) the program should
|
||||
ideally be closing the stream once it's not in use and (2) the program
|
||||
is about to exit anyway, so keeping the backup buffer around a wee bit
|
||||
longer isn't a real problem. Free it anyway to keep valgrind happy
|
||||
when the streams in question are the standard ones, i.e. stdout, stdin
|
||||
or stderr.
|
||||
|
||||
Also, the _IO_have_backup macro checks for _IO_save_base,
|
||||
which is a roundabout way to check for a backup buffer instead of
|
||||
directly looking for _IO_backup_base. The roundabout check breaks when
|
||||
the main get area has not been used and user pushes a char into the
|
||||
backup buffer with ungetc. Fix this to use the _IO_backup_base
|
||||
directly.
|
||||
|
||||
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit 3e1d8d1d1dca24ae90df2ea826a8916896fc7e77)
|
||||
|
||||
diff --git a/libio/genops.c b/libio/genops.c
|
||||
index 4f5c6136f3ef1b88..bb1d9594ebb60375 100644
|
||||
--- a/libio/genops.c
|
||||
+++ b/libio/genops.c
|
||||
@@ -789,6 +789,12 @@ _IO_unbuffer_all (void)
|
||||
legacy = 1;
|
||||
#endif
|
||||
|
||||
+ /* Free up the backup area if it was ever allocated. */
|
||||
+ if (_IO_have_backup (fp))
|
||||
+ _IO_free_backup_area (fp);
|
||||
+ if (fp->_mode > 0 && _IO_have_wbackup (fp))
|
||||
+ _IO_free_wbackup_area (fp);
|
||||
+
|
||||
if (! (fp->_flags & _IO_UNBUFFERED)
|
||||
/* Iff stream is un-orientated, it wasn't used. */
|
||||
&& (legacy || fp->_mode != 0))
|
||||
diff --git a/libio/libioP.h b/libio/libioP.h
|
||||
index 1af287b19f30fa2a..616253fcd00f04db 100644
|
||||
--- a/libio/libioP.h
|
||||
+++ b/libio/libioP.h
|
||||
@@ -577,8 +577,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW;
|
||||
((__fp)->_wide_data->_IO_write_base \
|
||||
= (__fp)->_wide_data->_IO_write_ptr = __p, \
|
||||
(__fp)->_wide_data->_IO_write_end = (__ep))
|
||||
-#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL)
|
||||
-#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL)
|
||||
+#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL)
|
||||
+#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL)
|
||||
#define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP)
|
||||
#define _IO_have_markers(fp) ((fp)->_markers != NULL)
|
||||
#define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index 159dc472e4c76b9a..b9c38ce6b3b2f43a 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -257,6 +257,7 @@ tests := \
|
||||
tst-swscanf \
|
||||
tst-tmpnam \
|
||||
tst-ungetc \
|
||||
+ tst-ungetc-leak \
|
||||
tst-unlockedio \
|
||||
tst-vfprintf-mbs-prec \
|
||||
tst-vfprintf-user-type \
|
||||
@@ -301,6 +302,7 @@ tests-special += \
|
||||
$(objpfx)tst-printfsz-islongdouble.out \
|
||||
$(objpfx)tst-setvbuf1-cmp.out \
|
||||
$(objpfx)tst-unbputc.out \
|
||||
+ $(objpfx)tst-ungetc-leak-mem.out \
|
||||
$(objpfx)tst-vfprintf-width-prec-mem.out \
|
||||
# tests-special
|
||||
|
||||
@@ -315,6 +317,8 @@ generated += \
|
||||
tst-printf-fp-leak-mem.out \
|
||||
tst-printf-fp-leak.mtrace \
|
||||
tst-scanf-bz27650.mtrace \
|
||||
+ tst-ungetc-leak-mem.out \
|
||||
+ tst-ungetc-leak.mtrace \
|
||||
tst-vfprintf-width-prec-mem.out \
|
||||
tst-vfprintf-width-prec.mtrace \
|
||||
# generated
|
||||
@@ -407,6 +411,9 @@ tst-printf-fp-leak-ENV = \
|
||||
tst-scanf-bz27650-ENV = \
|
||||
MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \
|
||||
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
|
||||
+tst-ungetc-leak-ENV = \
|
||||
+ MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \
|
||||
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
|
||||
|
||||
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
|
||||
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
|
||||
diff --git a/stdio-common/tst-ungetc-leak.c b/stdio-common/tst-ungetc-leak.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..6c5152b43f80b217
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-ungetc-leak.c
|
||||
@@ -0,0 +1,32 @@
|
||||
+/* Test for memory leak with ungetc when stream is unused.
|
||||
+ Copyright The GNU Toolchain Authors.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ mtrace ();
|
||||
+ TEST_COMPARE (ungetc('y', stdin), 'y');
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,83 @@
|
||||
commit cae418638e83bcac4e65d612036edbd58f6e9364
|
||||
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||
Date: Fri Jul 26 13:21:34 2024 +0100
|
||||
|
||||
posix: Use <support/check.h> facilities in tst-truncate and tst-truncate64
|
||||
|
||||
Remove local FAIL macro in favor to FAIL_RET from <support/check.h>,
|
||||
which provides equivalent reporting, with the name of the file of the
|
||||
failure site additionally included, for the tst-truncate-common core
|
||||
shared between the tst-truncate and tst-truncate64 tests.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
(cherry picked from commit fe47595504a55e7bb992f8928533df154b510383)
|
||||
|
||||
diff --git a/posix/tst-truncate-common.c b/posix/tst-truncate-common.c
|
||||
index b774fa46b80412b4..b8c561ffdb2b2903 100644
|
||||
--- a/posix/tst-truncate-common.c
|
||||
+++ b/posix/tst-truncate-common.c
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include <support/check.h>
|
||||
+
|
||||
static void do_prepare (void);
|
||||
#define PREPARE(argc, argv) do_prepare ()
|
||||
static int do_test (void);
|
||||
@@ -42,9 +44,6 @@ do_prepare (void)
|
||||
}
|
||||
}
|
||||
|
||||
-#define FAIL(str) \
|
||||
- do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0)
|
||||
-
|
||||
static int
|
||||
do_test_with_offset (off_t offset)
|
||||
{
|
||||
@@ -54,35 +53,35 @@ do_test_with_offset (off_t offset)
|
||||
memset (buf, 0xcf, sizeof (buf));
|
||||
|
||||
if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf))
|
||||
- FAIL ("write failed");
|
||||
+ FAIL_RET ("write failed");
|
||||
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf)))
|
||||
- FAIL ("initial size wrong");
|
||||
+ FAIL_RET ("initial size wrong");
|
||||
|
||||
if (ftruncate (temp_fd, offset + 800) < 0)
|
||||
- FAIL ("size reduction with ftruncate failed");
|
||||
+ FAIL_RET ("size reduction with ftruncate failed");
|
||||
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
|
||||
- FAIL ("size after reduction with ftruncate is incorrect");
|
||||
+ FAIL_RET ("size after reduction with ftruncate is incorrect");
|
||||
|
||||
/* The following test covers more than POSIX. POSIX does not require
|
||||
that ftruncate() can increase the file size. But we are testing
|
||||
Unix systems. */
|
||||
if (ftruncate (temp_fd, offset + 1200) < 0)
|
||||
- FAIL ("size increate with ftruncate failed");
|
||||
+ FAIL_RET ("size increate with ftruncate failed");
|
||||
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
|
||||
- FAIL ("size after increase is incorrect");
|
||||
+ FAIL_RET ("size after increase is incorrect");
|
||||
|
||||
if (truncate (temp_filename, offset + 800) < 0)
|
||||
- FAIL ("size reduction with truncate failed");
|
||||
+ FAIL_RET ("size reduction with truncate failed");
|
||||
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
|
||||
- FAIL ("size after reduction with truncate incorrect");
|
||||
+ FAIL_RET ("size after reduction with truncate incorrect");
|
||||
|
||||
/* The following test covers more than POSIX. POSIX does not require
|
||||
that truncate() can increase the file size. But we are testing
|
||||
Unix systems. */
|
||||
if (truncate (temp_filename, (offset + 1200)) < 0)
|
||||
- FAIL ("size increase with truncate failed");
|
||||
+ FAIL_RET ("size increase with truncate failed");
|
||||
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
|
||||
- FAIL ("size increase with truncate is incorrect");
|
||||
+ FAIL_RET ("size increase with truncate is incorrect");
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
commit 5ff30b2f75681e1f752eeaad9d48ad249dabe71c
|
||||
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||
Date: Fri Jul 26 13:21:34 2024 +0100
|
||||
|
||||
nptl: Use <support/check.h> facilities in tst-setuid3
|
||||
|
||||
Remove local FAIL macro in favor to FAIL_EXIT1 from <support/check.h>,
|
||||
which provides equivalent reporting, with the name of the file and the
|
||||
line number within of the failure site additionally included. Remove
|
||||
FAIL_ERR altogether and include ": %m" explicitly with the format string
|
||||
supplied to FAIL_EXIT1 as there seems little value to have a separate
|
||||
macro just for this.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
(cherry picked from commit 8c98195af6e6f1ce21743fc26c723e0f7e45bcf2)
|
||||
|
||||
diff --git a/sysdeps/pthread/tst-setuid3.c b/sysdeps/pthread/tst-setuid3.c
|
||||
index 83f42a0ae5b06df5..3845ab03d306cf0f 100644
|
||||
--- a/sysdeps/pthread/tst-setuid3.c
|
||||
+++ b/sysdeps/pthread/tst-setuid3.c
|
||||
@@ -15,24 +15,19 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
-#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include <support/check.h>
|
||||
+
|
||||
/* The test must run under a non-privileged user ID. */
|
||||
static const uid_t test_uid = 1;
|
||||
|
||||
static pthread_barrier_t barrier1;
|
||||
static pthread_barrier_t barrier2;
|
||||
|
||||
-#define FAIL(fmt, ...) \
|
||||
- do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
|
||||
-
|
||||
-#define FAIL_ERR(fmt, ...) \
|
||||
- do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0)
|
||||
-
|
||||
/* True if x is not a successful return code from pthread_barrier_wait. */
|
||||
static inline bool
|
||||
is_invalid_barrier_ret (int x)
|
||||
@@ -45,10 +40,10 @@ thread_func (void *ctx __attribute__ ((unused)))
|
||||
{
|
||||
int ret = pthread_barrier_wait (&barrier1);
|
||||
if (is_invalid_barrier_ret (ret))
|
||||
- FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
|
||||
ret = pthread_barrier_wait (&barrier2);
|
||||
if (is_invalid_barrier_ret (ret))
|
||||
- FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -59,13 +54,13 @@ setuid_failure (int phase)
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
- FAIL ("setuid succeeded unexpectedly in phase %d", phase);
|
||||
+ FAIL_EXIT1 ("setuid succeeded unexpectedly in phase %d", phase);
|
||||
case -1:
|
||||
if (errno != EPERM)
|
||||
- FAIL_ERR ("setuid phase %d", phase);
|
||||
+ FAIL_EXIT1 ("setuid phase %d: %m", phase);
|
||||
break;
|
||||
default:
|
||||
- FAIL ("invalid setuid return value in phase %d: %d", phase, ret);
|
||||
+ FAIL_EXIT1 ("invalid setuid return value in phase %d: %d", phase, ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,42 +69,42 @@ do_test (void)
|
||||
{
|
||||
if (getuid () == 0)
|
||||
if (setuid (test_uid) != 0)
|
||||
- FAIL_ERR ("setuid (%u)", (unsigned) test_uid);
|
||||
+ FAIL_EXIT1 ("setuid (%u): %m", (unsigned) test_uid);
|
||||
if (setuid (getuid ()))
|
||||
- FAIL_ERR ("setuid (%s)", "getuid ()");
|
||||
+ FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
|
||||
setuid_failure (1);
|
||||
|
||||
int ret = pthread_barrier_init (&barrier1, NULL, 2);
|
||||
if (ret != 0)
|
||||
- FAIL ("pthread_barrier_init (barrier1): %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_barrier_init (barrier1): %d", ret);
|
||||
ret = pthread_barrier_init (&barrier2, NULL, 2);
|
||||
if (ret != 0)
|
||||
- FAIL ("pthread_barrier_init (barrier2): %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_barrier_init (barrier2): %d", ret);
|
||||
|
||||
pthread_t thread;
|
||||
ret = pthread_create (&thread, NULL, thread_func, NULL);
|
||||
if (ret != 0)
|
||||
- FAIL ("pthread_create: %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_create: %d", ret);
|
||||
|
||||
/* Ensure that the thread is running properly. */
|
||||
ret = pthread_barrier_wait (&barrier1);
|
||||
if (is_invalid_barrier_ret (ret))
|
||||
- FAIL ("pthread_barrier_wait (barrier1): %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier1): %d", ret);
|
||||
|
||||
setuid_failure (2);
|
||||
|
||||
/* Check success case. */
|
||||
if (setuid (getuid ()) != 0)
|
||||
- FAIL_ERR ("setuid (%s)", "getuid ()");
|
||||
+ FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
|
||||
|
||||
/* Shutdown. */
|
||||
ret = pthread_barrier_wait (&barrier2);
|
||||
if (is_invalid_barrier_ret (ret))
|
||||
- FAIL ("pthread_barrier_wait (barrier2): %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier2): %d", ret);
|
||||
|
||||
ret = pthread_join (thread, NULL);
|
||||
if (ret != 0)
|
||||
- FAIL ("pthread_join: %d", ret);
|
||||
+ FAIL_EXIT1 ("pthread_join: %d", ret);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,499 @@
|
||||
commit 28c4f32f71c4cdd8549842c646819538206ba3a6
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Jul 1 17:42:04 2024 +0200
|
||||
|
||||
elf: Support recursive use of dynamic TLS in interposed malloc
|
||||
|
||||
It turns out that quite a few applications use bundled mallocs that
|
||||
have been built to use global-dynamic TLS (instead of the recommended
|
||||
initial-exec TLS). The previous workaround from
|
||||
commit afe42e935b3ee97bac9a7064157587777259c60e ("elf: Avoid some
|
||||
free (NULL) calls in _dl_update_slotinfo") does not fix all
|
||||
encountered cases unfortunatelly.
|
||||
|
||||
This change avoids the TLS generation update for recursive use
|
||||
of TLS from a malloc that was called during a TLS update. This
|
||||
is possible because an interposed malloc has a fixed module ID and
|
||||
TLS slot. (It cannot be unloaded.) If an initially-loaded module ID
|
||||
is encountered in __tls_get_addr and the dynamic linker is already
|
||||
in the middle of a TLS update, use the outdated DTV, thus avoiding
|
||||
another call into malloc. It's still necessary to update the
|
||||
DTV to the most recent generation, to get out of the slow path,
|
||||
which is why the check for recursion is needed.
|
||||
|
||||
The bookkeeping is done using a global counter instead of per-thread
|
||||
flag because TLS access in the dynamic linker is tricky.
|
||||
|
||||
All this will go away once the dynamic linker stops using malloc
|
||||
for TLS, likely as part of a change that pre-allocates all TLS
|
||||
during pthread_create/dlopen.
|
||||
|
||||
Fixes commit d2123d68275acc0f061e73d5f86ca504e0d5a344 ("elf: Fix slow
|
||||
tls access after dlopen [BZ #19924]").
|
||||
|
||||
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||
(cherry picked from commit 018f0fc3b818d4d1460a4e2384c24802504b1d20)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index a50a988e7362cf3b..d81309321031fcb6 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -443,6 +443,7 @@ tests += \
|
||||
tst-p_align1 \
|
||||
tst-p_align2 \
|
||||
tst-p_align3 \
|
||||
+ tst-recursive-tls \
|
||||
tst-relsort1 \
|
||||
tst-ro-dynamic \
|
||||
tst-rtld-run-static \
|
||||
@@ -877,6 +878,23 @@ modules-names += \
|
||||
tst-null-argv-lib \
|
||||
tst-p_alignmod-base \
|
||||
tst-p_alignmod3 \
|
||||
+ tst-recursive-tlsmallocmod \
|
||||
+ tst-recursive-tlsmod0 \
|
||||
+ tst-recursive-tlsmod1 \
|
||||
+ tst-recursive-tlsmod2 \
|
||||
+ tst-recursive-tlsmod3 \
|
||||
+ tst-recursive-tlsmod4 \
|
||||
+ tst-recursive-tlsmod5 \
|
||||
+ tst-recursive-tlsmod6 \
|
||||
+ tst-recursive-tlsmod7 \
|
||||
+ tst-recursive-tlsmod8 \
|
||||
+ tst-recursive-tlsmod9 \
|
||||
+ tst-recursive-tlsmod10 \
|
||||
+ tst-recursive-tlsmod11 \
|
||||
+ tst-recursive-tlsmod12 \
|
||||
+ tst-recursive-tlsmod13 \
|
||||
+ tst-recursive-tlsmod14 \
|
||||
+ tst-recursive-tlsmod15 \
|
||||
tst-relsort1mod1 \
|
||||
tst-relsort1mod2 \
|
||||
tst-ro-dynamic-mod \
|
||||
@@ -3064,3 +3082,11 @@ CFLAGS-tst-gnu2-tls2mod0.c += -mtls-dialect=$(have-mtls-descriptor)
|
||||
CFLAGS-tst-gnu2-tls2mod1.c += -mtls-dialect=$(have-mtls-descriptor)
|
||||
CFLAGS-tst-gnu2-tls2mod2.c += -mtls-dialect=$(have-mtls-descriptor)
|
||||
endif
|
||||
+
|
||||
+$(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so
|
||||
+# More objects than DTV_SURPLUS, to trigger DTV reallocation.
|
||||
+$(objpfx)tst-recursive-tls.out: \
|
||||
+ $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
|
||||
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
|
||||
+$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
|
||||
+ $(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
|
||||
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
|
||||
index 670dbc42fc2e3334..3d221273f1915f19 100644
|
||||
--- a/elf/dl-tls.c
|
||||
+++ b/elf/dl-tls.c
|
||||
@@ -75,6 +75,31 @@
|
||||
/* Default for dl_tls_static_optional. */
|
||||
#define OPTIONAL_TLS 512
|
||||
|
||||
+/* Used to count the number of threads currently executing dynamic TLS
|
||||
+ updates. Used to avoid recursive malloc calls in __tls_get_addr
|
||||
+ for an interposed malloc that uses global-dynamic TLS (which is not
|
||||
+ recommended); see _dl_tls_allocate_active checks. This could be a
|
||||
+ per-thread flag, but would need TLS access in the dynamic linker. */
|
||||
+unsigned int _dl_tls_threads_in_update;
|
||||
+
|
||||
+static inline void
|
||||
+_dl_tls_allocate_begin (void)
|
||||
+{
|
||||
+ atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, 1);
|
||||
+}
|
||||
+
|
||||
+static inline void
|
||||
+_dl_tls_allocate_end (void)
|
||||
+{
|
||||
+ atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, -1);
|
||||
+}
|
||||
+
|
||||
+static inline bool
|
||||
+_dl_tls_allocate_active (void)
|
||||
+{
|
||||
+ return atomic_load_relaxed (&_dl_tls_threads_in_update) > 0;
|
||||
+}
|
||||
+
|
||||
/* Compute the static TLS surplus based on the namespace count and the
|
||||
TLS space that can be used for optimizations. */
|
||||
static inline int
|
||||
@@ -425,12 +450,18 @@ _dl_allocate_tls_storage (void)
|
||||
size += TLS_PRE_TCB_SIZE;
|
||||
#endif
|
||||
|
||||
- /* Perform the allocation. Reserve space for the required alignment
|
||||
- and the pointer to the original allocation. */
|
||||
+ /* Reserve space for the required alignment and the pointer to the
|
||||
+ original allocation. */
|
||||
size_t alignment = GLRO (dl_tls_static_align);
|
||||
+
|
||||
+ /* Perform the allocation. */
|
||||
+ _dl_tls_allocate_begin ();
|
||||
void *allocated = malloc (size + alignment + sizeof (void *));
|
||||
if (__glibc_unlikely (allocated == NULL))
|
||||
- return NULL;
|
||||
+ {
|
||||
+ _dl_tls_allocate_end ();
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
/* Perform alignment and allocate the DTV. */
|
||||
#if TLS_TCB_AT_TP
|
||||
@@ -466,6 +497,8 @@ _dl_allocate_tls_storage (void)
|
||||
result = allocate_dtv (result);
|
||||
if (result == NULL)
|
||||
free (allocated);
|
||||
+
|
||||
+ _dl_tls_allocate_end ();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -483,6 +516,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
|
||||
size_t newsize = max_modid + DTV_SURPLUS;
|
||||
size_t oldsize = dtv[-1].counter;
|
||||
|
||||
+ _dl_tls_allocate_begin ();
|
||||
if (dtv == GL(dl_initial_dtv))
|
||||
{
|
||||
/* This is the initial dtv that was either statically allocated in
|
||||
@@ -502,6 +536,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
}
|
||||
+ _dl_tls_allocate_end ();
|
||||
|
||||
newp[0].counter = newsize;
|
||||
|
||||
@@ -676,7 +711,9 @@ allocate_dtv_entry (size_t alignment, size_t size)
|
||||
if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
|
||||
{
|
||||
/* The alignment is supported by malloc. */
|
||||
+ _dl_tls_allocate_begin ();
|
||||
void *ptr = malloc (size);
|
||||
+ _dl_tls_allocate_end ();
|
||||
return (struct dtv_pointer) { ptr, ptr };
|
||||
}
|
||||
|
||||
@@ -688,7 +725,10 @@ allocate_dtv_entry (size_t alignment, size_t size)
|
||||
|
||||
/* Perform the allocation. This is the pointer we need to free
|
||||
later. */
|
||||
+ _dl_tls_allocate_begin ();
|
||||
void *start = malloc (alloc_size);
|
||||
+ _dl_tls_allocate_end ();
|
||||
+
|
||||
if (start == NULL)
|
||||
return (struct dtv_pointer) {};
|
||||
|
||||
@@ -826,7 +866,11 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
|
||||
free implementation. Checking here papers over at
|
||||
least some dynamic TLS usage by interposed mallocs. */
|
||||
if (dtv[modid].pointer.to_free != NULL)
|
||||
- free (dtv[modid].pointer.to_free);
|
||||
+ {
|
||||
+ _dl_tls_allocate_begin ();
|
||||
+ free (dtv[modid].pointer.to_free);
|
||||
+ _dl_tls_allocate_end ();
|
||||
+ }
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[modid].pointer.to_free = NULL;
|
||||
|
||||
@@ -956,10 +1000,22 @@ __tls_get_addr (GET_ADDR_ARGS)
|
||||
size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
|
||||
if (__glibc_unlikely (dtv[0].counter != gen))
|
||||
{
|
||||
- /* Update DTV up to the global generation, see CONCURRENCY NOTES
|
||||
- in _dl_update_slotinfo. */
|
||||
- gen = atomic_load_acquire (&GL(dl_tls_generation));
|
||||
- return update_get_addr (GET_ADDR_PARAM, gen);
|
||||
+ if (_dl_tls_allocate_active ()
|
||||
+ && GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
|
||||
+ /* This is a reentrant __tls_get_addr call, but we can
|
||||
+ satisfy it because it's an initially-loaded module ID.
|
||||
+ These TLS slotinfo slots do not change, so the
|
||||
+ out-of-date generation counter does not matter. However,
|
||||
+ if not in a TLS update, still update_get_addr below, to
|
||||
+ get off the slow path eventually. */
|
||||
+ ;
|
||||
+ else
|
||||
+ {
|
||||
+ /* Update DTV up to the global generation, see CONCURRENCY NOTES
|
||||
+ in _dl_update_slotinfo. */
|
||||
+ gen = atomic_load_acquire (&GL(dl_tls_generation));
|
||||
+ return update_get_addr (GET_ADDR_PARAM, gen);
|
||||
+ }
|
||||
}
|
||||
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||
@@ -969,7 +1025,7 @@ __tls_get_addr (GET_ADDR_ARGS)
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
-#endif
|
||||
+#endif /* SHARED */
|
||||
|
||||
|
||||
/* Look up the module's TLS block as for __tls_get_addr,
|
||||
@@ -1018,6 +1074,25 @@ _dl_tls_get_addr_soft (struct link_map *l)
|
||||
return data;
|
||||
}
|
||||
|
||||
+size_t _dl_tls_initial_modid_limit;
|
||||
+
|
||||
+void
|
||||
+_dl_tls_initial_modid_limit_setup (void)
|
||||
+{
|
||||
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
+ size_t idx;
|
||||
+ for (idx = 0; idx < listp->len; ++idx)
|
||||
+ {
|
||||
+ struct link_map *l = listp->slotinfo[idx].map;
|
||||
+ if (l == NULL
|
||||
+ /* The object can be unloaded, so its modid can be
|
||||
+ reassociated. */
|
||||
+ || !(l->l_type == lt_executable || l->l_type == lt_library))
|
||||
+ break;
|
||||
+ }
|
||||
+ _dl_tls_initial_modid_limit = idx;
|
||||
+}
|
||||
+
|
||||
|
||||
void
|
||||
_dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
@@ -1050,9 +1125,11 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
the first slot. */
|
||||
assert (idx == 0);
|
||||
|
||||
+ _dl_tls_allocate_begin ();
|
||||
listp = (struct dtv_slotinfo_list *)
|
||||
malloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
+ _dl_tls_allocate_end ();
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* We ran out of memory while resizing the dtv slotinfo list. */
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index ac4bb236527882db..4b01e9352acd327b 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -788,6 +788,8 @@ init_tls (size_t naudit)
|
||||
_dl_fatal_printf ("\
|
||||
cannot allocate TLS data structures for initial thread\n");
|
||||
|
||||
+ _dl_tls_initial_modid_limit_setup ();
|
||||
+
|
||||
/* Store for detection of the special case by __tls_get_addr
|
||||
so it knows not to pass this dtv to the normal realloc. */
|
||||
GL(dl_initial_dtv) = GET_DTV (tcbp);
|
||||
diff --git a/elf/tst-recursive-tls.c b/elf/tst-recursive-tls.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..716d1f783a67ddc2
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-recursive-tls.c
|
||||
@@ -0,0 +1,60 @@
|
||||
+/* Test with interposed malloc with dynamic TLS.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 <array_length.h>
|
||||
+#include <stdio.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+/* Defined in tst-recursive-tlsmallocmod.so. */
|
||||
+extern __thread unsigned int malloc_subsytem_counter;
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* 16 is large enough to exercise the DTV resizing case. */
|
||||
+ void *handles[16];
|
||||
+
|
||||
+ for (unsigned int i = 0; i < array_length (handles); ++i)
|
||||
+ {
|
||||
+ /* Re-use the TLS slot for module 0. */
|
||||
+ if (i > 0)
|
||||
+ xdlclose (handles[0]);
|
||||
+
|
||||
+ char soname[30];
|
||||
+ snprintf (soname, sizeof (soname), "tst-recursive-tlsmod%u.so", i);
|
||||
+ handles[i] = xdlopen (soname, RTLD_NOW);
|
||||
+
|
||||
+ if (i > 0)
|
||||
+ {
|
||||
+ handles[0] = xdlopen ("tst-recursive-tlsmod0.so", RTLD_NOW);
|
||||
+ int (*fptr) (void) = xdlsym (handles[0], "get_threadvar_0");
|
||||
+ /* May trigger TLS storage allocation using malloc. */
|
||||
+ TEST_COMPARE (fptr (), 0);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (unsigned int i = 0; i < array_length (handles); ++i)
|
||||
+ xdlclose (handles[i]);
|
||||
+
|
||||
+ printf ("info: malloc subsystem calls: %u\n", malloc_subsytem_counter);
|
||||
+ TEST_VERIFY (malloc_subsytem_counter > 0);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-recursive-tlsmallocmod.c b/elf/tst-recursive-tlsmallocmod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..c24e9945d1b6db58
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-recursive-tlsmallocmod.c
|
||||
@@ -0,0 +1,64 @@
|
||||
+/* Interposed malloc with dynamic TLS.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+#include <dlfcn.h>
|
||||
+
|
||||
+__thread unsigned int malloc_subsytem_counter;
|
||||
+
|
||||
+static __typeof (malloc) *malloc_fptr;
|
||||
+static __typeof (free) *free_fptr;
|
||||
+static __typeof (calloc) *calloc_fptr;
|
||||
+static __typeof (realloc) *realloc_fptr;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ malloc_fptr = dlsym (RTLD_NEXT, "malloc");
|
||||
+ free_fptr = dlsym (RTLD_NEXT, "free");
|
||||
+ calloc_fptr = dlsym (RTLD_NEXT, "calloc");
|
||||
+ realloc_fptr = dlsym (RTLD_NEXT, "realloc");
|
||||
+}
|
||||
+
|
||||
+void *
|
||||
+malloc (size_t size)
|
||||
+{
|
||||
+ ++malloc_subsytem_counter;
|
||||
+ return malloc_fptr (size);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+free (void *ptr)
|
||||
+{
|
||||
+ ++malloc_subsytem_counter;
|
||||
+ return free_fptr (ptr);
|
||||
+}
|
||||
+
|
||||
+void *
|
||||
+calloc (size_t a, size_t b)
|
||||
+{
|
||||
+ ++malloc_subsytem_counter;
|
||||
+ return calloc_fptr (a, b);
|
||||
+}
|
||||
+
|
||||
+void *
|
||||
+realloc (void *ptr, size_t size)
|
||||
+{
|
||||
+ ++malloc_subsytem_counter;
|
||||
+ return realloc_fptr (ptr, size);
|
||||
+}
|
||||
diff --git a/elf/tst-recursive-tlsmodN.c b/elf/tst-recursive-tlsmodN.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..bb7592aee6ed347e
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-recursive-tlsmodN.c
|
||||
@@ -0,0 +1,28 @@
|
||||
+/* Test module with global-dynamic TLS. Used to trigger DTV reallocation.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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/>. */
|
||||
+
|
||||
+/* Compiled with VAR and FUNC set via -D. FUNC requires some
|
||||
+ relocation against TLS variable VAR. */
|
||||
+
|
||||
+__thread int VAR;
|
||||
+
|
||||
+int
|
||||
+FUNC (void)
|
||||
+{
|
||||
+ return VAR;
|
||||
+}
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 50f58a60e3f02330..656e8a3fa005021d 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -1256,6 +1256,20 @@ extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid,
|
||||
size_t gen)
|
||||
attribute_hidden;
|
||||
|
||||
+/* The last TLS module ID that is initially loaded, plus 1. TLS
|
||||
+ addresses for modules with IDs lower than that can be obtained from
|
||||
+ the DTV even if its generation is outdated. */
|
||||
+extern size_t _dl_tls_initial_modid_limit attribute_hidden attribute_relro;
|
||||
+
|
||||
+/* Compute _dl_tls_initial_modid_limit. To be called after initial
|
||||
+ relocation. */
|
||||
+void _dl_tls_initial_modid_limit_setup (void) attribute_hidden;
|
||||
+
|
||||
+/* Number of threads currently in a TLS update. This is used to
|
||||
+ detect reentrant __tls_get_addr calls without a per-thread
|
||||
+ flag. */
|
||||
+extern unsigned int _dl_tls_threads_in_update attribute_hidden;
|
||||
+
|
||||
/* Look up the module's TLS block as for __tls_get_addr,
|
||||
but never touch anything. Return null if it's not allocated yet. */
|
||||
extern void *_dl_tls_get_addr_soft (struct link_map *l) attribute_hidden;
|
||||
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
|
||||
index 869023bbba6f5817..b3c1e4fcd7813b8b 100644
|
||||
--- a/sysdeps/x86_64/dl-tls.c
|
||||
+++ b/sysdeps/x86_64/dl-tls.c
|
||||
@@ -41,7 +41,10 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
|
||||
dtv_t *dtv = THREAD_DTV ();
|
||||
|
||||
size_t gen = atomic_load_acquire (&GL(dl_tls_generation));
|
||||
- if (__glibc_unlikely (dtv[0].counter != gen))
|
||||
+ if (__glibc_unlikely (dtv[0].counter != gen)
|
||||
+ /* See comment in __tls_get_addr in elf/dl-tls.c. */
|
||||
+ && !(_dl_tls_allocate_active ()
|
||||
+ && GET_ADDR_MODULE < _dl_tls_initial_modid_limit))
|
||||
return update_get_addr (GET_ADDR_PARAM, gen);
|
||||
|
||||
return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
|
@ -0,0 +1,93 @@
|
||||
commit e3d5d2d3508faeb8545f871a419f4ac46fa16df2
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Aug 1 23:31:23 2024 +0200
|
||||
|
||||
elf: Clarify and invert second argument of _dl_allocate_tls_init
|
||||
|
||||
Also remove an outdated comment: _dl_allocate_tls_init is
|
||||
called as part of pthread_create.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit fe06fb313bddf7e4530056897d4a706606e49377)
|
||||
|
||||
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
|
||||
index 3d221273f1915f19..ecb966d282213131 100644
|
||||
--- a/elf/dl-tls.c
|
||||
+++ b/elf/dl-tls.c
|
||||
@@ -552,9 +552,14 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
|
||||
/* Allocate initial TLS. RESULT should be a non-NULL pointer to storage
|
||||
for the TLS space. The DTV may be resized, and so this function may
|
||||
call malloc to allocate that space. The loader's GL(dl_load_tls_lock)
|
||||
- is taken when manipulating global TLS-related data in the loader. */
|
||||
+ is taken when manipulating global TLS-related data in the loader.
|
||||
+
|
||||
+ If MAIN_THREAD, this is the first call during process
|
||||
+ initialization. In this case, TLS initialization for secondary
|
||||
+ (audit) namespaces is skipped because that has already been handled
|
||||
+ by dlopen. */
|
||||
void *
|
||||
-_dl_allocate_tls_init (void *result, bool init_tls)
|
||||
+_dl_allocate_tls_init (void *result, bool main_thread)
|
||||
{
|
||||
if (result == NULL)
|
||||
/* The memory allocation failed. */
|
||||
@@ -633,7 +638,7 @@ _dl_allocate_tls_init (void *result, bool init_tls)
|
||||
because it would already be set by the audit setup. However,
|
||||
subsequent thread creation would need to follow the default
|
||||
behaviour. */
|
||||
- if (map->l_ns != LM_ID_BASE && !init_tls)
|
||||
+ if (map->l_ns != LM_ID_BASE && main_thread)
|
||||
continue;
|
||||
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size), '\0',
|
||||
@@ -661,7 +666,7 @@ _dl_allocate_tls (void *mem)
|
||||
{
|
||||
return _dl_allocate_tls_init (mem == NULL
|
||||
? _dl_allocate_tls_storage ()
|
||||
- : allocate_dtv (mem), true);
|
||||
+ : allocate_dtv (mem), false);
|
||||
}
|
||||
rtld_hidden_def (_dl_allocate_tls)
|
||||
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index 4b01e9352acd327b..3ca9a11009a74626 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -2337,7 +2337,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
into the main thread's TLS area, which we allocated above.
|
||||
Note: thread-local variables must only be accessed after completing
|
||||
the next step. */
|
||||
- _dl_allocate_tls_init (tcbp, false);
|
||||
+ _dl_allocate_tls_init (tcbp, true);
|
||||
|
||||
/* And finally install it for the main thread. */
|
||||
if (! __rtld_tls_init_tp_called)
|
||||
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
|
||||
index 9ed886573fdc3b7d..d9adb5856cefa533 100644
|
||||
--- a/nptl/allocatestack.c
|
||||
+++ b/nptl/allocatestack.c
|
||||
@@ -141,7 +141,7 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||
|
||||
/* Re-initialize the TLS. */
|
||||
- _dl_allocate_tls_init (TLS_TPADJ (result), true);
|
||||
+ _dl_allocate_tls_init (TLS_TPADJ (result), false);
|
||||
|
||||
return result;
|
||||
}
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 656e8a3fa005021d..154efb0e1985e907 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -1200,10 +1200,8 @@ extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp);
|
||||
|
||||
extern void _dl_allocate_static_tls (struct link_map *map) attribute_hidden;
|
||||
|
||||
-/* These are internal entry points to the two halves of _dl_allocate_tls,
|
||||
- only used within rtld.c itself at startup time. */
|
||||
extern void *_dl_allocate_tls_storage (void) attribute_hidden;
|
||||
-extern void *_dl_allocate_tls_init (void *, bool);
|
||||
+extern void *_dl_allocate_tls_init (void *result, bool main_thread);
|
||||
rtld_hidden_proto (_dl_allocate_tls_init)
|
||||
|
||||
/* True if the TCB has been set up. */
|
@ -0,0 +1,540 @@
|
||||
commit 27a0c6b4902b49efa156e530a63640495c4b1179
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Aug 1 23:31:30 2024 +0200
|
||||
|
||||
elf: Avoid re-initializing already allocated TLS in dlopen (bug 31717)
|
||||
|
||||
The old code used l_init_called as an indicator for whether TLS
|
||||
initialization was complete. However, it is possible that
|
||||
TLS for an object is initialized, written to, and then dlopen
|
||||
for this object is called again, and l_init_called is not true at
|
||||
this point. Previously, this resulted in TLS being initialized
|
||||
twice, discarding any interim writes (technically introducing a
|
||||
use-after-free bug even).
|
||||
|
||||
This commit introduces an explicit per-object flag, l_tls_in_slotinfo.
|
||||
It indicates whether _dl_add_to_slotinfo has been called for this
|
||||
object. This flag is used to avoid double-initialization of TLS.
|
||||
In update_tls_slotinfo, the first_static_tls micro-optimization
|
||||
is removed because preserving the initalization flag for subsequent
|
||||
use by the second loop for static TLS is a bit complicated, and
|
||||
another per-object flag does not seem to be worth it. Furthermore,
|
||||
the l_init_called flag is dropped from the second loop (for static
|
||||
TLS initialization) because l_need_tls_init on its own prevents
|
||||
double-initialization.
|
||||
|
||||
The remaining l_init_called usage in resize_scopes and update_scopes
|
||||
is just an optimization due to the use of scope_has_map, so it is
|
||||
not changed in this commit.
|
||||
|
||||
The isupper check ensures that libc.so.6 is TLS is not reverted.
|
||||
Such a revert happens if l_need_tls_init is not cleared in
|
||||
_dl_allocate_tls_init for the main_thread case, now that
|
||||
l_init_called is not checked anymore in update_tls_slotinfo
|
||||
in elf/dl-open.c.
|
||||
|
||||
Reported-by: Jonathon Anderson <janderson@rice.edu>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit 5097cd344fd243fb8deb6dec96e8073753f962f9)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index d81309321031fcb6..a90305d39b68fb5e 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -414,6 +414,10 @@ tests += \
|
||||
tst-dlmopen4 \
|
||||
tst-dlopen-self \
|
||||
tst-dlopen-tlsmodid \
|
||||
+ tst-dlopen-tlsreinit1 \
|
||||
+ tst-dlopen-tlsreinit2 \
|
||||
+ tst-dlopen-tlsreinit3 \
|
||||
+ tst-dlopen-tlsreinit4 \
|
||||
tst-dlopenfail \
|
||||
tst-dlopenfail-2 \
|
||||
tst-dlopenrpath \
|
||||
@@ -838,6 +842,9 @@ modules-names += \
|
||||
tst-dlmopen-twice-mod1 \
|
||||
tst-dlmopen-twice-mod2 \
|
||||
tst-dlmopen1mod \
|
||||
+ tst-dlopen-tlsreinitmod1 \
|
||||
+ tst-dlopen-tlsreinitmod2 \
|
||||
+ tst-dlopen-tlsreinitmod3 \
|
||||
tst-dlopenfaillinkmod \
|
||||
tst-dlopenfailmod1 \
|
||||
tst-dlopenfailmod2 \
|
||||
@@ -3090,3 +3097,26 @@ $(objpfx)tst-recursive-tls.out: \
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
|
||||
$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
|
||||
$(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
|
||||
+
|
||||
+# Order matters here. The test needs the constructor for
|
||||
+# tst-dlopen-tlsreinitmod2.so to be called first.
|
||||
+LDFLAGS-tst-dlopen-tlsreinitmod1.so = -Wl,--no-as-needed
|
||||
+$(objpfx)tst-dlopen-tlsreinitmod1.so: \
|
||||
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
|
||||
+LDFLAGS-tst-dlopen-tlsreinit2 = -Wl,--no-as-needed
|
||||
+$(objpfx)tst-dlopen-tlsreinit2: \
|
||||
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
|
||||
+LDFLAGS-tst-dlopen-tlsreinit4 = -Wl,--no-as-needed
|
||||
+$(objpfx)tst-dlopen-tlsreinit4: \
|
||||
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
|
||||
+# tst-dlopen-tlsreinitmod2.so is underlinked and refers to
|
||||
+# tst-dlopen-tlsreinitmod3.so. The dependency is provided via
|
||||
+# $(objpfx)tst-dlopen-tlsreinitmod1.so.
|
||||
+tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
|
||||
+$(objpfx)tst-dlopen-tlsreinit.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
|
||||
+ $(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
|
||||
+# Reuse an audit module which provides ample debug logging.
|
||||
+$(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
|
||||
+tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
+$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
|
||||
+tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index c378da16c025f825..8556e7bd2fb0b40e 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -363,17 +363,8 @@ resize_tls_slotinfo (struct link_map *new)
|
||||
{
|
||||
bool any_tls = false;
|
||||
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
- {
|
||||
- struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
-
|
||||
- /* Only add TLS memory if this object is loaded now and
|
||||
- therefore is not yet initialized. */
|
||||
- if (! imap->l_init_called && imap->l_tls_blocksize > 0)
|
||||
- {
|
||||
- _dl_add_to_slotinfo (imap, false);
|
||||
- any_tls = true;
|
||||
- }
|
||||
- }
|
||||
+ if (_dl_add_to_slotinfo (new->l_searchlist.r_list[i], false))
|
||||
+ any_tls = true;
|
||||
return any_tls;
|
||||
}
|
||||
|
||||
@@ -383,22 +374,8 @@ resize_tls_slotinfo (struct link_map *new)
|
||||
static void
|
||||
update_tls_slotinfo (struct link_map *new)
|
||||
{
|
||||
- unsigned int first_static_tls = new->l_searchlist.r_nlist;
|
||||
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
- {
|
||||
- struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
-
|
||||
- /* Only add TLS memory if this object is loaded now and
|
||||
- therefore is not yet initialized. */
|
||||
- if (! imap->l_init_called && imap->l_tls_blocksize > 0)
|
||||
- {
|
||||
- _dl_add_to_slotinfo (imap, true);
|
||||
-
|
||||
- if (imap->l_need_tls_init
|
||||
- && first_static_tls == new->l_searchlist.r_nlist)
|
||||
- first_static_tls = i;
|
||||
- }
|
||||
- }
|
||||
+ _dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
|
||||
|
||||
size_t newgen = GL(dl_tls_generation) + 1;
|
||||
if (__glibc_unlikely (newgen == 0))
|
||||
@@ -410,13 +387,11 @@ TLS generation counter wrapped! Please report this."));
|
||||
/* We need a second pass for static tls data, because
|
||||
_dl_update_slotinfo must not be run while calls to
|
||||
_dl_add_to_slotinfo are still pending. */
|
||||
- for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
{
|
||||
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
|
||||
- if (imap->l_need_tls_init
|
||||
- && ! imap->l_init_called
|
||||
- && imap->l_tls_blocksize > 0)
|
||||
+ if (imap->l_need_tls_init && imap->l_tls_blocksize > 0)
|
||||
{
|
||||
/* For static TLS we have to allocate the memory here and
|
||||
now, but we can delay updating the DTV. */
|
||||
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
|
||||
index ecb966d282213131..3d529b722cb271d9 100644
|
||||
--- a/elf/dl-tls.c
|
||||
+++ b/elf/dl-tls.c
|
||||
@@ -632,17 +632,21 @@ _dl_allocate_tls_init (void *result, bool main_thread)
|
||||
some platforms use in static programs requires it. */
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
|
||||
- /* Copy the initialization image and clear the BSS part. For
|
||||
- audit modules or dependencies with initial-exec TLS, we can not
|
||||
- set the initial TLS image on default loader initialization
|
||||
- because it would already be set by the audit setup. However,
|
||||
- subsequent thread creation would need to follow the default
|
||||
- behaviour. */
|
||||
+ /* Copy the initialization image and clear the BSS part.
|
||||
+ For audit modules or dependencies with initial-exec TLS,
|
||||
+ we can not set the initial TLS image on default loader
|
||||
+ initialization because it would already be set by the
|
||||
+ audit setup, which uses the dlopen code and already
|
||||
+ clears l_need_tls_init. Calls with !main_thread from
|
||||
+ pthread_create need to initialze TLS for the current
|
||||
+ thread regardless of namespace. */
|
||||
if (map->l_ns != LM_ID_BASE && main_thread)
|
||||
continue;
|
||||
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size), '\0',
|
||||
map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
+ if (main_thread)
|
||||
+ map->l_need_tls_init = 0;
|
||||
}
|
||||
|
||||
total += cnt;
|
||||
@@ -1099,9 +1103,32 @@ _dl_tls_initial_modid_limit_setup (void)
|
||||
}
|
||||
|
||||
|
||||
-void
|
||||
+/* Add module to slot information data. If DO_ADD is false, only the
|
||||
+ required memory is allocated. Must be called with
|
||||
+ GL (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.
|
||||
+
|
||||
+ Return false if L has already been added to the slotinfo data, or
|
||||
+ if L has no TLS data. If the returned value is true, L has been
|
||||
+ added with this call (DO_ADD), or has been added in a previous call
|
||||
+ (!DO_ADD).
|
||||
+
|
||||
+ The expected usage is as follows: Call _dl_add_to_slotinfo for
|
||||
+ several link maps with DO_ADD set to false, and record if any calls
|
||||
+ result in a true result. If there was a true result, call
|
||||
+ _dl_add_to_slotinfo again, this time with DO_ADD set to true. (For
|
||||
+ simplicity, it's possible to call the function for link maps where
|
||||
+ the previous result was false.) The return value from the second
|
||||
+ round of calls can be ignored. If there was true result initially,
|
||||
+ call _dl_update_slotinfo to update the TLS generation counter. */
|
||||
+bool
|
||||
_dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
{
|
||||
+ if (l->l_tls_blocksize == 0 || l->l_tls_in_slotinfo)
|
||||
+ return false;
|
||||
+
|
||||
/* Now that we know the object is loaded successfully add
|
||||
modules containing TLS data to the dtv info table. We
|
||||
might have to increase its size. */
|
||||
@@ -1157,7 +1184,10 @@ cannot create TLS data structures"));
|
||||
atomic_store_relaxed (&listp->slotinfo[idx].map, l);
|
||||
atomic_store_relaxed (&listp->slotinfo[idx].gen,
|
||||
GL(dl_tls_generation) + 1);
|
||||
+ l->l_tls_in_slotinfo = true;
|
||||
}
|
||||
+
|
||||
+ return true;
|
||||
}
|
||||
|
||||
#if PTHREAD_IN_LIBC
|
||||
diff --git a/elf/tst-dlopen-tlsreinit1.c b/elf/tst-dlopen-tlsreinit1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..2016b9b0c646a11d
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinit1.c
|
||||
@@ -0,0 +1,40 @@
|
||||
+/* Test that dlopen preserves already accessed TLS (bug 31717).
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 <stdbool.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <ctype.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ void *handle = xdlopen ("tst-dlopen-tlsreinitmod1.so", RTLD_NOW);
|
||||
+
|
||||
+ bool *tlsreinitmod3_tested = xdlsym (handle, "tlsreinitmod3_tested");
|
||||
+ TEST_VERIFY (*tlsreinitmod3_tested);
|
||||
+
|
||||
+ xdlclose (handle);
|
||||
+
|
||||
+ /* This crashes if the libc.so.6 TLS image has been reverted. */
|
||||
+ TEST_VERIFY (!isupper ('@'));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopen-tlsreinit2.c b/elf/tst-dlopen-tlsreinit2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..90ad2c7713776b4d
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinit2.c
|
||||
@@ -0,0 +1,39 @@
|
||||
+/* Test that dlopen preserves already accessed TLS (bug 31717).
|
||||
+ Variant with initially-linked modules.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 <ctype.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Defined in tst-dlopen-tlsreinitmod3.so. */
|
||||
+ extern bool tlsreinitmod3_tested;
|
||||
+ TEST_VERIFY (tlsreinitmod3_tested);
|
||||
+
|
||||
+ /* This crashes if the libc.so.6 TLS image has been reverted. */
|
||||
+ TEST_VERIFY (!isupper ('@'));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopen-tlsreinit3.c b/elf/tst-dlopen-tlsreinit3.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..79bd585afff66d0b
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinit3.c
|
||||
@@ -0,0 +1,2 @@
|
||||
+/* Same code, but run with LD_AUDIT=tst-auditmod1.so. */
|
||||
+#include "tst-dlopen-tlsreinit1.c"
|
||||
diff --git a/elf/tst-dlopen-tlsreinit4.c b/elf/tst-dlopen-tlsreinit4.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..344c9211abe553e6
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinit4.c
|
||||
@@ -0,0 +1,2 @@
|
||||
+/* Same code, but run with LD_AUDIT=tst-auditmod1.so. */
|
||||
+#include "tst-dlopen-tlsreinit2.c"
|
||||
diff --git a/elf/tst-dlopen-tlsreinitmod1.c b/elf/tst-dlopen-tlsreinitmod1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..354cc3de5131423d
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinitmod1.c
|
||||
@@ -0,0 +1,20 @@
|
||||
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 1.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* This module triggers loading of tst-dlopen-tlsreinitmod2.so and
|
||||
+ tst-dlopen-tlsreinitmod3.so. */
|
||||
diff --git a/elf/tst-dlopen-tlsreinitmod2.c b/elf/tst-dlopen-tlsreinitmod2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..677e69bd35e57dfa
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinitmod2.c
|
||||
@@ -0,0 +1,30 @@
|
||||
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 2.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+/* Defined in tst-dlopen-tlsreinitmod3.so. This an underlinked symbol
|
||||
+ dependency. */
|
||||
+extern void call_tlsreinitmod3 (void);
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+tlsreinitmod2_init (void)
|
||||
+{
|
||||
+ puts ("info: constructor of tst-dlopen-tlsreinitmod2.so invoked");
|
||||
+ call_tlsreinitmod3 ();
|
||||
+}
|
||||
diff --git a/elf/tst-dlopen-tlsreinitmod3.c b/elf/tst-dlopen-tlsreinitmod3.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..ef769c51313a234f
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-tlsreinitmod3.c
|
||||
@@ -0,0 +1,102 @@
|
||||
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 3.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <dlfcn.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdio.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Used to verify from the main program that the test ran. */
|
||||
+bool tlsreinitmod3_tested;
|
||||
+
|
||||
+/* This TLS variable must not revert back to the initial state after
|
||||
+ dlopen. */
|
||||
+static __thread int tlsreinitmod3_state = 1;
|
||||
+
|
||||
+/* Set from the ELF constructor during dlopen. */
|
||||
+static bool tlsreinitmod3_constructed;
|
||||
+
|
||||
+/* Second half of test, behind a compiler barrier. The compiler
|
||||
+ barrier is necessary to prevent carrying over TLS address
|
||||
+ information from call_tlsreinitmod3 to call_tlsreinitmod3_tail. */
|
||||
+void call_tlsreinitmod3_tail (void *self) __attribute__ ((weak));
|
||||
+
|
||||
+/* Called from tst-dlopen-tlsreinitmod2.so. */
|
||||
+void
|
||||
+call_tlsreinitmod3 (void)
|
||||
+{
|
||||
+ printf ("info: call_tlsreinitmod3 invoked (state=%d)\n",
|
||||
+ tlsreinitmod3_state);
|
||||
+
|
||||
+ if (tlsreinitmod3_constructed)
|
||||
+ {
|
||||
+ puts ("error: call_tlsreinitmod3 called after ELF constructor");
|
||||
+ fflush (stdout);
|
||||
+ /* Cannot rely on test harness due to dynamic linking. */
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+
|
||||
+ tlsreinitmod3_state = 2;
|
||||
+
|
||||
+ /* Self-dlopen. This will run the ELF constructor. */
|
||||
+ void *self = dlopen ("tst-dlopen-tlsreinitmod3.so", RTLD_NOW);
|
||||
+ if (self == NULL)
|
||||
+ {
|
||||
+ printf ("error: dlopen: %s\n", dlerror ());
|
||||
+ fflush (stdout);
|
||||
+ /* Cannot rely on test harness due to dynamic linking. */
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+
|
||||
+ call_tlsreinitmod3_tail (self);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+call_tlsreinitmod3_tail (void *self)
|
||||
+{
|
||||
+ printf ("info: dlopen returned in tlsreinitmod3 (state=%d)\n",
|
||||
+ tlsreinitmod3_state);
|
||||
+
|
||||
+ if (!tlsreinitmod3_constructed)
|
||||
+ {
|
||||
+ puts ("error: dlopen did not call tlsreinitmod3 ELF constructor");
|
||||
+ fflush (stdout);
|
||||
+ /* Cannot rely on test harness due to dynamic linking. */
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+
|
||||
+ if (tlsreinitmod3_state != 2)
|
||||
+ {
|
||||
+ puts ("error: TLS state reverted in tlsreinitmod3");
|
||||
+ fflush (stdout);
|
||||
+ /* Cannot rely on test harness due to dynamic linking. */
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+
|
||||
+ dlclose (self);
|
||||
+
|
||||
+ /* Signal test completion to the main program. */
|
||||
+ tlsreinitmod3_tested = true;
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+tlsreinitmod3_init (void)
|
||||
+{
|
||||
+ puts ("info: constructor of tst-dlopen-tlsreinitmod3.so invoked");
|
||||
+ tlsreinitmod3_constructed = true;
|
||||
+}
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index cb0d7d8e2fc32687..5ed445d5a6cdf12d 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -212,6 +212,7 @@ struct link_map
|
||||
unsigned int l_find_object_processed:1; /* Zero if _dl_find_object_update
|
||||
needs to process this
|
||||
lt_library map. */
|
||||
+ unsigned int l_tls_in_slotinfo:1; /* TLS slotinfo updated in dlopen. */
|
||||
|
||||
/* NODELETE status of the map. Only valid for maps of type
|
||||
lt_loaded. Lazy binding sets l_nodelete_active directly,
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 154efb0e1985e907..259ce2e7d6e8ff31 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -1239,13 +1239,7 @@ extern void *_dl_open (const char *name, int mode, const void *caller,
|
||||
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_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. */
|
||||
-extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
+extern bool _dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
attribute_hidden;
|
||||
|
||||
/* Update slot information data for at least the generation of the
|
@ -0,0 +1,27 @@
|
||||
commit 7f5027995f45337a3fc4bb6d0b2039ee1e685f2e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Sep 9 21:10:23 2024 +0200
|
||||
|
||||
elf: Fix tst-dlopen-tlsreinit1.out test dependency
|
||||
|
||||
Fixes commit 5097cd344fd243fb8deb6dec96e8073753f962f9
|
||||
("elf: Avoid re-initializing already allocated TLS in dlopen
|
||||
(bug 31717)").
|
||||
|
||||
Reported-by: Patsy Griffin <patsy@redhat.com>
|
||||
Reviewed-by: Patsy Griffin <patsy@redhat.com>
|
||||
(cherry picked from commit e82a7cb1622bff08d8e3a144d7c5516a088f1cbc)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index a90305d39b68fb5e..8a5678aa63736812 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -3113,7 +3113,7 @@ $(objpfx)tst-dlopen-tlsreinit4: \
|
||||
# tst-dlopen-tlsreinitmod3.so. The dependency is provided via
|
||||
# $(objpfx)tst-dlopen-tlsreinitmod1.so.
|
||||
tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
|
||||
-$(objpfx)tst-dlopen-tlsreinit.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
|
||||
+$(objpfx)tst-dlopen-tlsreinit1.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
|
||||
$(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
|
||||
# Reuse an audit module which provides ample debug logging.
|
||||
$(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
|
@ -0,0 +1,140 @@
|
||||
commit 4e382ce01cce1ef2ab8548dc1dda2ad3046662d8
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 10 12:40:27 2024 +0200
|
||||
|
||||
debug: Fix read error handling in pcprofiledump
|
||||
|
||||
The reading loops did not check for read failures. Addresses
|
||||
a static analysis report.
|
||||
|
||||
Manually tested by compiling a program with the GCC's
|
||||
-finstrument-functions option, running it with
|
||||
“LD_PRELOAD=debug/libpcprofile.so PCPROFILE_OUTPUT=output-file”,
|
||||
and reviewing the output of “debug/pcprofiledump output-file”.
|
||||
|
||||
(cherry picked from commit 89b088bf70c651c231bf27e644270d093b8f144a)
|
||||
|
||||
diff --git a/debug/pcprofiledump.c b/debug/pcprofiledump.c
|
||||
index 049a9c2744df739a..94530f0cf92f0652 100644
|
||||
--- a/debug/pcprofiledump.c
|
||||
+++ b/debug/pcprofiledump.c
|
||||
@@ -75,6 +75,44 @@ static struct argp argp =
|
||||
options, parse_opt, args_doc, doc, NULL, more_help
|
||||
};
|
||||
|
||||
+/* Try to read SIZE bytes from FD and store them on BUF. Terminate
|
||||
+ the process upon read error. Also terminate the process if less
|
||||
+ than SIZE bytes are remaining in the file. If !IN_HEADER, do not
|
||||
+ terminate the process if the end of the file is encountered
|
||||
+ immediately, before any bytes are read.
|
||||
+
|
||||
+ Returns true if SIZE bytes have been read, and false if no bytes
|
||||
+ have been read due to an end-of-file condition. */
|
||||
+static bool
|
||||
+read_exactly (int fd, void *buffer, size_t size, bool in_header)
|
||||
+{
|
||||
+ char *p = buffer;
|
||||
+ char *end = p + size;
|
||||
+ while (p < end)
|
||||
+ {
|
||||
+ ssize_t ret = TEMP_FAILURE_RETRY (read (fd, p, end - p));
|
||||
+ if (ret < 0)
|
||||
+ {
|
||||
+ if (in_header)
|
||||
+ error (EXIT_FAILURE, errno, _("cannot read header"));
|
||||
+ else
|
||||
+ error (EXIT_FAILURE, errno, _("cannot read pointer pair"));
|
||||
+ }
|
||||
+ if (ret == 0)
|
||||
+ {
|
||||
+ if (p == buffer && !in_header)
|
||||
+ /* Nothing has been read. */
|
||||
+ return false;
|
||||
+ if (in_header)
|
||||
+ error (EXIT_FAILURE, 0, _("unexpected end of file in header"));
|
||||
+ else
|
||||
+ error (EXIT_FAILURE, 0,
|
||||
+ _("unexpected end of file in pointer pair"));
|
||||
+ }
|
||||
+ p += ret;
|
||||
+ }
|
||||
+ return true;
|
||||
+}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
@@ -110,8 +148,7 @@ main (int argc, char *argv[])
|
||||
/* Read the first 4-byte word. It contains the information about
|
||||
the word size and the endianness. */
|
||||
uint32_t word;
|
||||
- if (TEMP_FAILURE_RETRY (read (fd, &word, 4)) != 4)
|
||||
- error (EXIT_FAILURE, errno, _("cannot read header"));
|
||||
+ read_exactly (fd, &word, sizeof (word), true);
|
||||
|
||||
/* Check whether we have to swap the byte order. */
|
||||
int must_swap = (word & 0x0fffffff) == bswap_32 (0xdeb00000);
|
||||
@@ -121,56 +158,30 @@ main (int argc, char *argv[])
|
||||
/* We have two loops, one for 32 bit pointers, one for 64 bit pointers. */
|
||||
if (word == 0xdeb00004)
|
||||
{
|
||||
- union
|
||||
- {
|
||||
- uint32_t ptrs[2];
|
||||
- char bytes[8];
|
||||
- } pair;
|
||||
+ uint32_t ptrs[2];
|
||||
|
||||
while (1)
|
||||
{
|
||||
- size_t len = sizeof (pair);
|
||||
- size_t n;
|
||||
-
|
||||
- while (len > 0
|
||||
- && (n = TEMP_FAILURE_RETRY (read (fd, &pair.bytes[8 - len],
|
||||
- len))) != 0)
|
||||
- len -= n;
|
||||
-
|
||||
- if (len != 0)
|
||||
- /* Nothing to read. */
|
||||
+ if (!read_exactly (fd, ptrs, sizeof (ptrs), false))
|
||||
break;
|
||||
|
||||
printf ("this = %#010" PRIx32 ", caller = %#010" PRIx32 "\n",
|
||||
- must_swap ? bswap_32 (pair.ptrs[0]) : pair.ptrs[0],
|
||||
- must_swap ? bswap_32 (pair.ptrs[1]) : pair.ptrs[1]);
|
||||
+ must_swap ? bswap_32 (ptrs[0]) : ptrs[0],
|
||||
+ must_swap ? bswap_32 (ptrs[1]) : ptrs[1]);
|
||||
}
|
||||
}
|
||||
else if (word == 0xdeb00008)
|
||||
{
|
||||
- union
|
||||
- {
|
||||
- uint64_t ptrs[2];
|
||||
- char bytes[16];
|
||||
- } pair;
|
||||
+ uint64_t ptrs[2];
|
||||
|
||||
while (1)
|
||||
{
|
||||
- size_t len = sizeof (pair);
|
||||
- size_t n;
|
||||
-
|
||||
- while (len > 0
|
||||
- && (n = TEMP_FAILURE_RETRY (read (fd, &pair.bytes[8 - len],
|
||||
- len))) != 0)
|
||||
- len -= n;
|
||||
-
|
||||
- if (len != 0)
|
||||
- /* Nothing to read. */
|
||||
+ if (!read_exactly (fd, ptrs, sizeof (ptrs), false))
|
||||
break;
|
||||
|
||||
printf ("this = %#018" PRIx64 ", caller = %#018" PRIx64 "\n",
|
||||
- must_swap ? bswap_64 (pair.ptrs[0]) : pair.ptrs[0],
|
||||
- must_swap ? bswap_64 (pair.ptrs[1]) : pair.ptrs[1]);
|
||||
+ must_swap ? bswap_64 (ptrs[0]) : ptrs[0],
|
||||
+ must_swap ? bswap_64 (ptrs[1]) : ptrs[1]);
|
||||
}
|
||||
}
|
||||
else
|
@ -0,0 +1,28 @@
|
||||
commit 84f6bfce2c37e32b9888321fc3131ffbbe6deeba
|
||||
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Date: Tue Sep 3 14:58:33 2024 -0400
|
||||
|
||||
libio: Attempt wide backup free only for non-legacy code
|
||||
|
||||
_wide_data and _mode are not available in legacy code, so do not attempt
|
||||
to free the wide backup buffer in legacy code.
|
||||
|
||||
Resolves: BZ #32137 and BZ #27821
|
||||
|
||||
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
(cherry picked from commit ae4d44b1d501421ad9a3af95279b8f4d1546f1ce)
|
||||
|
||||
diff --git a/libio/genops.c b/libio/genops.c
|
||||
index bb1d9594ebb60375..02292beed9bc3668 100644
|
||||
--- a/libio/genops.c
|
||||
+++ b/libio/genops.c
|
||||
@@ -792,7 +792,7 @@ _IO_unbuffer_all (void)
|
||||
/* Free up the backup area if it was ever allocated. */
|
||||
if (_IO_have_backup (fp))
|
||||
_IO_free_backup_area (fp);
|
||||
- if (fp->_mode > 0 && _IO_have_wbackup (fp))
|
||||
+ if (!legacy && fp->_mode > 0 && _IO_have_wbackup (fp))
|
||||
_IO_free_wbackup_area (fp);
|
||||
|
||||
if (! (fp->_flags & _IO_UNBUFFERED)
|
@ -0,0 +1,275 @@
|
||||
commit 373aab3e52e1c764cf8d86ae14bc4b14e064d623
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
Date: Wed Sep 25 15:51:23 2024 +0200
|
||||
|
||||
stdio-common: Add new test for fdopen
|
||||
|
||||
This commit adds fdopen test with all modes.
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
(cherry picked from commit 1d72fa3cfa046f7293421a7e58f2a272474ea901)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index b9c38ce6b3b2f43a..5f3bd4662340eee9 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -206,6 +206,7 @@ tests := \
|
||||
tst-cookie \
|
||||
tst-dprintf-length \
|
||||
tst-fdopen \
|
||||
+ tst-fdopen2 \
|
||||
tst-ferror \
|
||||
tst-fgets \
|
||||
tst-fileno \
|
||||
diff --git a/stdio-common/tst-fdopen2.c b/stdio-common/tst-fdopen2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0c6625f25853aed5
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-fdopen2.c
|
||||
@@ -0,0 +1,246 @@
|
||||
+/* Test the fdopen function.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <support/temp_file.h>
|
||||
+
|
||||
+char *tmp_dir;
|
||||
+char *path_to_file;
|
||||
+
|
||||
+void
|
||||
+prepare_tmp_dir (void)
|
||||
+{
|
||||
+ tmp_dir = support_create_temp_directory ("tst-fdopen2");
|
||||
+ path_to_file = xasprintf ("%s/tst-fdopen2.txt", tmp_dir);
|
||||
+}
|
||||
+
|
||||
+/* open temp file descriptor with mode. */
|
||||
+int
|
||||
+open_tmp_fd (int mode)
|
||||
+{
|
||||
+ int fd = xopen (path_to_file, mode, 0644);
|
||||
+ return fd;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* close and remove temp file with close. */
|
||||
+void
|
||||
+close_tmp_fd (int fd)
|
||||
+{
|
||||
+ xclose (fd);
|
||||
+ xunlink (path_to_file);
|
||||
+}
|
||||
+
|
||||
+/* close and remove temp file with fclose. */
|
||||
+void
|
||||
+close_tmp_fp (FILE *fp)
|
||||
+{
|
||||
+ fclose (fp);
|
||||
+ xunlink (path_to_file);
|
||||
+}
|
||||
+
|
||||
+/* test "w" fdopen mode. */
|
||||
+void
|
||||
+do_test_fdopen_w (void)
|
||||
+{
|
||||
+ int fd, ret;
|
||||
+ FILE *fp;
|
||||
+ fd = open_tmp_fd (O_WRONLY | O_CREAT | O_TRUNC);
|
||||
+
|
||||
+ /* test mode mismatch. */
|
||||
+ fp = fdopen (fd, "r");
|
||||
+ if (fp != NULL || errno != EINVAL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, r) should fail with EINVAL: %m", fd);
|
||||
+ }
|
||||
+
|
||||
+ fp = fdopen (fd, "w");
|
||||
+ if (fp == NULL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, w): %m", fd);
|
||||
+ }
|
||||
+
|
||||
+ const void *buf = "AAAA";
|
||||
+ ret = fwrite (buf, 1, 4, fp);
|
||||
+ if (ret != 4)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fwrite (): %m");
|
||||
+ }
|
||||
+
|
||||
+ unsigned char buf2[4];
|
||||
+ rewind (fp);
|
||||
+ clearerr (fp);
|
||||
+ /* fread should fail in "w" mode */
|
||||
+ ret = fread (buf2, 1, 4, fp);
|
||||
+ if (ret != 0 || ferror (fp) == 0)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fread should fail in \"w\" mode");
|
||||
+ }
|
||||
+
|
||||
+ fclose (fp);
|
||||
+}
|
||||
+
|
||||
+/* test "r" fdopen mode. */
|
||||
+void
|
||||
+do_test_fdopen_r (void)
|
||||
+{
|
||||
+ int fd, ret;
|
||||
+ FILE *fp;
|
||||
+ fd = open_tmp_fd (O_RDONLY);
|
||||
+
|
||||
+ /* test mode mismatch. */
|
||||
+ fp = fdopen (fd, "w");
|
||||
+ if (fp != NULL || errno != EINVAL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, w) should fail with EINVAL: %m", fd);
|
||||
+ }
|
||||
+
|
||||
+ fp = fdopen (fd, "r");
|
||||
+ if (fp == NULL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, w): %m", fd);
|
||||
+ }
|
||||
+
|
||||
+ const void *buf = "BBBB";
|
||||
+ /* fwrite should fail in "r" mode. */
|
||||
+ ret = fwrite (buf, 1, 4, fp);
|
||||
+ if (ret != 0 || ferror (fp) == 0)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fwrite should fail in \"r\" mode");
|
||||
+ }
|
||||
+
|
||||
+ unsigned char buf2[4];
|
||||
+ ret = fread (buf2, 1, 4, fp);
|
||||
+ if (ret != 4)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fread (): %m");
|
||||
+ }
|
||||
+
|
||||
+ fclose (fp);
|
||||
+}
|
||||
+
|
||||
+/* test "a" fdopen mode. */
|
||||
+void
|
||||
+do_test_fdopen_a (void)
|
||||
+{
|
||||
+ int fd, ret;
|
||||
+ FILE *fp;
|
||||
+ fd = open_tmp_fd (O_WRONLY | O_CREAT | O_APPEND);
|
||||
+
|
||||
+ /* test mode mismatch. */
|
||||
+ fp = fdopen (fd, "r+");
|
||||
+ if (fp != NULL || errno != EINVAL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, \"r+\") should fail with EINVAL: %m", fd);
|
||||
+ }
|
||||
+
|
||||
+ fp = fdopen (fd, "a");
|
||||
+ if (fp == NULL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, w): %m", fd);
|
||||
+ }
|
||||
+
|
||||
+ const void *buf = "CCCC";
|
||||
+ ret = fwrite (buf, 1, 4, fp);
|
||||
+ if (ret != 4)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fwrite (): %m");
|
||||
+ }
|
||||
+
|
||||
+ /* fread should fail in "a" mode. */
|
||||
+ unsigned char buf2[4];
|
||||
+ clearerr (fp);
|
||||
+ ret = fread (buf2, 1, 4, fp);
|
||||
+ if (ret != 0 || ferror (fp) == 0)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fread should fail \"a\" mode");
|
||||
+ }
|
||||
+
|
||||
+ fclose (fp);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+do_test_fdopen_mode (int mode, const char *fmode)
|
||||
+{
|
||||
+ int fd, ret;
|
||||
+ FILE *fp;
|
||||
+ fd = open_tmp_fd (mode);
|
||||
+
|
||||
+ fp = fdopen (fd, fmode);
|
||||
+ if (fp == NULL)
|
||||
+ {
|
||||
+ close_tmp_fd (fd);
|
||||
+ FAIL_EXIT1 ("fdopen (%d, %s): %m", fd, fmode);
|
||||
+ }
|
||||
+
|
||||
+ const void *buf = "EEEE";
|
||||
+ ret = fwrite (buf, 1, 4, fp);
|
||||
+ if (ret != 4)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fwrite () in mode:%s returns %d: %m", fmode, ret);
|
||||
+ }
|
||||
+
|
||||
+ rewind (fp);
|
||||
+ unsigned char buf2[4];
|
||||
+ ret = fread (buf2, 1, 4, fp);
|
||||
+ if (ret != 4)
|
||||
+ {
|
||||
+ close_tmp_fp (fp);
|
||||
+ FAIL_EXIT1 ("fread () in mode:%s returns %d: %m", fmode, ret);
|
||||
+ }
|
||||
+
|
||||
+ fclose (fp);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+
|
||||
+ prepare_tmp_dir ();
|
||||
+
|
||||
+ do_test_fdopen_w ();
|
||||
+ do_test_fdopen_r ();
|
||||
+ do_test_fdopen_a ();
|
||||
+
|
||||
+ /* test r+ w+ a+ fdopen modes. */
|
||||
+ do_test_fdopen_mode (O_RDWR, "r+");
|
||||
+ do_test_fdopen_mode (O_RDWR | O_CREAT | O_TRUNC, "w+");
|
||||
+ do_test_fdopen_mode (O_RDWR | O_CREAT | O_APPEND, "a+");
|
||||
+ xunlink (path_to_file);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,165 @@
|
||||
commit d8b4fc3653ca08912a6dec57a3ba36a2db779488
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Tue Sep 24 14:06:22 2024 +0000
|
||||
|
||||
Add tests of fread
|
||||
|
||||
There seem to be no glibc tests specifically for the fread function.
|
||||
Add basic tests of that function.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit d14c977c65aac7db35bb59380ef99d6582c4f930)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index 5f3bd4662340eee9..c822434293b7e809 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -216,6 +216,7 @@ tests := \
|
||||
tst-fmemopen4 \
|
||||
tst-fphex \
|
||||
tst-fphex-wide \
|
||||
+ tst-fread \
|
||||
tst-fseek \
|
||||
tst-fwrite \
|
||||
tst-gets \
|
||||
diff --git a/stdio-common/tst-fread.c b/stdio-common/tst-fread.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..4d9a7895f66a7980
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-fread.c
|
||||
@@ -0,0 +1,134 @@
|
||||
+/* Test fread.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char *temp_dir = support_create_temp_directory ("tst-fread");
|
||||
+ char *file1 = xasprintf ("%s/file1", temp_dir);
|
||||
+ support_write_file_string (file1, "file1");
|
||||
+ add_temp_file (file1);
|
||||
+ FILE *fp;
|
||||
+ size_t ret;
|
||||
+ char buf[1024];
|
||||
+
|
||||
+ verbose_printf ("test single-byte reads\n");
|
||||
+ fp = xfopen (file1, "r");
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 1, 2, fp);
|
||||
+ TEST_COMPARE (ret, 2);
|
||||
+ TEST_COMPARE (buf[0], 'f');
|
||||
+ TEST_COMPARE (buf[1], 'i');
|
||||
+ TEST_COMPARE (feof (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 2);
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 1, 3, fp);
|
||||
+ TEST_COMPARE (ret, 3);
|
||||
+ TEST_COMPARE (buf[0], 'l');
|
||||
+ TEST_COMPARE (buf[1], 'e');
|
||||
+ TEST_COMPARE (buf[2], '1');
|
||||
+ TEST_COMPARE (ftell (fp), 5);
|
||||
+ TEST_COMPARE (feof (fp), 0);
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 1, 1, fp);
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ TEST_COMPARE (!!feof (fp), 1);
|
||||
+ TEST_COMPARE (ferror (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 5);
|
||||
+ xfclose (fp);
|
||||
+
|
||||
+ verbose_printf ("test single-byte reads, EOF part way through\n");
|
||||
+ fp = xfopen (file1, "r");
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 1, sizeof buf, fp);
|
||||
+ TEST_COMPARE (ret, 5);
|
||||
+ TEST_COMPARE (buf[0], 'f');
|
||||
+ TEST_COMPARE (buf[1], 'i');
|
||||
+ TEST_COMPARE (buf[2], 'l');
|
||||
+ TEST_COMPARE (buf[3], 'e');
|
||||
+ TEST_COMPARE (buf[4], '1');
|
||||
+ TEST_COMPARE (!!feof (fp), 1);
|
||||
+ TEST_COMPARE (ferror (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 5);
|
||||
+ xfclose (fp);
|
||||
+
|
||||
+ verbose_printf ("test multi-byte reads\n");
|
||||
+ fp = xfopen (file1, "r");
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 2, 2, fp);
|
||||
+ TEST_COMPARE (ret, 2);
|
||||
+ TEST_COMPARE (buf[0], 'f');
|
||||
+ TEST_COMPARE (buf[1], 'i');
|
||||
+ TEST_COMPARE (buf[2], 'l');
|
||||
+ TEST_COMPARE (buf[3], 'e');
|
||||
+ TEST_COMPARE (feof (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 4);
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 3, 3, fp);
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ /* The bytes written for a partial element read are unspecified. */
|
||||
+ TEST_COMPARE (!!feof (fp), 1);
|
||||
+ TEST_COMPARE (ferror (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 5);
|
||||
+ xfclose (fp);
|
||||
+
|
||||
+ verbose_printf ("test read error\n");
|
||||
+ fp = xfopen (file1, "r");
|
||||
+ xclose (fileno (fp));
|
||||
+ memset (buf, 0, sizeof buf);
|
||||
+ ret = fread (buf, 1, sizeof buf, fp);
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ TEST_COMPARE (feof (fp), 0);
|
||||
+ TEST_COMPARE (!!ferror (fp), 1);
|
||||
+ fclose (fp);
|
||||
+
|
||||
+ verbose_printf ("test zero size\n");
|
||||
+ fp = xfopen (file1, "r");
|
||||
+ ret = fread (buf, 0, SIZE_MAX, fp);
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ TEST_COMPARE (feof (fp), 0);
|
||||
+ TEST_COMPARE (ferror (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 0);
|
||||
+ xfclose (fp);
|
||||
+
|
||||
+ verbose_printf ("test zero items\n");
|
||||
+ fp = xfopen (file1, "r");
|
||||
+ ret = fread (buf, SIZE_MAX, 0, fp);
|
||||
+ TEST_COMPARE (ret, 0);
|
||||
+ TEST_COMPARE (feof (fp), 0);
|
||||
+ TEST_COMPARE (ferror (fp), 0);
|
||||
+ TEST_COMPARE (ftell (fp), 0);
|
||||
+ xfclose (fp);
|
||||
+
|
||||
+ free (temp_dir);
|
||||
+ free (file1);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,51 @@
|
||||
commit 293e4e3c90e390fa0b839c66f388a723ac6787e2
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Wed Aug 14 17:15:46 2024 +0000
|
||||
|
||||
Test errno setting on strtod overflow in tst-strtod-round
|
||||
|
||||
We have no tests that errno is set to ERANGE on overflow of
|
||||
strtod-family functions (we do have some tests for underflow, in
|
||||
tst-strtod-underflow). Add such tests to tst-strtod-round.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 207d64feb26279e152c50744e3c37e68491aca99)
|
||||
|
||||
diff --git a/stdlib/tst-strtod-round-skeleton.c b/stdlib/tst-strtod-round-skeleton.c
|
||||
index 6fba4b522862cbb9..c3cc0201d4b1a062 100644
|
||||
--- a/stdlib/tst-strtod-round-skeleton.c
|
||||
+++ b/stdlib/tst-strtod-round-skeleton.c
|
||||
@@ -21,6 +21,7 @@
|
||||
declared in the headers. */
|
||||
#define _LIBC_TEST 1
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
+#include <errno.h>
|
||||
#include <fenv.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
@@ -205,7 +206,9 @@ struct test {
|
||||
#define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
{ \
|
||||
feclearexcept (FE_ALL_EXCEPT); \
|
||||
+ errno = 0; \
|
||||
FTYPE f = STRTO (FSUF) (s, NULL); \
|
||||
+ int new_errno = errno; \
|
||||
if (f != expected->FSUF \
|
||||
|| (copysign ## CSUF) (1.0 ## LSUF, f) \
|
||||
!= (copysign ## CSUF) (1.0 ## LSUF, expected->FSUF)) \
|
||||
@@ -254,6 +257,14 @@ struct test {
|
||||
printf ("ignoring this exception error\n"); \
|
||||
} \
|
||||
} \
|
||||
+ if (overflow->FSUF && new_errno != ERANGE) \
|
||||
+ { \
|
||||
+ printf (FNPFXS "to" #FSUF \
|
||||
+ " (" STRM ") left errno == %d," \
|
||||
+ " not %d (ERANGE)\n", \
|
||||
+ s, new_errno, ERANGE); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
} \
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,447 @@
|
||||
commit a7be595c67d12f1a442e3f6894d67e20c7724bed
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Tue Aug 27 12:41:02 2024 +0000
|
||||
|
||||
Fix strtod subnormal rounding (bug 30220)
|
||||
|
||||
As reported in bug 30220, the implementation of strtod-family
|
||||
functions has a bug in the following case: the input string would,
|
||||
with infinite exponent range, take one more bit to represent than is
|
||||
available in the normal precision of the return type; the value
|
||||
represented is in the subnormal range; and there are no nonzero bits
|
||||
in the value, below those that can be represented in subnormal
|
||||
precision, other than the least significant bit and possibly the
|
||||
0.5ulp bit. In this case, round_and_return ends up discarding the
|
||||
least significant bit.
|
||||
|
||||
Fix by saving that bit to merge into more_bits (it can't be merged in
|
||||
at the time it's computed, because more_bits mustn't include this bit
|
||||
in the case of after-rounding tininess detection checking if the
|
||||
result is still subnormal when rounded to normal precision, so merging
|
||||
this bit into more_bits needs to take place after that check).
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 457622c2fa8f9f7435822d5287a437bc8be8090d)
|
||||
|
||||
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
|
||||
index be515ce659b35530..beb97b3d0cf3191a 100644
|
||||
--- a/stdlib/strtod_l.c
|
||||
+++ b/stdlib/strtod_l.c
|
||||
@@ -222,6 +222,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
|
||||
|
||||
mp_size_t shift = MIN_EXP - 1 - exponent;
|
||||
bool is_tiny = true;
|
||||
+ bool old_half_bit = (round_limb & (((mp_limb_t) 1) << round_bit)) != 0;
|
||||
|
||||
more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
|
||||
if (shift == MANT_DIG)
|
||||
@@ -292,6 +293,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
|
||||
round_bit = shift - 1;
|
||||
(void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
|
||||
}
|
||||
+ more_bits |= old_half_bit;
|
||||
/* This is a hook for the m68k long double format, where the
|
||||
exponent bias is the same for normalized and denormalized
|
||||
numbers. */
|
||||
diff --git a/stdlib/tst-strtod-round-data b/stdlib/tst-strtod-round-data
|
||||
index 84ab705709b24b6c..9489fbcc9ce7eee2 100644
|
||||
--- a/stdlib/tst-strtod-round-data
|
||||
+++ b/stdlib/tst-strtod-round-data
|
||||
@@ -265,3 +265,15 @@
|
||||
1.000000000000000000000000000000000385185988877447170611195588516985463707620329643077639047987759113311767578125
|
||||
1.0000000000000000000000000000000001925929944387235853055977942584927318538101648215388195239938795566558837890625
|
||||
1.00000000000000000000000000000000009629649721936179265279889712924636592690508241076940976199693977832794189453125
|
||||
+0x30000002222225p-1077
|
||||
+0x0.7fffffffffffeap-1022
|
||||
+0x0.7fffffffffffe9p-1022
|
||||
+0x0.7ffffd4p-126
|
||||
+0x0.7ffffffffffffffd4p-16382
|
||||
+0x0.7ffffffffffffffd4p-16383
|
||||
+0x0.7ffffffffffffffffffffffffffeap-16382
|
||||
+0x0.7000004p-126
|
||||
+0x0.70000000000002p-1022
|
||||
+0x0.70000000000000004p-16382
|
||||
+0x0.70000000000000004p-16383
|
||||
+0x0.70000000000000000000000000002p-16382
|
||||
diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h
|
||||
index 13e62dd2b0588a16..ed50eb2537bc175c 100644
|
||||
--- a/stdlib/tst-strtod-round-data.h
|
||||
+++ b/stdlib/tst-strtod-round-data.h
|
||||
@@ -15437,4 +15437,376 @@ static const struct test tests[] = {
|
||||
0x1p+0, false, false,
|
||||
0x1p+0, false, false,
|
||||
0x1.0000000000000000000000000001p+0, false, false),
|
||||
+ TEST ("0x30000002222225p-1077",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x1.800000111111p-1024, false, true,
|
||||
+ 0x1.8000001111114p-1024, false, true,
|
||||
+ 0x1.800000111111p-1024, false, true,
|
||||
+ 0x1.8000001111114p-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ true,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ false,
|
||||
+ 0x1.800000111111p-1024, false, true,
|
||||
+ 0x1.8000001111114p-1024, false, true,
|
||||
+ 0x1.800000111111p-1024, false, true,
|
||||
+ 0x1.8000001111114p-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false,
|
||||
+ 0x1.80000011111128p-1024, false, false),
|
||||
+ TEST ("0x0.7fffffffffffeap-1022",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ true,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ false,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa8p-1024, false, false),
|
||||
+ TEST ("0x0.7fffffffffffe9p-1022",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ true,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ false,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ 0x1.ffffffffffff8p-1024, false, true,
|
||||
+ 0x1.ffffffffffffcp-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false,
|
||||
+ 0x1.ffffffffffffa4p-1024, false, false),
|
||||
+ TEST ("0x0.7ffffd4p-126",
|
||||
+ false,
|
||||
+ 0x1.fffffp-128, false, true,
|
||||
+ 0x1.fffff8p-128, false, true,
|
||||
+ 0x1.fffffp-128, false, true,
|
||||
+ 0x1.fffff8p-128, false, true,
|
||||
+ true,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false,
|
||||
+ 0x1.fffff5p-128, false, false),
|
||||
+ TEST ("0x0.7ffffffffffffffd4p-16382",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0x1.fffffffffffffffp-16384, false, true,
|
||||
+ 0x1.fffffffffffffff8p-16384, false, true,
|
||||
+ 0x1.fffffffffffffffp-16384, false, true,
|
||||
+ 0x1.fffffffffffffff8p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x1.fffffffffffffff4p-16384, false, true,
|
||||
+ 0x1.fffffffffffffff4p-16384, false, true,
|
||||
+ 0x1.fffffffffffffff4p-16384, false, true,
|
||||
+ 0x1.fffffffffffffff8p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ true,
|
||||
+ 0x1.fffffffffffffff5p-16384, false, false,
|
||||
+ 0x1.fffffffffffffff5p-16384, false, false,
|
||||
+ 0x1.fffffffffffffff5p-16384, false, false,
|
||||
+ 0x1.fffffffffffffff5p-16384, false, false),
|
||||
+ TEST ("0x0.7ffffffffffffffd4p-16383",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0xf.ffffffffffffff8p-16388, false, true,
|
||||
+ 0xf.ffffffffffffff8p-16388, false, true,
|
||||
+ 0xf.ffffffffffffff8p-16388, false, true,
|
||||
+ 0x1p-16384, false, true,
|
||||
+ false,
|
||||
+ 0xf.ffffffffffffff8p-16388, false, true,
|
||||
+ 0xf.ffffffffffffffcp-16388, false, true,
|
||||
+ 0xf.ffffffffffffff8p-16388, false, true,
|
||||
+ 0xf.ffffffffffffffcp-16388, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ true,
|
||||
+ 0xf.ffffffffffffffa8p-16388, false, false,
|
||||
+ 0xf.ffffffffffffffa8p-16388, false, false,
|
||||
+ 0xf.ffffffffffffffa8p-16388, false, false,
|
||||
+ 0xf.ffffffffffffffa8p-16388, false, false),
|
||||
+ TEST ("0x0.7ffffffffffffffffffffffffffeap-16382",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0x1.fffffffffffffff8p-16384, false, true,
|
||||
+ 0x2p-16384, false, true,
|
||||
+ 0x1.fffffffffffffff8p-16384, false, true,
|
||||
+ 0x2p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x1.fffffffffffffffcp-16384, false, true,
|
||||
+ 0x2p-16384, false, true,
|
||||
+ 0x1.fffffffffffffffcp-16384, false, true,
|
||||
+ 0x2p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0x1.fffffffffffffffffffffffffff8p-16384, false, true,
|
||||
+ 0x1.fffffffffffffffffffffffffffcp-16384, false, true,
|
||||
+ 0x1.fffffffffffffffffffffffffff8p-16384, false, true,
|
||||
+ 0x1.fffffffffffffffffffffffffffcp-16384, false, true),
|
||||
+ TEST ("0x0.7000004p-126",
|
||||
+ false,
|
||||
+ 0x1.cp-128, false, true,
|
||||
+ 0x1.cp-128, false, true,
|
||||
+ 0x1.cp-128, false, true,
|
||||
+ 0x1.c00008p-128, false, true,
|
||||
+ true,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ true,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false,
|
||||
+ 0x1.c00001p-128, false, false),
|
||||
+ TEST ("0x0.70000000000002p-1022",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x1.cp-1024, false, true,
|
||||
+ 0x1.cp-1024, false, true,
|
||||
+ 0x1.cp-1024, false, true,
|
||||
+ 0x1.c000000000004p-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ true,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ false,
|
||||
+ 0x1.cp-1024, false, true,
|
||||
+ 0x1.cp-1024, false, true,
|
||||
+ 0x1.cp-1024, false, true,
|
||||
+ 0x1.c000000000004p-1024, false, true,
|
||||
+ true,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false,
|
||||
+ 0x1.c0000000000008p-1024, false, false),
|
||||
+ TEST ("0x0.70000000000000004p-16382",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.c000000000000008p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.c000000000000004p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ true,
|
||||
+ 0x1.c000000000000001p-16384, false, false,
|
||||
+ 0x1.c000000000000001p-16384, false, false,
|
||||
+ 0x1.c000000000000001p-16384, false, false,
|
||||
+ 0x1.c000000000000001p-16384, false, false),
|
||||
+ TEST ("0x0.70000000000000004p-16383",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0xep-16388, false, true,
|
||||
+ 0xep-16388, false, true,
|
||||
+ 0xep-16388, false, true,
|
||||
+ 0xe.000000000000008p-16388, false, true,
|
||||
+ false,
|
||||
+ 0xep-16388, false, true,
|
||||
+ 0xep-16388, false, true,
|
||||
+ 0xep-16388, false, true,
|
||||
+ 0xe.000000000000004p-16388, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ true,
|
||||
+ 0xe.0000000000000008p-16388, false, false,
|
||||
+ 0xe.0000000000000008p-16388, false, false,
|
||||
+ 0xe.0000000000000008p-16388, false, false,
|
||||
+ 0xe.0000000000000008p-16388, false, false),
|
||||
+ TEST ("0x0.70000000000000000000000000002p-16382",
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x8p-152, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.c000000000000008p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.c000000000000004p-16384, false, true,
|
||||
+ false,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x0p+0, false, true,
|
||||
+ 0x4p-1076, false, true,
|
||||
+ false,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.cp-16384, false, true,
|
||||
+ 0x1.c000000000000000000000000004p-16384, false, true),
|
||||
};
|
@ -0,0 +1,600 @@
|
||||
commit 86369c9ee4d200527e85d240fa0ee081fdb9fb4c
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Tue Aug 27 20:41:54 2024 +0000
|
||||
|
||||
Make __strtod_internal tests type-generic
|
||||
|
||||
Some of the strtod tests use type-generic machinery in tst-strtod.h to
|
||||
test the strto* functions for all floating types, while others only
|
||||
test double even when the tests are in fact meaningful for all
|
||||
floating types.
|
||||
|
||||
Convert the tests of the internal __strtod_internal interface to cover
|
||||
all floating types. I haven't tried to convert them to use newer test
|
||||
interfaces in other ways, just made the changes necessary to use the
|
||||
type-generic machinery. As an internal interface, there are no
|
||||
aliases for different types with the same ABI (however,
|
||||
__strtold_internal is defined even if long double has the same ABI as
|
||||
double), so macros used by the type-generic testing code are redefined
|
||||
as needed to avoid expecting such aliases to be present.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 3fc063dee01da4f80920a14b7db637c8501d6fd4)
|
||||
|
||||
diff --git a/stdlib/tst-strtod1i.c b/stdlib/tst-strtod1i.c
|
||||
index 9d6bb760fb954508..44ae0264f4f99a92 100644
|
||||
--- a/stdlib/tst-strtod1i.c
|
||||
+++ b/stdlib/tst-strtod1i.c
|
||||
@@ -25,60 +25,91 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
-/* Perform a few tests in a locale with thousands separators. */
|
||||
-static int
|
||||
-do_test (void)
|
||||
-{
|
||||
- static const struct
|
||||
- {
|
||||
- const char *loc;
|
||||
- const char *str;
|
||||
- double exp;
|
||||
- ptrdiff_t nread;
|
||||
- } tests[] =
|
||||
- {
|
||||
- { "de_DE.UTF-8", "1,5", 1.5, 3 },
|
||||
- { "de_DE.UTF-8", "1.5", 1.0, 1 },
|
||||
- { "de_DE.UTF-8", "1.500", 1500.0, 5 },
|
||||
- { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65, 26 }
|
||||
- };
|
||||
-#define ntests (sizeof (tests) / sizeof (tests[0]))
|
||||
- size_t n;
|
||||
- int result = 0;
|
||||
-
|
||||
- puts ("\nLocale tests");
|
||||
+#include "tst-strtod.h"
|
||||
|
||||
- for (n = 0; n < ntests; ++n)
|
||||
- {
|
||||
- double d;
|
||||
- char *endp;
|
||||
+/* This tests internal interfaces, which are only defined for types
|
||||
+ with distinct ABIs, so disable testing for types without distinct
|
||||
+ ABIs. */
|
||||
+#undef IF_FLOAT32
|
||||
+#define IF_FLOAT32(x)
|
||||
+#undef IF_FLOAT64
|
||||
+#define IF_FLOAT64(x)
|
||||
+#undef IF_FLOAT32X
|
||||
+#define IF_FLOAT32X(x)
|
||||
+#undef IF_FLOAT64X
|
||||
+#define IF_FLOAT64X(x)
|
||||
+#if !__HAVE_DISTINCT_FLOAT128
|
||||
+# undef IF_FLOAT128
|
||||
+# define IF_FLOAT128(x)
|
||||
+#endif
|
||||
|
||||
- if (setlocale (LC_ALL, tests[n].loc) == NULL)
|
||||
- {
|
||||
- printf ("cannot set locale %s\n", tests[n].loc);
|
||||
- result = 1;
|
||||
- continue;
|
||||
- }
|
||||
+#define ntests (sizeof (tests) / sizeof (tests[0]))
|
||||
|
||||
- d = __strtod_internal (tests[n].str, &endp, 1);
|
||||
- if (d != tests[n].exp)
|
||||
- {
|
||||
- printf ("strtod(\"%s\") returns %g and not %g\n",
|
||||
- tests[n].str, d, tests[n].exp);
|
||||
- result = 1;
|
||||
- }
|
||||
- else if (endp - tests[n].str != tests[n].nread)
|
||||
- {
|
||||
- printf ("strtod(\"%s\") read %td bytes and not %td\n",
|
||||
- tests[n].str, endp - tests[n].str, tests[n].nread);
|
||||
- result = 1;
|
||||
- }
|
||||
- }
|
||||
+/* Perform a few tests in a locale with thousands separators. */
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+static int \
|
||||
+test_strto ## FSUF (void) \
|
||||
+{ \
|
||||
+ static const struct \
|
||||
+ { \
|
||||
+ const char *loc; \
|
||||
+ const char *str; \
|
||||
+ FTYPE exp; \
|
||||
+ ptrdiff_t nread; \
|
||||
+ } tests[] = \
|
||||
+ { \
|
||||
+ { "de_DE.UTF-8", "1,5", 1.5 ## LSUF, 3 }, \
|
||||
+ { "de_DE.UTF-8", "1.5", 1.0 ## LSUF, 1 }, \
|
||||
+ { "de_DE.UTF-8", "1.500", 1500.0 ## LSUF, 5 }, \
|
||||
+ { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65 ## LSUF, 26 } \
|
||||
+ }; \
|
||||
+ size_t n; \
|
||||
+ int result = 0; \
|
||||
+ \
|
||||
+ puts ("\nLocale tests"); \
|
||||
+ \
|
||||
+ for (n = 0; n < ntests; ++n) \
|
||||
+ { \
|
||||
+ FTYPE d; \
|
||||
+ char *endp; \
|
||||
+ \
|
||||
+ if (setlocale (LC_ALL, tests[n].loc) == NULL) \
|
||||
+ { \
|
||||
+ printf ("cannot set locale %s\n", tests[n].loc); \
|
||||
+ result = 1; \
|
||||
+ continue; \
|
||||
+ } \
|
||||
+ \
|
||||
+ d = __strto ## FSUF ## _internal (tests[n].str, &endp, 1); \
|
||||
+ if (d != tests[n].exp) \
|
||||
+ { \
|
||||
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf1, sizeof (buf1), "%g", d); \
|
||||
+ FTOSTR (buf2, sizeof (buf2), "%g", tests[n].exp); \
|
||||
+ printf ("strto" # FSUF "(\"%s\") returns %s and not %s\n", \
|
||||
+ tests[n].str, buf1, buf2); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ else if (endp - tests[n].str != tests[n].nread) \
|
||||
+ { \
|
||||
+ printf ("strto" # FSUF "(\"%s\") read %td bytes and not %td\n", \
|
||||
+ tests[n].str, endp - tests[n].str, tests[n].nread); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (result == 0) \
|
||||
+ puts ("all OK"); \
|
||||
+ \
|
||||
+ return result ? EXIT_FAILURE : EXIT_SUCCESS; \
|
||||
+}
|
||||
|
||||
- if (result == 0)
|
||||
- puts ("all OK");
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
|
||||
- return result ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ return STRTOD_TEST_FOREACH (test_strto);
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
diff --git a/stdlib/tst-strtod3.c b/stdlib/tst-strtod3.c
|
||||
index 23abec1896896276..0d662d8be83a7525 100644
|
||||
--- a/stdlib/tst-strtod3.c
|
||||
+++ b/stdlib/tst-strtod3.c
|
||||
@@ -3,19 +3,73 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
-static const struct
|
||||
-{
|
||||
- const char *in;
|
||||
- const char *out;
|
||||
- double expected;
|
||||
-} tests[] =
|
||||
- {
|
||||
- { "000,,,e1", ",,,e1", 0.0 },
|
||||
- { "000e1", "", 0.0 },
|
||||
- { "000,1e1", ",1e1", 0.0 }
|
||||
- };
|
||||
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
|
||||
+#include "tst-strtod.h"
|
||||
+
|
||||
+/* This tests internal interfaces, which are only defined for types
|
||||
+ with distinct ABIs, so disable testing for types without distinct
|
||||
+ ABIs. */
|
||||
+#undef IF_FLOAT32
|
||||
+#define IF_FLOAT32(x)
|
||||
+#undef IF_FLOAT64
|
||||
+#define IF_FLOAT64(x)
|
||||
+#undef IF_FLOAT32X
|
||||
+#define IF_FLOAT32X(x)
|
||||
+#undef IF_FLOAT64X
|
||||
+#define IF_FLOAT64X(x)
|
||||
+#if !__HAVE_DISTINCT_FLOAT128
|
||||
+# undef IF_FLOAT128
|
||||
+# define IF_FLOAT128(x)
|
||||
+#endif
|
||||
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+static const struct \
|
||||
+{ \
|
||||
+ const char *in; \
|
||||
+ const char *out; \
|
||||
+ FTYPE expected; \
|
||||
+} tests_strto ## FSUF[] = \
|
||||
+ { \
|
||||
+ { "000,,,e1", ",,,e1", 0.0 ## LSUF }, \
|
||||
+ { "000e1", "", 0.0 ## LSUF }, \
|
||||
+ { "000,1e1", ",1e1", 0.0 ## LSUF } \
|
||||
+ }; \
|
||||
+ \
|
||||
+static int \
|
||||
+test_strto ## FSUF (void) \
|
||||
+{ \
|
||||
+ int status = 0; \
|
||||
+ \
|
||||
+ for (int i = 0; \
|
||||
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
|
||||
+ ++i) \
|
||||
+ { \
|
||||
+ char *ep; \
|
||||
+ FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
|
||||
+ &ep, 1); \
|
||||
+ \
|
||||
+ if (strcmp (ep, tests_strto ## FSUF[i].out) != 0) \
|
||||
+ { \
|
||||
+ printf ("%d: got rest string \"%s\", expected \"%s\"\n", \
|
||||
+ i, ep, tests_strto ## FSUF[i].out); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (r != tests_strto ## FSUF[i].expected) \
|
||||
+ { \
|
||||
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
|
||||
+ FTOSTR (buf2, sizeof (buf2), "%g", \
|
||||
+ tests_strto ## FSUF[i].expected); \
|
||||
+ printf ("%d: got wrong results %s, expected %s\n", \
|
||||
+ i, buf1, buf2); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ \
|
||||
+ return status; \
|
||||
+}
|
||||
+
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -26,29 +80,7 @@ do_test (void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- int status = 0;
|
||||
-
|
||||
- for (int i = 0; i < NTESTS; ++i)
|
||||
- {
|
||||
- char *ep;
|
||||
- double r = __strtod_internal (tests[i].in, &ep, 1);
|
||||
-
|
||||
- if (strcmp (ep, tests[i].out) != 0)
|
||||
- {
|
||||
- printf ("%d: got rest string \"%s\", expected \"%s\"\n",
|
||||
- i, ep, tests[i].out);
|
||||
- status = 1;
|
||||
- }
|
||||
-
|
||||
- if (r != tests[i].expected)
|
||||
- {
|
||||
- printf ("%d: got wrong results %g, expected %g\n",
|
||||
- i, r, tests[i].expected);
|
||||
- status = 1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return status;
|
||||
+ return STRTOD_TEST_FOREACH (test_strto);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
diff --git a/stdlib/tst-strtod4.c b/stdlib/tst-strtod4.c
|
||||
index 6cc4e843c78a4ac0..dfd3f05027c0d3c1 100644
|
||||
--- a/stdlib/tst-strtod4.c
|
||||
+++ b/stdlib/tst-strtod4.c
|
||||
@@ -3,22 +3,76 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
+#include "tst-strtod.h"
|
||||
+
|
||||
+/* This tests internal interfaces, which are only defined for types
|
||||
+ with distinct ABIs, so disable testing for types without distinct
|
||||
+ ABIs. */
|
||||
+#undef IF_FLOAT32
|
||||
+#define IF_FLOAT32(x)
|
||||
+#undef IF_FLOAT64
|
||||
+#define IF_FLOAT64(x)
|
||||
+#undef IF_FLOAT32X
|
||||
+#define IF_FLOAT32X(x)
|
||||
+#undef IF_FLOAT64X
|
||||
+#define IF_FLOAT64X(x)
|
||||
+#if !__HAVE_DISTINCT_FLOAT128
|
||||
+# undef IF_FLOAT128
|
||||
+# define IF_FLOAT128(x)
|
||||
+#endif
|
||||
+
|
||||
#define NNBSP "\xe2\x80\xaf"
|
||||
|
||||
-static const struct
|
||||
-{
|
||||
- const char *in;
|
||||
- const char *out;
|
||||
- double expected;
|
||||
-} tests[] =
|
||||
- {
|
||||
- { "000"NNBSP"000"NNBSP"000", "", 0.0 },
|
||||
- { "1"NNBSP"000"NNBSP"000,5x", "x", 1000000.5 },
|
||||
- /* Bug 30964 */
|
||||
- { "10"NNBSP NNBSP"200", NNBSP NNBSP"200", 10.0 }
|
||||
- };
|
||||
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+static const struct \
|
||||
+{ \
|
||||
+ const char *in; \
|
||||
+ const char *out; \
|
||||
+ FTYPE expected; \
|
||||
+} tests_strto ## FSUF[] = \
|
||||
+ { \
|
||||
+ { "000"NNBSP"000"NNBSP"000", "", 0.0 ## LSUF }, \
|
||||
+ { "1"NNBSP"000"NNBSP"000,5x", "x", 1000000.5 ## LSUF }, \
|
||||
+ /* Bug 30964 */ \
|
||||
+ { "10"NNBSP NNBSP"200", NNBSP NNBSP"200", 10.0 ## LSUF } \
|
||||
+ }; \
|
||||
+ \
|
||||
+static int \
|
||||
+test_strto ## FSUF (void) \
|
||||
+{ \
|
||||
+ int status = 0; \
|
||||
+ \
|
||||
+ for (int i = 0; \
|
||||
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
|
||||
+ ++i) \
|
||||
+ { \
|
||||
+ char *ep; \
|
||||
+ FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
|
||||
+ &ep, 1); \
|
||||
+ \
|
||||
+ if (strcmp (ep, tests_strto ## FSUF[i].out) != 0) \
|
||||
+ { \
|
||||
+ printf ("%d: got rest string \"%s\", expected \"%s\"\n", \
|
||||
+ i, ep, tests_strto ## FSUF[i].out); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (r != tests_strto ## FSUF[i].expected) \
|
||||
+ { \
|
||||
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
|
||||
+ FTOSTR (buf2, sizeof (buf2), "%g", \
|
||||
+ tests_strto ## FSUF[i].expected); \
|
||||
+ printf ("%d: got wrong results %s, expected %s\n", \
|
||||
+ i, buf1, buf2); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ \
|
||||
+ return status; \
|
||||
+}
|
||||
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -29,29 +83,7 @@ do_test (void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- int status = 0;
|
||||
-
|
||||
- for (int i = 0; i < NTESTS; ++i)
|
||||
- {
|
||||
- char *ep;
|
||||
- double r = __strtod_internal (tests[i].in, &ep, 1);
|
||||
-
|
||||
- if (strcmp (ep, tests[i].out) != 0)
|
||||
- {
|
||||
- printf ("%d: got rest string \"%s\", expected \"%s\"\n",
|
||||
- i, ep, tests[i].out);
|
||||
- status = 1;
|
||||
- }
|
||||
-
|
||||
- if (r != tests[i].expected)
|
||||
- {
|
||||
- printf ("%d: got wrong results %g, expected %g\n",
|
||||
- i, r, tests[i].expected);
|
||||
- status = 1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return status;
|
||||
+ return STRTOD_TEST_FOREACH (test_strto);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
diff --git a/stdlib/tst-strtod5i.c b/stdlib/tst-strtod5i.c
|
||||
index ee54e3404c6e56c1..136aedea68745dd6 100644
|
||||
--- a/stdlib/tst-strtod5i.c
|
||||
+++ b/stdlib/tst-strtod5i.c
|
||||
@@ -16,52 +16,112 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
+/* Defining _LIBC_TEST ensures long double math functions are
|
||||
+ declared in the headers. */
|
||||
+#define _LIBC_TEST 1
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
+#include "tst-strtod.h"
|
||||
+
|
||||
+/* This tests internal interfaces, which are only defined for types
|
||||
+ with distinct ABIs, so disable testing for types without distinct
|
||||
+ ABIs. */
|
||||
+#undef IF_FLOAT32
|
||||
+#define IF_FLOAT32(x)
|
||||
+#undef IF_FLOAT64
|
||||
+#define IF_FLOAT64(x)
|
||||
+#undef IF_FLOAT32X
|
||||
+#define IF_FLOAT32X(x)
|
||||
+#undef IF_FLOAT64X
|
||||
+#define IF_FLOAT64X(x)
|
||||
+#if !__HAVE_DISTINCT_FLOAT128
|
||||
+# undef IF_FLOAT128
|
||||
+# define IF_FLOAT128(x)
|
||||
+#endif
|
||||
+
|
||||
#define NNBSP "\xe2\x80\xaf"
|
||||
|
||||
-static const struct
|
||||
-{
|
||||
- const char *in;
|
||||
- int group;
|
||||
- double expected;
|
||||
-} tests[] =
|
||||
- {
|
||||
- { "0", 0, 0.0 },
|
||||
- { "000", 0, 0.0 },
|
||||
- { "-0", 0, -0.0 },
|
||||
- { "-000", 0, -0.0 },
|
||||
- { "0,", 0, 0.0 },
|
||||
- { "-0,", 0, -0.0 },
|
||||
- { "0,0", 0, 0.0 },
|
||||
- { "-0,0", 0, -0.0 },
|
||||
- { "0e-10", 0, 0.0 },
|
||||
- { "-0e-10", 0, -0.0 },
|
||||
- { "0,e-10", 0, 0.0 },
|
||||
- { "-0,e-10", 0, -0.0 },
|
||||
- { "0,0e-10", 0, 0.0 },
|
||||
- { "-0,0e-10", 0, -0.0 },
|
||||
- { "0e-1000000", 0, 0.0 },
|
||||
- { "-0e-1000000", 0, -0.0 },
|
||||
- { "0,0e-1000000", 0, 0.0 },
|
||||
- { "-0,0e-1000000", 0, -0.0 },
|
||||
- { "0", 1, 0.0 },
|
||||
- { "000", 1, 0.0 },
|
||||
- { "-0", 1, -0.0 },
|
||||
- { "-000", 1, -0.0 },
|
||||
- { "0e-10", 1, 0.0 },
|
||||
- { "-0e-10", 1, -0.0 },
|
||||
- { "0e-1000000", 1, 0.0 },
|
||||
- { "-0e-1000000", 1, -0.0 },
|
||||
- { "000"NNBSP"000"NNBSP"000", 1, 0.0 },
|
||||
- { "-000"NNBSP"000"NNBSP"000", 1, -0.0 }
|
||||
- };
|
||||
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+static const struct \
|
||||
+{ \
|
||||
+ const char *in; \
|
||||
+ int group; \
|
||||
+ FTYPE expected; \
|
||||
+} tests_strto ## FSUF[] = \
|
||||
+ { \
|
||||
+ { "0", 0, 0.0 ## LSUF }, \
|
||||
+ { "000", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0", 0, -0.0 ## LSUF }, \
|
||||
+ { "-000", 0, -0.0 ## LSUF }, \
|
||||
+ { "0,", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0,", 0, -0.0 ## LSUF }, \
|
||||
+ { "0,0", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0,0", 0, -0.0 ## LSUF }, \
|
||||
+ { "0e-10", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0e-10", 0, -0.0 ## LSUF }, \
|
||||
+ { "0,e-10", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0,e-10", 0, -0.0 ## LSUF }, \
|
||||
+ { "0,0e-10", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0,0e-10", 0, -0.0 ## LSUF }, \
|
||||
+ { "0e-1000000", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0e-1000000", 0, -0.0 ## LSUF }, \
|
||||
+ { "0,0e-1000000", 0, 0.0 ## LSUF }, \
|
||||
+ { "-0,0e-1000000", 0, -0.0 ## LSUF }, \
|
||||
+ { "0", 1, 0.0 ## LSUF }, \
|
||||
+ { "000", 1, 0.0 ## LSUF }, \
|
||||
+ { "-0", 1, -0.0 ## LSUF }, \
|
||||
+ { "-000", 1, -0.0 ## LSUF }, \
|
||||
+ { "0e-10", 1, 0.0 ## LSUF }, \
|
||||
+ { "-0e-10", 1, -0.0 ## LSUF }, \
|
||||
+ { "0e-1000000", 1, 0.0 ## LSUF }, \
|
||||
+ { "-0e-1000000", 1, -0.0 ## LSUF }, \
|
||||
+ { "000"NNBSP"000"NNBSP"000", 1, 0.0 ## LSUF }, \
|
||||
+ { "-000"NNBSP"000"NNBSP"000", 1, -0.0 ## LSUF } \
|
||||
+ }; \
|
||||
+ \
|
||||
+static int \
|
||||
+test_strto ## FSUF (void) \
|
||||
+{ \
|
||||
+ int status = 0; \
|
||||
+ \
|
||||
+ for (int i = 0; \
|
||||
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
|
||||
+ ++i) \
|
||||
+ { \
|
||||
+ char *ep; \
|
||||
+ FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
|
||||
+ &ep, \
|
||||
+ tests_strto ## FSUF[i].group); \
|
||||
+ \
|
||||
+ if (*ep != '\0') \
|
||||
+ { \
|
||||
+ printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (r != tests_strto ## FSUF[i].expected \
|
||||
+ || (copysign ## CSUF (10.0 ## LSUF, r) \
|
||||
+ != copysign ## CSUF (10.0 ## LSUF, \
|
||||
+ tests_strto ## FSUF[i].expected))) \
|
||||
+ { \
|
||||
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
|
||||
+ FTOSTR (buf2, sizeof (buf2), "%g", \
|
||||
+ tests_strto ## FSUF[i].expected); \
|
||||
+ printf ("%d: got wrong results %s, expected %s\n", \
|
||||
+ i, buf1, buf2); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ \
|
||||
+ return status; \
|
||||
+}
|
||||
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -72,29 +132,7 @@ do_test (void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- int status = 0;
|
||||
-
|
||||
- for (int i = 0; i < NTESTS; ++i)
|
||||
- {
|
||||
- char *ep;
|
||||
- double r = __strtod_internal (tests[i].in, &ep, tests[i].group);
|
||||
-
|
||||
- if (*ep != '\0')
|
||||
- {
|
||||
- printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep);
|
||||
- status = 1;
|
||||
- }
|
||||
-
|
||||
- if (r != tests[i].expected
|
||||
- || copysign (10.0, r) != copysign (10.0, tests[i].expected))
|
||||
- {
|
||||
- printf ("%d: got wrong results %g, expected %g\n",
|
||||
- i, r, tests[i].expected);
|
||||
- status = 1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return status;
|
||||
+ return STRTOD_TEST_FOREACH (test_strto);
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
@ -0,0 +1,142 @@
|
||||
commit 63bcc017446d14e64aed8511845400fc661f2828
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Wed Sep 4 13:20:18 2024 +0000
|
||||
|
||||
Improve NaN payload testing
|
||||
|
||||
There are two separate sets of tests of NaN payloads in glibc:
|
||||
|
||||
* libm-test-{get,set}payload* verify that getpayload, setpayload,
|
||||
setpayloadsig and __builtin_nan functions are consistent in their
|
||||
payload handling.
|
||||
|
||||
* test-nan-payload verifies that strtod-family functions and the
|
||||
not-built-in nan functions are consistent in their payload handling.
|
||||
|
||||
Nothing, however, connects the two sets of functions (i.e., verifies
|
||||
that strtod / nan are consistent with getpayload / setpayload /
|
||||
__builtin_nan).
|
||||
|
||||
Improve test-nan-payload to check actual payload value with getpayload
|
||||
rather than just verifying that the strtod and nan functions produce
|
||||
the same NaN. Also check that the NaNs produced aren't signaling and
|
||||
extend the tests to cover _FloatN / _FloatNx.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit be77d5ae417236883c02d3d67c0716e3f669fa41)
|
||||
|
||||
diff --git a/math/test-nan-payload.c b/math/test-nan-payload.c
|
||||
index 4a81dc348bac0691..55c13de14eb6a4d0 100644
|
||||
--- a/math/test-nan-payload.c
|
||||
+++ b/math/test-nan-payload.c
|
||||
@@ -16,6 +16,8 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
+#define _LIBC_TEST 1
|
||||
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
@@ -31,7 +33,7 @@
|
||||
#define CHECK_IS_NAN(TYPE, A) \
|
||||
do \
|
||||
{ \
|
||||
- if (isnan (A)) \
|
||||
+ if (isnan (A) && !issignaling (A)) \
|
||||
puts ("PASS: " #TYPE " " #A); \
|
||||
else \
|
||||
{ \
|
||||
@@ -41,6 +43,19 @@
|
||||
} \
|
||||
while (0)
|
||||
|
||||
+#define CHECK_PAYLOAD(TYPE, FUNC, A, P) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ if (FUNC (&(A)) == (P)) \
|
||||
+ puts ("PASS: " #TYPE " payload " #A); \
|
||||
+ else \
|
||||
+ { \
|
||||
+ puts ("FAIL: " #TYPE " payload " #A); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
#define CHECK_SAME_NAN(TYPE, A, B) \
|
||||
do \
|
||||
{ \
|
||||
@@ -71,7 +86,7 @@
|
||||
bits. */
|
||||
#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
|
||||
|
||||
-#define RUN_TESTS(TYPE, SFUNC, FUNC, MANT_DIG) \
|
||||
+#define RUN_TESTS(TYPE, SFUNC, FUNC, PLFUNC, MANT_DIG) \
|
||||
do \
|
||||
{ \
|
||||
TYPE n123 = WRAP_NAN (FUNC, "123"); \
|
||||
@@ -82,6 +97,10 @@
|
||||
CHECK_IS_NAN (TYPE, n456); \
|
||||
TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
|
||||
CHECK_IS_NAN (TYPE, s456); \
|
||||
+ TYPE nh123 = WRAP_NAN (FUNC, "0x123"); \
|
||||
+ CHECK_IS_NAN (TYPE, nh123); \
|
||||
+ TYPE sh123 = WRAP_STRTO (SFUNC, "NAN(0x123)"); \
|
||||
+ CHECK_IS_NAN (TYPE, sh123); \
|
||||
TYPE n123x = WRAP_NAN (FUNC, "123)"); \
|
||||
CHECK_IS_NAN (TYPE, n123x); \
|
||||
TYPE nemp = WRAP_NAN (FUNC, ""); \
|
||||
@@ -92,8 +111,16 @@
|
||||
CHECK_IS_NAN (TYPE, sx); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, n123, s123); \
|
||||
+ CHECK_PAYLOAD (TYPE, PLFUNC, n123, 123); \
|
||||
+ CHECK_PAYLOAD (TYPE, PLFUNC, s123, 123); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, n456, s456); \
|
||||
+ CHECK_PAYLOAD (TYPE, PLFUNC, n456, 456); \
|
||||
+ CHECK_PAYLOAD (TYPE, PLFUNC, s456, 456); \
|
||||
+ if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
+ CHECK_SAME_NAN (TYPE, nh123, sh123); \
|
||||
+ CHECK_PAYLOAD (TYPE, PLFUNC, nh123, 0x123); \
|
||||
+ CHECK_PAYLOAD (TYPE, PLFUNC, sh123, 0x123); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, nemp, semp); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
@@ -110,9 +137,31 @@ static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
- RUN_TESTS (float, strtof, nanf, FLT_MANT_DIG);
|
||||
- RUN_TESTS (double, strtod, nan, DBL_MANT_DIG);
|
||||
- RUN_TESTS (long double, strtold, nanl, LDBL_MANT_DIG);
|
||||
+ RUN_TESTS (float, strtof, nanf, getpayloadf, FLT_MANT_DIG);
|
||||
+ RUN_TESTS (double, strtod, nan, getpayload, DBL_MANT_DIG);
|
||||
+ RUN_TESTS (long double, strtold, nanl, getpayloadl, LDBL_MANT_DIG);
|
||||
+#if __HAVE_FLOAT16
|
||||
+ RUN_TESTS (_Float16, strtof16, nanf16, getpayloadf16, FLT16_MANT_DIG);
|
||||
+#endif
|
||||
+#if __HAVE_FLOAT32
|
||||
+ RUN_TESTS (_Float32, strtof32, nanf32, getpayloadf32, FLT32_MANT_DIG);
|
||||
+#endif
|
||||
+#if __HAVE_FLOAT64
|
||||
+ RUN_TESTS (_Float64, strtof64, nanf64, getpayloadf64, FLT64_MANT_DIG);
|
||||
+#endif
|
||||
+#if __HAVE_FLOAT128
|
||||
+ RUN_TESTS (_Float128, strtof128, nanf128, getpayloadf128, FLT128_MANT_DIG);
|
||||
+#endif
|
||||
+#if __HAVE_FLOAT32X
|
||||
+ RUN_TESTS (_Float32x, strtof32x, nanf32x, getpayloadf32x, FLT32X_MANT_DIG);
|
||||
+#endif
|
||||
+#if __HAVE_FLOAT64X
|
||||
+ RUN_TESTS (_Float64x, strtof64x, nanf64x, getpayloadf64x, FLT64X_MANT_DIG);
|
||||
+#endif
|
||||
+#if __HAVE_FLOAT128X
|
||||
+ RUN_TESTS (_Float128x, strtof128x, nanf128x, getpayloadf128x,
|
||||
+ FLT128X_MANT_DIG);
|
||||
+#endif
|
||||
return result;
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
commit 6624318c89185fe8b9d1f61e7a6841a843b8f9f3
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Wed Sep 4 13:21:23 2024 +0000
|
||||
|
||||
Do not set errno for overflowing NaN payload in strtod/nan (bug 32045)
|
||||
|
||||
As reported in bug 32045, it's incorrect for strtod/nan functions to
|
||||
set errno based on overflowing payload (strtod should only set errno
|
||||
for overflow / underflow of its actual result, and potentially if
|
||||
nothing in the string can be parsed as a number at all; nan should be
|
||||
a pure function that never sets it). Save and restore errno around
|
||||
the internal strtoull call and add associated test coverage.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 64f62c47e9c350f353336f2df6714e1d48ec50d8)
|
||||
|
||||
diff --git a/math/Makefile b/math/Makefile
|
||||
index 79ef4ebb65cd40ea..14107855e88bc96b 100644
|
||||
--- a/math/Makefile
|
||||
+++ b/math/Makefile
|
||||
@@ -462,6 +462,7 @@ CFLAGS-test-flt-eval-method.c += -fexcess-precision=standard
|
||||
CFLAGS-test-fe-snans-always-signal.c += $(config-cflags-signaling-nans)
|
||||
|
||||
CFLAGS-test-nan-const.c += -fno-builtin
|
||||
+CFLAGS-test-nan-payload.c += -fno-builtin
|
||||
|
||||
include ../Rules
|
||||
|
||||
diff --git a/math/test-nan-payload.c b/math/test-nan-payload.c
|
||||
index 55c13de14eb6a4d0..413791e09f8b348d 100644
|
||||
--- a/math/test-nan-payload.c
|
||||
+++ b/math/test-nan-payload.c
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#define _LIBC_TEST 1
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
+#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
@@ -82,6 +83,26 @@
|
||||
} \
|
||||
while (0)
|
||||
|
||||
+#define CLEAR_ERRNO \
|
||||
+ do \
|
||||
+ { \
|
||||
+ errno = 12345; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
+#define CHECK_ERRNO(TYPE, A) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ if (errno == 12345) \
|
||||
+ puts ("PASS: " #TYPE " " #A " errno"); \
|
||||
+ else \
|
||||
+ { \
|
||||
+ puts ("FAIL: " #TYPE " " #A " errno"); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
/* Cannot test payloads by memcmp for formats where NaNs have padding
|
||||
bits. */
|
||||
#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
|
||||
@@ -89,26 +110,58 @@
|
||||
#define RUN_TESTS(TYPE, SFUNC, FUNC, PLFUNC, MANT_DIG) \
|
||||
do \
|
||||
{ \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE n123 = WRAP_NAN (FUNC, "123"); \
|
||||
+ CHECK_ERRNO (TYPE, n123); \
|
||||
CHECK_IS_NAN (TYPE, n123); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE s123 = WRAP_STRTO (SFUNC, "NAN(123)"); \
|
||||
+ CHECK_ERRNO (TYPE, s123); \
|
||||
CHECK_IS_NAN (TYPE, s123); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE n456 = WRAP_NAN (FUNC, "456"); \
|
||||
+ CHECK_ERRNO (TYPE, n456); \
|
||||
CHECK_IS_NAN (TYPE, n456); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
|
||||
+ CHECK_ERRNO (TYPE, s456); \
|
||||
CHECK_IS_NAN (TYPE, s456); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE nh123 = WRAP_NAN (FUNC, "0x123"); \
|
||||
+ CHECK_ERRNO (TYPE, nh123); \
|
||||
CHECK_IS_NAN (TYPE, nh123); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE sh123 = WRAP_STRTO (SFUNC, "NAN(0x123)"); \
|
||||
+ CHECK_ERRNO (TYPE, sh123); \
|
||||
CHECK_IS_NAN (TYPE, sh123); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE n123x = WRAP_NAN (FUNC, "123)"); \
|
||||
+ CHECK_ERRNO (TYPE, n123x); \
|
||||
CHECK_IS_NAN (TYPE, n123x); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE nemp = WRAP_NAN (FUNC, ""); \
|
||||
+ CHECK_ERRNO (TYPE, nemp); \
|
||||
CHECK_IS_NAN (TYPE, nemp); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE semp = WRAP_STRTO (SFUNC, "NAN()"); \
|
||||
+ CHECK_ERRNO (TYPE, semp); \
|
||||
CHECK_IS_NAN (TYPE, semp); \
|
||||
+ CLEAR_ERRNO; \
|
||||
TYPE sx = WRAP_STRTO (SFUNC, "NAN"); \
|
||||
+ CHECK_ERRNO (TYPE, sx); \
|
||||
CHECK_IS_NAN (TYPE, sx); \
|
||||
+ CLEAR_ERRNO; \
|
||||
+ TYPE novf = WRAP_NAN (FUNC, "9999999999" \
|
||||
+ "99999999999999999999" \
|
||||
+ "9999999999"); \
|
||||
+ CHECK_ERRNO (TYPE, novf); \
|
||||
+ CHECK_IS_NAN (TYPE, novf); \
|
||||
+ CLEAR_ERRNO; \
|
||||
+ TYPE sovf = WRAP_STRTO (SFUNC, "NAN(9999999999" \
|
||||
+ "99999999999999999999" \
|
||||
+ "9999999999)"); \
|
||||
+ CHECK_ERRNO (TYPE, sovf); \
|
||||
+ CHECK_IS_NAN (TYPE, sovf); \
|
||||
if (CAN_TEST_EQ (MANT_DIG)) \
|
||||
CHECK_SAME_NAN (TYPE, n123, s123); \
|
||||
CHECK_PAYLOAD (TYPE, PLFUNC, n123, 123); \
|
||||
diff --git a/stdlib/strtod_nan_main.c b/stdlib/strtod_nan_main.c
|
||||
index 4cb286d2b3fb0676..39fb7e9f75bc5dbd 100644
|
||||
--- a/stdlib/strtod_nan_main.c
|
||||
+++ b/stdlib/strtod_nan_main.c
|
||||
@@ -16,6 +16,7 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
+#include <errno.h>
|
||||
#include <ieee754.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
@@ -50,7 +51,9 @@ STRTOD_NAN (const STRING_TYPE *str, STRING_TYPE **endptr, STRING_TYPE endc)
|
||||
STRING_TYPE *endp;
|
||||
unsigned long long int mant;
|
||||
|
||||
+ int save_errno = errno;
|
||||
mant = STRTOULL (str, &endp, 0);
|
||||
+ __set_errno (save_errno);
|
||||
if (endp == cp)
|
||||
SET_NAN_PAYLOAD (retval, mant);
|
||||
|
@ -0,0 +1,77 @@
|
||||
commit a2f7087237e77122c2c08b15efc3cee5f475cd46
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Sep 5 21:18:23 2024 +0200
|
||||
|
||||
powerpc64le: Build new strtod tests with long double ABI flags (bug 32145)
|
||||
|
||||
This fixes several test failures:
|
||||
|
||||
=====FAIL: stdlib/tst-strtod1i.out=====
|
||||
Locale tests
|
||||
all OK
|
||||
Locale tests
|
||||
all OK
|
||||
Locale tests
|
||||
strtold("1,5") returns -6,38643e+367 and not 1,5
|
||||
strtold("1.5") returns 1,5 and not 1
|
||||
strtold("1.500") returns 1 and not 1500
|
||||
strtold("36.893.488.147.419.103.232") returns 1500 and not 3,68935e+19
|
||||
Locale tests
|
||||
all OK
|
||||
|
||||
=====FAIL: stdlib/tst-strtod3.out=====
|
||||
0: got wrong results -2.5937e+4826, expected 0
|
||||
|
||||
=====FAIL: stdlib/tst-strtod4.out=====
|
||||
0: got wrong results -6,38643e+367, expected 0
|
||||
1: got wrong results 0, expected 1e+06
|
||||
2: got wrong results 1e+06, expected 10
|
||||
|
||||
=====FAIL: stdlib/tst-strtod5i.out=====
|
||||
0: got wrong results -6,38643e+367, expected 0
|
||||
2: got wrong results 0, expected -0
|
||||
4: got wrong results -0, expected 0
|
||||
5: got wrong results 0, expected -0
|
||||
6: got wrong results -0, expected 0
|
||||
7: got wrong results 0, expected -0
|
||||
8: got wrong results -0, expected 0
|
||||
9: got wrong results 0, expected -0
|
||||
10: got wrong results -0, expected 0
|
||||
11: got wrong results 0, expected -0
|
||||
12: got wrong results -0, expected 0
|
||||
13: got wrong results 0, expected -0
|
||||
14: got wrong results -0, expected 0
|
||||
15: got wrong results 0, expected -0
|
||||
16: got wrong results -0, expected 0
|
||||
17: got wrong results 0, expected -0
|
||||
18: got wrong results -0, expected 0
|
||||
20: got wrong results 0, expected -0
|
||||
22: got wrong results -0, expected 0
|
||||
23: got wrong results 0, expected -0
|
||||
24: got wrong results -0, expected 0
|
||||
25: got wrong results 0, expected -0
|
||||
26: got wrong results -0, expected 0
|
||||
27: got wrong results 0, expected -0
|
||||
|
||||
Fixes commit 3fc063dee01da4f80920a14b7db637c8501d6fd4
|
||||
("Make __strtod_internal tests type-generic").
|
||||
|
||||
Suggested-by: Joseph Myers <josmyers@redhat.com>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit cc3e743fc09ee6fca45767629df9cbcbe1feba82)
|
||||
|
||||
diff --git a/sysdeps/powerpc/powerpc64/le/Makefile b/sysdeps/powerpc/powerpc64/le/Makefile
|
||||
index 5214eb40adbdf25d..ca5e395f8db6c83e 100644
|
||||
--- a/sysdeps/powerpc/powerpc64/le/Makefile
|
||||
+++ b/sysdeps/powerpc/powerpc64/le/Makefile
|
||||
@@ -129,6 +129,10 @@ CFLAGS-tst-strtod-round.c += $(type-float128-CFLAGS)
|
||||
CFLAGS-tst-wcstod-round.c += $(type-float128-CFLAGS)
|
||||
CFLAGS-tst-strtod-nan-locale.c += $(type-float128-CFLAGS)
|
||||
CFLAGS-tst-wcstod-nan-locale.c += $(type-float128-CFLAGS)
|
||||
+CFLAGS-tst-strtod1i.c += $(type-float128-CFLAGS)
|
||||
+CFLAGS-tst-strtod3.c += $(type-float128-CFLAGS)
|
||||
+CFLAGS-tst-strtod4.c += $(type-float128-CFLAGS)
|
||||
+CFLAGS-tst-strtod5i.c += $(type-float128-CFLAGS)
|
||||
CFLAGS-tst-strtod6.c += $(type-float128-CFLAGS)
|
||||
CFLAGS-tst-strfrom.c += $(type-float128-CFLAGS)
|
||||
CFLAGS-tst-strfrom-locale.c += $(type-float128-CFLAGS)
|
@ -0,0 +1,256 @@
|
||||
commit 988de945389e22460a2f75e677d55ac5f96408f3
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Fri Sep 20 23:23:13 2024 +0000
|
||||
|
||||
Make tst-strtod2 and tst-strtod5 type-generic
|
||||
|
||||
Some of the strtod tests use type-generic machinery in tst-strtod.h to
|
||||
test the strto* functions for all floating types, while others only
|
||||
test double even when the tests are in fact meaningful for all
|
||||
floating types.
|
||||
|
||||
Convert tst-strtod2 and tst-strtod5 to use the type-generic machinery
|
||||
so they test all floating types. I haven't tried to convert them to
|
||||
use newer test interfaces in other ways, just made the changes
|
||||
necessary to use the type-generic machinery.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 8de031bcb9adfa736c0caed2c79d10947b8d8f48)
|
||||
|
||||
diff --git a/stdlib/tst-strtod2.c b/stdlib/tst-strtod2.c
|
||||
index a7df82ebbde14c5f..2cb0953fa911efd0 100644
|
||||
--- a/stdlib/tst-strtod2.c
|
||||
+++ b/stdlib/tst-strtod2.c
|
||||
@@ -1,43 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
-struct test
|
||||
-{
|
||||
- const char *str;
|
||||
- double result;
|
||||
- size_t offset;
|
||||
-} tests[] =
|
||||
-{
|
||||
- { "0xy", 0.0, 1 },
|
||||
- { "0x.y", 0.0, 1 },
|
||||
- { "0x0.y", 0.0, 4 },
|
||||
- { "0x.0y", 0.0, 4 },
|
||||
- { ".y", 0.0, 0 },
|
||||
- { "0.y", 0.0, 2 },
|
||||
- { ".0y", 0.0, 2 }
|
||||
-};
|
||||
+#include "tst-strtod.h"
|
||||
+
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+struct test_strto ## FSUF \
|
||||
+{ \
|
||||
+ const char *str; \
|
||||
+ FTYPE result; \
|
||||
+ size_t offset; \
|
||||
+} tests_strto ## FSUF[] = \
|
||||
+{ \
|
||||
+ { "0xy", 0.0 ## LSUF, 1 }, \
|
||||
+ { "0x.y", 0.0 ## LSUF, 1 }, \
|
||||
+ { "0x0.y", 0.0 ## LSUF, 4 }, \
|
||||
+ { "0x.0y", 0.0 ## LSUF, 4 }, \
|
||||
+ { ".y", 0.0 ## LSUF, 0 }, \
|
||||
+ { "0.y", 0.0 ## LSUF, 2 }, \
|
||||
+ { ".0y", 0.0 ## LSUF, 2 } \
|
||||
+}; \
|
||||
+ \
|
||||
+static int \
|
||||
+test_strto ## FSUF (void) \
|
||||
+{ \
|
||||
+ int status = 0; \
|
||||
+ for (size_t i = 0; \
|
||||
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
|
||||
+ ++i) \
|
||||
+ { \
|
||||
+ char *ep; \
|
||||
+ FTYPE r = strto ## FSUF (tests_strto ## FSUF[i].str, &ep); \
|
||||
+ if (r != tests_strto ## FSUF[i].result) \
|
||||
+ { \
|
||||
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
|
||||
+ FTOSTR (buf2, sizeof (buf2), "%g", tests_strto ## FSUF[i].result); \
|
||||
+ printf ("test %zu r = %s, expect %s\n", i, buf1, buf2); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ if (ep != tests_strto ## FSUF[i].str + tests_strto ## FSUF[i].offset) \
|
||||
+ { \
|
||||
+ printf ("test %zu strto" #FSUF \
|
||||
+ " parsed %tu characters, expected %zu\n", \
|
||||
+ i, ep - tests_strto ## FSUF[i].str, \
|
||||
+ tests_strto ## FSUF[i].offset); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ return status; \
|
||||
+}
|
||||
+
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
- int status = 0;
|
||||
- for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
|
||||
- {
|
||||
- char *ep;
|
||||
- double r = strtod (tests[i].str, &ep);
|
||||
- if (r != tests[i].result)
|
||||
- {
|
||||
- printf ("test %zu r = %g, expect %g\n", i, r, tests[i].result);
|
||||
- status = 1;
|
||||
- }
|
||||
- if (ep != tests[i].str + tests[i].offset)
|
||||
- {
|
||||
- printf ("test %zu strtod parsed %tu characters, expected %zu\n",
|
||||
- i, ep - tests[i].str, tests[i].offset);
|
||||
- status = 1;
|
||||
- }
|
||||
- }
|
||||
- return status;
|
||||
+ return STRTOD_TEST_FOREACH (test_strto);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
diff --git a/stdlib/tst-strtod5.c b/stdlib/tst-strtod5.c
|
||||
index 29153ec0057178e9..7eb9b3a2d7f31b2a 100644
|
||||
--- a/stdlib/tst-strtod5.c
|
||||
+++ b/stdlib/tst-strtod5.c
|
||||
@@ -22,35 +22,75 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
+#include "tst-strtod.h"
|
||||
+
|
||||
#define NBSP "\xc2\xa0"
|
||||
|
||||
-static const struct
|
||||
-{
|
||||
- const char *in;
|
||||
- double expected;
|
||||
-} tests[] =
|
||||
- {
|
||||
- { "0", 0.0 },
|
||||
- { "000", 0.0 },
|
||||
- { "-0", -0.0 },
|
||||
- { "-000", -0.0 },
|
||||
- { "0,", 0.0 },
|
||||
- { "-0,", -0.0 },
|
||||
- { "0,0", 0.0 },
|
||||
- { "-0,0", -0.0 },
|
||||
- { "0e-10", 0.0 },
|
||||
- { "-0e-10", -0.0 },
|
||||
- { "0,e-10", 0.0 },
|
||||
- { "-0,e-10", -0.0 },
|
||||
- { "0,0e-10", 0.0 },
|
||||
- { "-0,0e-10", -0.0 },
|
||||
- { "0e-1000000", 0.0 },
|
||||
- { "-0e-1000000", -0.0 },
|
||||
- { "0,0e-1000000", 0.0 },
|
||||
- { "-0,0e-1000000", -0.0 },
|
||||
- };
|
||||
-#define NTESTS (sizeof (tests) / sizeof (tests[0]))
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+static const struct \
|
||||
+{ \
|
||||
+ const char *in; \
|
||||
+ FTYPE expected; \
|
||||
+} tests_strto ## FSUF[] = \
|
||||
+ { \
|
||||
+ { "0", 0.0 ## LSUF }, \
|
||||
+ { "000", 0.0 ## LSUF }, \
|
||||
+ { "-0", -0.0 ## LSUF }, \
|
||||
+ { "-000", -0.0 ## LSUF }, \
|
||||
+ { "0,", 0.0 ## LSUF }, \
|
||||
+ { "-0,", -0.0 ## LSUF }, \
|
||||
+ { "0,0", 0.0 ## LSUF }, \
|
||||
+ { "-0,0", -0.0 ## LSUF }, \
|
||||
+ { "0e-10", 0.0 ## LSUF }, \
|
||||
+ { "-0e-10", -0.0 ## LSUF }, \
|
||||
+ { "0,e-10", 0.0 ## LSUF }, \
|
||||
+ { "-0,e-10", -0.0 ## LSUF }, \
|
||||
+ { "0,0e-10", 0.0 ## LSUF }, \
|
||||
+ { "-0,0e-10", -0.0 ## LSUF }, \
|
||||
+ { "0e-1000000", 0.0 ## LSUF }, \
|
||||
+ { "-0e-1000000", -0.0 ## LSUF }, \
|
||||
+ { "0,0e-1000000", 0.0 ## LSUF }, \
|
||||
+ { "-0,0e-1000000", -0.0 ## LSUF }, \
|
||||
+ }; \
|
||||
+ \
|
||||
+ \
|
||||
+static int \
|
||||
+test_strto ## FSUF (void) \
|
||||
+{ \
|
||||
+ int status = 0; \
|
||||
+ \
|
||||
+ for (int i = 0; \
|
||||
+ i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
|
||||
+ ++i) \
|
||||
+ { \
|
||||
+ char *ep; \
|
||||
+ FTYPE r = strto ## FSUF (tests_strto ## FSUF[i].in, &ep); \
|
||||
+ \
|
||||
+ if (*ep != '\0') \
|
||||
+ { \
|
||||
+ printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (r != tests_strto ## FSUF[i].expected \
|
||||
+ || (copysign ## CSUF (10.0 ## LSUF, r) \
|
||||
+ != copysign ## CSUF (10.0 ## LSUF, \
|
||||
+ tests_strto ## FSUF[i].expected))) \
|
||||
+ { \
|
||||
+ char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf1, sizeof (buf1), "%g", r); \
|
||||
+ FTOSTR (buf2, sizeof (buf2), "%g", \
|
||||
+ tests_strto ## FSUF[i].expected); \
|
||||
+ printf ("%d: got wrong results %s, expected %s\n", \
|
||||
+ i, buf1, buf2); \
|
||||
+ status = 1; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ \
|
||||
+ return status; \
|
||||
+}
|
||||
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -61,29 +101,7 @@ do_test (void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- int status = 0;
|
||||
-
|
||||
- for (int i = 0; i < NTESTS; ++i)
|
||||
- {
|
||||
- char *ep;
|
||||
- double r = strtod (tests[i].in, &ep);
|
||||
-
|
||||
- if (*ep != '\0')
|
||||
- {
|
||||
- printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep);
|
||||
- status = 1;
|
||||
- }
|
||||
-
|
||||
- if (r != tests[i].expected
|
||||
- || copysign (10.0, r) != copysign (10.0, tests[i].expected))
|
||||
- {
|
||||
- printf ("%d: got wrong results %g, expected %g\n",
|
||||
- i, r, tests[i].expected);
|
||||
- status = 1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return status;
|
||||
+ return STRTOD_TEST_FOREACH (test_strto);
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
@ -0,0 +1,81 @@
|
||||
commit 3edc0f22a620fdda6eda69cfd47d96142132943f
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Fri Sep 20 23:24:02 2024 +0000
|
||||
|
||||
Add more tests of strtod end pointer
|
||||
|
||||
Although there are some tests in tst-strtod2 and tst-strtod3 for the
|
||||
end pointer provided by strtod when it doesn't parse the whole string,
|
||||
they aren't very thorough. Add tests of more such cases to
|
||||
tst-strtod2.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit b5d3737b305525315e0c7c93ca49eadc868eabd5)
|
||||
|
||||
diff --git a/stdlib/tst-strtod2.c b/stdlib/tst-strtod2.c
|
||||
index 2cb0953fa911efd0..c84bd792c1a3f511 100644
|
||||
--- a/stdlib/tst-strtod2.c
|
||||
+++ b/stdlib/tst-strtod2.c
|
||||
@@ -1,3 +1,4 @@
|
||||
+#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -17,10 +18,46 @@ struct test_strto ## FSUF \
|
||||
{ "0x.0y", 0.0 ## LSUF, 4 }, \
|
||||
{ ".y", 0.0 ## LSUF, 0 }, \
|
||||
{ "0.y", 0.0 ## LSUF, 2 }, \
|
||||
- { ".0y", 0.0 ## LSUF, 2 } \
|
||||
+ { ".0y", 0.0 ## LSUF, 2 }, \
|
||||
+ { "1.0e", 1.0 ## LSUF, 3 }, \
|
||||
+ { "1.0e+", 1.0 ## LSUF, 3 }, \
|
||||
+ { "1.0e-", 1.0 ## LSUF, 3 }, \
|
||||
+ { "1.0ex", 1.0 ## LSUF, 3 }, \
|
||||
+ { "1.0e+x", 1.0 ## LSUF, 3 }, \
|
||||
+ { "1.0e-x", 1.0 ## LSUF, 3 }, \
|
||||
+ { "0x1p", 1.0 ## LSUF, 3 }, \
|
||||
+ { "0x1p+", 1.0 ## LSUF, 3 }, \
|
||||
+ { "0x1p-", 1.0 ## LSUF, 3 }, \
|
||||
+ { "0x1px", 1.0 ## LSUF, 3 }, \
|
||||
+ { "0x1p+x", 1.0 ## LSUF, 3 }, \
|
||||
+ { "0x1p-x", 1.0 ## LSUF, 3 }, \
|
||||
+ { "INFx", INFINITY, 3 }, \
|
||||
+ { "infx", INFINITY, 3 }, \
|
||||
+ { "INFINITx", INFINITY, 3 }, \
|
||||
+ { "infinitx", INFINITY, 3 }, \
|
||||
+ { "INFINITYY", INFINITY, 8 }, \
|
||||
+ { "infinityy", INFINITY, 8 }, \
|
||||
+ { "NANx", NAN, 3 }, \
|
||||
+ { "nanx", NAN, 3 }, \
|
||||
+ { "NAN(", NAN, 3 }, \
|
||||
+ { "nan(", NAN, 3 }, \
|
||||
+ { "NAN(x", NAN, 3 }, \
|
||||
+ { "nan(x", NAN, 3 }, \
|
||||
+ { "NAN(x)y", NAN, 6 }, \
|
||||
+ { "nan(x)y", NAN, 6 }, \
|
||||
+ { "NAN(*)y", NAN, 3 }, \
|
||||
+ { "nan(*)y", NAN, 3 } \
|
||||
}; \
|
||||
\
|
||||
static int \
|
||||
+compare_strto ## FSUF (FTYPE x, FTYPE y) \
|
||||
+{ \
|
||||
+ if (isnan (x) && isnan (y)) \
|
||||
+ return 1; \
|
||||
+ return x == y; \
|
||||
+} \
|
||||
+ \
|
||||
+static int \
|
||||
test_strto ## FSUF (void) \
|
||||
{ \
|
||||
int status = 0; \
|
||||
@@ -30,7 +67,7 @@ test_strto ## FSUF (void) \
|
||||
{ \
|
||||
char *ep; \
|
||||
FTYPE r = strto ## FSUF (tests_strto ## FSUF[i].str, &ep); \
|
||||
- if (r != tests_strto ## FSUF[i].result) \
|
||||
+ if (!compare_strto ## FSUF (r, tests_strto ## FSUF[i].result)) \
|
||||
{ \
|
||||
char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
|
||||
FTOSTR (buf1, sizeof (buf1), "%g", r); \
|
@ -0,0 +1,40 @@
|
||||
commit fcdf98f38c16ea5c7296b20db2e9f60e9e6ed39e
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Fri Sep 20 23:24:45 2024 +0000
|
||||
|
||||
Add tests of more strtod special cases
|
||||
|
||||
There is very little test coverage of inputs to strtod-family
|
||||
functions that don't contain anything that can be parsed as a number
|
||||
(one test of ".y" in tst-strtod2), and none that I can see of skipping
|
||||
initial whitespace. Add some tests of these things to tst-strtod2.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 378039ca578c2ea93095a1e710d96f58c68a3997)
|
||||
|
||||
diff --git a/stdlib/tst-strtod2.c b/stdlib/tst-strtod2.c
|
||||
index c84bd792c1a3f511..d00bc13323c50622 100644
|
||||
--- a/stdlib/tst-strtod2.c
|
||||
+++ b/stdlib/tst-strtod2.c
|
||||
@@ -31,6 +31,20 @@ struct test_strto ## FSUF \
|
||||
{ "0x1px", 1.0 ## LSUF, 3 }, \
|
||||
{ "0x1p+x", 1.0 ## LSUF, 3 }, \
|
||||
{ "0x1p-x", 1.0 ## LSUF, 3 }, \
|
||||
+ { "", 0.0 ## LSUF, 0 }, \
|
||||
+ { ".", 0.0 ## LSUF, 0 }, \
|
||||
+ { "-", 0.0 ## LSUF, 0 }, \
|
||||
+ { "-.", 0.0 ## LSUF, 0 }, \
|
||||
+ { ".e", 0.0 ## LSUF, 0 }, \
|
||||
+ { "-.e", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t.", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t-", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t-.", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t.e", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t-.e", 0.0 ## LSUF, 0 }, \
|
||||
+ { " \t\f\r\n\v1", 1.0 ## LSUF, 7 }, \
|
||||
+ { " \t\f\r\n\v-1.5e2", -150.0 ## LSUF, 12 }, \
|
||||
{ "INFx", INFINITY, 3 }, \
|
||||
{ "infx", INFINITY, 3 }, \
|
||||
{ "INFINITx", INFINITY, 3 }, \
|
@ -0,0 +1,219 @@
|
||||
commit b74be22f65c017c6f980e608127c260497d7f3c2
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Tue Apr 30 09:57:12 2024 -0700
|
||||
|
||||
Add crt1-2.0.o for glibc 2.0 compatibility tests
|
||||
|
||||
Starting from glibc 2.1, crt1.o contains _IO_stdin_used which is checked
|
||||
by _IO_check_libio to provide binary compatibility for glibc 2.0. Add
|
||||
crt1-2.0.o for tests against glibc 2.0. Define tests-2.0 for glibc 2.0
|
||||
compatibility tests. Add and update glibc 2.0 compatibility tests for
|
||||
stderr, matherr and pthread_kill.
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
(cherry picked from commit 5f245f3bfbe61b2182964dafb94907e38284b806)
|
||||
|
||||
diff --git a/Makeconfig b/Makeconfig
|
||||
index 522182abdc426e70..a6cbb0c6f3149ca8 100644
|
||||
--- a/Makeconfig
|
||||
+++ b/Makeconfig
|
||||
@@ -360,6 +360,8 @@ whole-archive = -Wl,--whole-archive
|
||||
# Installed name of the startup code.
|
||||
# The ELF convention is that the startfile is called crt1.o
|
||||
start-installed-name = crt1.o
|
||||
+# Similar to crt1.o, but without _IO_stdin_used.
|
||||
+start-name-2.0 = crt1-2.0.o
|
||||
# On systems that do not need a special startfile for statically linked
|
||||
# binaries, simply set it to the normal name.
|
||||
ifndef static-start-installed-name
|
||||
@@ -537,6 +539,25 @@ else # build-static
|
||||
endif # build-shared
|
||||
endif # +link
|
||||
|
||||
+# Command for linking test programs with crt1.o from glibc 2.0.
|
||||
++link-2.0-before-inputs = -nostdlib -nostartfiles $(no-pie-ldflag) \
|
||||
+ $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
|
||||
+ $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
|
||||
+ $(firstword $(CRT-$(@F)) $(csu-objpfx)$(start-name-2.0)) \
|
||||
+ $(+preinit) $(+prector)
|
||||
++link-2.0-before-libc = -o $@ $(+link-2.0-before-inputs) \
|
||||
+ $(filter-out $(addprefix $(csu-objpfx),start.o \
|
||||
+ $(start-name-2.0))\
|
||||
+ $(+preinit) $(link-extra-libs) \
|
||||
+ $(common-objpfx)libc% $(+postinit),$^) \
|
||||
+ $(link-extra-libs)
|
||||
++link-after-libc = $(+postctor) $(+postinit)
|
||||
+define +link-2.0-tests
|
||||
+$(CC) $(+link-2.0-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
|
||||
+ $(+link-after-libc)
|
||||
+$(call after-link,$@)
|
||||
+endef
|
||||
+
|
||||
# The pretty printer test programs need to be compiled without optimizations
|
||||
# so they won't confuse gdb. We could use either the 'GCC optimize' pragma
|
||||
# or the 'optimize' function attribute to achieve this; however, at least on
|
||||
diff --git a/Rules b/Rules
|
||||
index dd7dae4a49466e5d..713c225d2ebf5506 100644
|
||||
--- a/Rules
|
||||
+++ b/Rules
|
||||
@@ -197,6 +197,7 @@ binaries-all = $(binaries-all-notests) $(binaries-all-tests)
|
||||
binaries-static-notests = $(others-static)
|
||||
binaries-static-tests = $(tests-static) $(xtests-static)
|
||||
binaries-static = $(binaries-static-notests) $(binaries-static-tests)
|
||||
+binaries-shared-2.0-tests = $(tests-2.0)
|
||||
ifeq (yesyes,$(have-fpie)$(build-shared))
|
||||
binaries-pie-tests = $(tests-pie) $(xtests-pie)
|
||||
binaries-pie-notests = $(others-pie)
|
||||
@@ -224,7 +225,8 @@ binaries-malloc-hugetlb2-tests =
|
||||
endif
|
||||
|
||||
binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests)
|
||||
-binaries-shared-tests = $(filter-out $(binaries-pie) $(binaries-static), \
|
||||
+binaries-shared-tests = $(filter-out $(binaries-pie) $(binaries-static) \
|
||||
+ $(binaries-shared-2.0-tests), \
|
||||
$(binaries-all-tests))
|
||||
binaries-shared-notests = $(filter-out $(binaries-pie) $(binaries-static), \
|
||||
$(binaries-all-notests))
|
||||
@@ -244,6 +246,15 @@ $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \
|
||||
$(+link-tests)
|
||||
endif
|
||||
|
||||
+# Linking test programs with crt1.o from glibc 2.0.
|
||||
+ifneq "$(strip $(binaries-shared-2.0-tests))" ""
|
||||
+$(addprefix $(objpfx),$(binaries-shared-2.0-tests)): %: %.o \
|
||||
+ $(link-extra-libs-tests) \
|
||||
+ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
|
||||
+ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
|
||||
+ $(+link-2.0-tests)
|
||||
+endif
|
||||
+
|
||||
ifneq "$(strip $(binaries-mcheck-tests))" ""
|
||||
$(addprefix $(objpfx),$(binaries-mcheck-tests)): %-mcheck: %.o \
|
||||
$(link-extra-libs-tests) \
|
||||
diff --git a/csu/Makefile b/csu/Makefile
|
||||
index ac05ab24d5df478b..34a8d74971e83885 100644
|
||||
--- a/csu/Makefile
|
||||
+++ b/csu/Makefile
|
||||
@@ -33,7 +33,7 @@ elide-routines.os = libc-tls
|
||||
csu-dummies = $(filter-out $(start-installed-name),crt1.o Mcrt1.o)
|
||||
extra-objs = start.o \
|
||||
$(start-installed-name) g$(start-installed-name) $(csu-dummies) \
|
||||
- S$(start-installed-name)
|
||||
+ S$(start-installed-name) $(start-name-2.0)
|
||||
omit-deps = $(patsubst %.o,%,$(start-installed-name) g$(start-installed-name) \
|
||||
b$(start-installed-name) $(csu-dummies) \
|
||||
S$(start-installed-name) \
|
||||
@@ -138,6 +138,9 @@ ifndef start-installed-name-rule
|
||||
$(objpfx)$(start-installed-name): $(objpfx)start.o $(objpfx)abi-note.o \
|
||||
$(objpfx)init.o $(objpfx)static-reloc.o
|
||||
$(link-relocatable)
|
||||
+$(objpfx)$(start-name-2.0): $(objpfx)start.o $(objpfx)abi-note.o \
|
||||
+ $(objpfx)static-reloc.o
|
||||
+ $(link-relocatable)
|
||||
$(objpfx)r$(start-installed-name): $(objpfx)start.o $(objpfx)abi-note.o \
|
||||
$(objpfx)init.o
|
||||
$(link-relocatable)
|
||||
diff --git a/libio/Makefile b/libio/Makefile
|
||||
index 27623c92a941fd05..b92aeaf62634f1cb 100644
|
||||
--- a/libio/Makefile
|
||||
+++ b/libio/Makefile
|
||||
@@ -212,6 +212,12 @@ aux := fileops genops stdfiles stdio strops
|
||||
ifeq ($(build-shared),yes)
|
||||
generated += tst-bz24228.mtrace tst-bz24228.check
|
||||
aux += oldfileops oldstdfiles
|
||||
+tests += \
|
||||
+ tst-stderr-compat \
|
||||
+# tests
|
||||
+tests-2.0 += \
|
||||
+ tst-stderr-compat \
|
||||
+# tests-2.0
|
||||
endif
|
||||
|
||||
shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \
|
||||
diff --git a/libio/tst-stderr-compat.c b/libio/tst-stderr-compat.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..8221415cd47f25ef
|
||||
--- /dev/null
|
||||
+++ b/libio/tst-stderr-compat.c
|
||||
@@ -0,0 +1,52 @@
|
||||
+/* Test that fclose works on stderr from glibc 2.0.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for 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 <shlib-compat.h>
|
||||
+
|
||||
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
|
||||
+# define _LIBC
|
||||
+# define _IO_USE_OLD_IO_FILE
|
||||
+# include <stdio.h>
|
||||
+# include <support/check.h>
|
||||
+
|
||||
+extern FILE _IO_stderr_;
|
||||
+compat_symbol_reference (libc, _IO_stderr_, _IO_stderr_, GLIBC_2_0);
|
||||
+compat_symbol_reference (libc, fclose, fclose, GLIBC_2_0);
|
||||
+
|
||||
+__attribute__ ((weak, noclone, noinline))
|
||||
+void
|
||||
+do_fclose (FILE *fp)
|
||||
+{
|
||||
+ TEST_VERIFY_EXIT (fclose (fp) == 0);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ do_fclose (&_IO_stderr_);
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/math/Makefile b/math/Makefile
|
||||
index 14107855e88bc96b..c98ee4ee0c1a4022 100644
|
||||
--- a/math/Makefile
|
||||
+++ b/math/Makefile
|
||||
@@ -261,6 +261,9 @@ tests-static = test-fpucw-static test-fpucw-ieee-static \
|
||||
# The tested symbols matherr, _LIB_VERSION have been removed in glibc 2.27.
|
||||
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
|
||||
tests += test-matherr test-matherr-2
|
||||
+tests-2.0 += \
|
||||
+ test-matherr-2 \
|
||||
+ # tests-2.0
|
||||
endif
|
||||
|
||||
# These tests use internal (unexported) GMP functions and are linked
|
||||
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
|
||||
index f9efb5076455e07e..04ea56559ef3a79b 100644
|
||||
--- a/sysdeps/pthread/Makefile
|
||||
+++ b/sysdeps/pthread/Makefile
|
||||
@@ -282,6 +282,10 @@ tests += \
|
||||
tst-vfork2x \
|
||||
# tests
|
||||
|
||||
+tests-2.0 += \
|
||||
+ tst-pthread_kill-exited
|
||||
+ # tests-2.0
|
||||
+
|
||||
tests-time64 += \
|
||||
tst-abstime-time64 \
|
||||
tst-cnd-timedwait-time64 \
|
@ -0,0 +1,441 @@
|
||||
commit b3c51635efb532dd0544e6f4dedd6a184f0ae1a2
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
Date: Fri Sep 20 23:25:32 2024 +0000
|
||||
|
||||
Make tst-strtod-underflow type-generic
|
||||
|
||||
The test tst-strtod-underflow covers various edge cases close to the
|
||||
underflow threshold for strtod (especially cases where underflow on
|
||||
architectures with after-rounding tininess detection depends on the
|
||||
rounding mode). Make it use the type-generic machinery, with
|
||||
corresponding test inputs for each supported floating-point format, so
|
||||
that other functions in the strtod family are tested for underflow
|
||||
edge cases as well.
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
(cherry picked from commit 94ca2c0894f0e1b62625c369cc598a2b9236622c)
|
||||
|
||||
diff --git a/stdlib/tst-strtod-underflow.c b/stdlib/tst-strtod-underflow.c
|
||||
index a5ced18599bbf985..8598b95b6da7fd40 100644
|
||||
--- a/stdlib/tst-strtod-underflow.c
|
||||
+++ b/stdlib/tst-strtod-underflow.c
|
||||
@@ -17,6 +17,10 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
+/* Defining _LIBC_TEST ensures long double math functions are
|
||||
+ declared in the headers. */
|
||||
+#define _LIBC_TEST 1
|
||||
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#include <errno.h>
|
||||
#include <fenv.h>
|
||||
#include <float.h>
|
||||
@@ -25,6 +29,60 @@
|
||||
#include <stdlib.h>
|
||||
#include <tininess.h>
|
||||
|
||||
+#include "tst-strtod.h"
|
||||
+
|
||||
+/* Logic for selecting between tests for different formats is as in
|
||||
+ tst-strtod-skeleton.c, but here it is selecting string inputs with
|
||||
+ different underflow properties, rather than generated test
|
||||
+ data. */
|
||||
+
|
||||
+#define _CONCAT(a, b) a ## b
|
||||
+#define CONCAT(a, b) _CONCAT (a, b)
|
||||
+
|
||||
+#define MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+ const char *s_ ## FSUF;
|
||||
+
|
||||
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
+# define CHOOSE_ld(f,d,...) d
|
||||
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16381
|
||||
+# define CHOOSE_ld(f,d,ld64i,...) ld64i
|
||||
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16382
|
||||
+# define CHOOSE_ld(f,d,ld64i,ld64m,...) ld64m
|
||||
+#elif LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024
|
||||
+# define CHOOSE_ld(f,d,ld64i,ld64m,ld106,...) ld106
|
||||
+#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
|
||||
+# define CHOOSE_ld(f,d,ld64i,ld64m,ld106,ld113,...) ld113
|
||||
+#else
|
||||
+# error "unknown long double format"
|
||||
+#endif
|
||||
+
|
||||
+#define CHOOSE_f(f,...) f
|
||||
+#define CHOOSE_f32(f,...) f
|
||||
+#define CHOOSE_d(f,d,...) d
|
||||
+#define CHOOSE_f64(f,d,...) d
|
||||
+#define CHOOSE_f32x(f,d,...) d
|
||||
+#define CHOOSE_f128(f,d,ld64i,ld64m,ld106,ld113,...) ld113
|
||||
+
|
||||
+#if __HAVE_FLOAT64X
|
||||
+# if FLT64X_MANT_DIG == 113 && FLT64X_MAX_EXP == 16384
|
||||
+# define CHOOSE_f64x(f,d,ld64i,ld64m,ld106,ld113,...) ld113
|
||||
+# elif (FLT64X_MANT_DIG == 64 \
|
||||
+ && FLT64X_MAX_EXP == 16384 \
|
||||
+ && FLT64X_MIN_EXP == -16381)
|
||||
+# define CHOOSE_f64x(f,d,ld64i,...) ld64i
|
||||
+# else
|
||||
+# error "unknown _Float64x format"
|
||||
+# endif
|
||||
+#endif
|
||||
+
|
||||
+#define _XNTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...) \
|
||||
+ CHOOSE_ ## FSUF (__VA_ARGS__),
|
||||
+#define XNTRY(...) \
|
||||
+ GEN_TEST_STRTOD_FOREACH (_XNTRY, __VA_ARGS__)
|
||||
+
|
||||
+#define TEST(f, d, ld64i, ld64m, ld106, ld113, u) \
|
||||
+ { XNTRY(f, d, ld64i, ld64m, ld106, ld113) u }
|
||||
+
|
||||
enum underflow_case
|
||||
{
|
||||
/* Result is exact or outside the subnormal range. */
|
||||
@@ -55,38 +113,194 @@ enum underflow_case
|
||||
|
||||
struct test
|
||||
{
|
||||
- const char *s;
|
||||
+ GEN_TEST_STRTOD_FOREACH (MEMBER)
|
||||
enum underflow_case c;
|
||||
};
|
||||
|
||||
static const struct test tests[] =
|
||||
{
|
||||
- { "0x1p-1022", UNDERFLOW_NONE },
|
||||
- { "-0x1p-1022", UNDERFLOW_NONE },
|
||||
- { "0x0p-10000000000000000000000000", UNDERFLOW_NONE },
|
||||
- { "-0x0p-10000000000000000000000000", UNDERFLOW_NONE },
|
||||
- { "0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS },
|
||||
- { "-0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS },
|
||||
- { "0x1.000000000000000000001p-1022", UNDERFLOW_NONE },
|
||||
- { "-0x1.000000000000000000001p-1022", UNDERFLOW_NONE },
|
||||
- { "0x1p-1075", UNDERFLOW_ALWAYS },
|
||||
- { "-0x1p-1075", UNDERFLOW_ALWAYS },
|
||||
- { "0x1p-1023", UNDERFLOW_NONE },
|
||||
- { "-0x1p-1023", UNDERFLOW_NONE },
|
||||
- { "0x1p-1074", UNDERFLOW_NONE },
|
||||
- { "-0x1p-1074", UNDERFLOW_NONE },
|
||||
- { "0x1.ffffffffffffep-1023", UNDERFLOW_NONE },
|
||||
- { "-0x1.ffffffffffffep-1023", UNDERFLOW_NONE },
|
||||
- { "0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS },
|
||||
- { "-0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS },
|
||||
- { "0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_UPWARD },
|
||||
- { "-0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_DOWNWARD },
|
||||
- { "0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_UPWARD },
|
||||
- { "-0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_DOWNWARD },
|
||||
- { "0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO },
|
||||
- { "-0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_UPWARD_ZERO },
|
||||
- { "0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO },
|
||||
- { "-0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_UPWARD_ZERO },
|
||||
+ TEST ("0x1p-126",
|
||||
+ "0x1p-1022",
|
||||
+ "0x1p-16382",
|
||||
+ "0x1p-16383",
|
||||
+ "0x1p-969",
|
||||
+ "0x1p-16382",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("-0x1p-126",
|
||||
+ "-0x1p-1022",
|
||||
+ "-0x1p-16382",
|
||||
+ "-0x1p-16383",
|
||||
+ "-0x1p-969",
|
||||
+ "-0x1p-16382",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("0x0p-10000000000000000000000000",
|
||||
+ "0x0p-10000000000000000000000000",
|
||||
+ "0x0p-10000000000000000000000000",
|
||||
+ "0x0p-10000000000000000000000000",
|
||||
+ "0x0p-10000000000000000000000000",
|
||||
+ "0x0p-10000000000000000000000000",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("-0x0p-10000000000000000000000000",
|
||||
+ "-0x0p-10000000000000000000000000",
|
||||
+ "-0x0p-10000000000000000000000000",
|
||||
+ "-0x0p-10000000000000000000000000",
|
||||
+ "-0x0p-10000000000000000000000000",
|
||||
+ "-0x0p-10000000000000000000000000",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("0x1p-10000000000000000000000000",
|
||||
+ "0x1p-10000000000000000000000000",
|
||||
+ "0x1p-10000000000000000000000000",
|
||||
+ "0x1p-10000000000000000000000000",
|
||||
+ "0x1p-10000000000000000000000000",
|
||||
+ "0x1p-10000000000000000000000000",
|
||||
+ UNDERFLOW_ALWAYS),
|
||||
+ TEST ("-0x1p-10000000000000000000000000",
|
||||
+ "-0x1p-10000000000000000000000000",
|
||||
+ "-0x1p-10000000000000000000000000",
|
||||
+ "-0x1p-10000000000000000000000000",
|
||||
+ "-0x1p-10000000000000000000000000",
|
||||
+ "-0x1p-10000000000000000000000000",
|
||||
+ UNDERFLOW_ALWAYS),
|
||||
+ TEST ("0x1.000000000000000000001p-126",
|
||||
+ "0x1.000000000000000000001p-1022",
|
||||
+ "0x1.000000000000000000001p-16382",
|
||||
+ "0x1.000000000000000000001p-16383",
|
||||
+ "0x1.000000000000000000001p-969",
|
||||
+ "0x1.00000000000000000000000000000000000000001p-16382",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("-0x1.000000000000000000001p-126",
|
||||
+ "-0x1.000000000000000000001p-1022",
|
||||
+ "-0x1.000000000000000000001p-16382",
|
||||
+ "-0x1.000000000000000000001p-16383",
|
||||
+ "-0x1.000000000000000000001p-969",
|
||||
+ "-0x1.00000000000000000000000000000000000000001p-16382",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("0x1p-150",
|
||||
+ "0x1p-1075",
|
||||
+ "0x1p-16446",
|
||||
+ "0x1p-16447",
|
||||
+ "0x1p-1075",
|
||||
+ "0x1p-16495",
|
||||
+ UNDERFLOW_ALWAYS),
|
||||
+ TEST ("-0x1p-150",
|
||||
+ "-0x1p-1075",
|
||||
+ "-0x1p-16446",
|
||||
+ "-0x1p-16447",
|
||||
+ "-0x1p-1075",
|
||||
+ "-0x1p-16495",
|
||||
+ UNDERFLOW_ALWAYS),
|
||||
+ TEST ("0x1p-127",
|
||||
+ "0x1p-1023",
|
||||
+ "0x1p-16383",
|
||||
+ "0x1p-16384",
|
||||
+ "0x1p-970",
|
||||
+ "0x1p-16383",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("-0x1p-127",
|
||||
+ "-0x1p-1023",
|
||||
+ "-0x1p-16383",
|
||||
+ "-0x1p-16384",
|
||||
+ "-0x1p-970",
|
||||
+ "-0x1p-16383",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("0x1p-149",
|
||||
+ "0x1p-1074",
|
||||
+ "0x1p-16445",
|
||||
+ "0x1p-16446",
|
||||
+ "0x1p-1074",
|
||||
+ "0x1p-16494",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("-0x1p-149",
|
||||
+ "-0x1p-1074",
|
||||
+ "-0x1p-16445",
|
||||
+ "-0x1p-16446",
|
||||
+ "-0x1p-1074",
|
||||
+ "-0x1p-16494",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("0x1.fffffcp-127",
|
||||
+ "0x1.ffffffffffffep-1023",
|
||||
+ "0x1.fffffffffffffffcp-16383",
|
||||
+ "0x1.fffffffffffffffcp-16384",
|
||||
+ "0x1.ffffffffffffffffffffffffffp-970",
|
||||
+ "0x1.fffffffffffffffffffffffffffep-16383",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("-0x1.fffffcp-127",
|
||||
+ "-0x1.ffffffffffffep-1023",
|
||||
+ "-0x1.fffffffffffffffcp-16383",
|
||||
+ "-0x1.fffffffffffffffcp-16384",
|
||||
+ "-0x1.ffffffffffffffffffffffffffp-970",
|
||||
+ "-0x1.fffffffffffffffffffffffffffep-16383",
|
||||
+ UNDERFLOW_NONE),
|
||||
+ TEST ("0x1.fffffep-127",
|
||||
+ "0x1.fffffffffffffp-1023",
|
||||
+ "0x1.fffffffffffffffep-16383",
|
||||
+ "0x1.fffffffffffffffep-16384",
|
||||
+ "0x1.ffffffffffffffffffffffffff8p-970",
|
||||
+ "0x1.ffffffffffffffffffffffffffffp-16383",
|
||||
+ UNDERFLOW_ALWAYS),
|
||||
+ TEST ("-0x1.fffffep-127",
|
||||
+ "-0x1.fffffffffffffp-1023",
|
||||
+ "-0x1.fffffffffffffffep-16383",
|
||||
+ "-0x1.fffffffffffffffep-16384",
|
||||
+ "-0x1.ffffffffffffffffffffffffff8p-970",
|
||||
+ "-0x1.ffffffffffffffffffffffffffffp-16383",
|
||||
+ UNDERFLOW_ALWAYS),
|
||||
+ TEST ("0x1.fffffe0001p-127",
|
||||
+ "0x1.fffffffffffff0001p-1023",
|
||||
+ "0x1.fffffffffffffffe0001p-16383",
|
||||
+ "0x1.fffffffffffffffe0001p-16384",
|
||||
+ "0x1.ffffffffffffffffffffffffff80001p-970",
|
||||
+ "0x1.ffffffffffffffffffffffffffff0001p-16383",
|
||||
+ UNDERFLOW_EXCEPT_UPWARD),
|
||||
+ TEST ("-0x1.fffffe0001p-127",
|
||||
+ "-0x1.fffffffffffff0001p-1023",
|
||||
+ "-0x1.fffffffffffffffe0001p-16383",
|
||||
+ "-0x1.fffffffffffffffe0001p-16384",
|
||||
+ "-0x1.ffffffffffffffffffffffffff80001p-970",
|
||||
+ "-0x1.ffffffffffffffffffffffffffff0001p-16383",
|
||||
+ UNDERFLOW_EXCEPT_DOWNWARD),
|
||||
+ TEST ("0x1.fffffeffffp-127",
|
||||
+ "0x1.fffffffffffff7fffp-1023",
|
||||
+ "0x1.fffffffffffffffeffffp-16383",
|
||||
+ "0x1.fffffffffffffffeffffp-16384",
|
||||
+ "0x1.ffffffffffffffffffffffffffbffffp-970",
|
||||
+ "0x1.ffffffffffffffffffffffffffff7fffp-16383",
|
||||
+ UNDERFLOW_EXCEPT_UPWARD),
|
||||
+ TEST ("-0x1.fffffeffffp-127",
|
||||
+ "-0x1.fffffffffffff7fffp-1023",
|
||||
+ "-0x1.fffffffffffffffeffffp-16383",
|
||||
+ "-0x1.fffffffffffffffeffffp-16384",
|
||||
+ "-0x1.ffffffffffffffffffffffffffbffffp-970",
|
||||
+ "-0x1.ffffffffffffffffffffffffffff7fffp-16383",
|
||||
+ UNDERFLOW_EXCEPT_DOWNWARD),
|
||||
+ TEST ("0x1.ffffffp-127",
|
||||
+ "0x1.fffffffffffff8p-1023",
|
||||
+ "0x1.ffffffffffffffffp-16383",
|
||||
+ "0x1.ffffffffffffffffp-16384",
|
||||
+ "0x1.ffffffffffffffffffffffffffcp-970",
|
||||
+ "0x1.ffffffffffffffffffffffffffff8p-16383",
|
||||
+ UNDERFLOW_ONLY_DOWNWARD_ZERO),
|
||||
+ TEST ("-0x1.ffffffp-127",
|
||||
+ "-0x1.fffffffffffff8p-1023",
|
||||
+ "-0x1.ffffffffffffffffp-16383",
|
||||
+ "-0x1.ffffffffffffffffp-16384",
|
||||
+ "-0x1.ffffffffffffffffffffffffffcp-970",
|
||||
+ "-0x1.ffffffffffffffffffffffffffff8p-16383",
|
||||
+ UNDERFLOW_ONLY_UPWARD_ZERO),
|
||||
+ TEST ("0x1.ffffffffffp-127",
|
||||
+ "0x1.fffffffffffffffffp-1023",
|
||||
+ "0x1.ffffffffffffffffffffp-16383",
|
||||
+ "0x1.ffffffffffffffffffffp-16384",
|
||||
+ "0x1.ffffffffffffffffffffffffffffffp-970",
|
||||
+ "0x1.ffffffffffffffffffffffffffffffffp-16383",
|
||||
+ UNDERFLOW_ONLY_DOWNWARD_ZERO),
|
||||
+ TEST ("-0x1.ffffffffffp-127",
|
||||
+ "-0x1.fffffffffffffffffp-1023",
|
||||
+ "-0x1.ffffffffffffffffffffp-16383",
|
||||
+ "-0x1.ffffffffffffffffffffp-16384",
|
||||
+ "-0x1.ffffffffffffffffffffffffffffffp-970",
|
||||
+ "-0x1.ffffffffffffffffffffffffffffffffp-16383",
|
||||
+ UNDERFLOW_ONLY_UPWARD_ZERO),
|
||||
};
|
||||
|
||||
/* Return whether to expect underflow from a particular testcase, in a
|
||||
@@ -133,39 +347,62 @@ static bool support_underflow_exception = false;
|
||||
volatile double d = DBL_MIN;
|
||||
volatile double dd;
|
||||
|
||||
-static int
|
||||
-test_in_one_mode (const char *s, enum underflow_case c, int rm,
|
||||
- const char *mode_name)
|
||||
+static bool
|
||||
+test_got_fe_underflow (void)
|
||||
{
|
||||
- int result = 0;
|
||||
- feclearexcept (FE_ALL_EXCEPT);
|
||||
- errno = 0;
|
||||
- double d = strtod (s, NULL);
|
||||
- int got_errno = errno;
|
||||
#ifdef FE_UNDERFLOW
|
||||
- bool got_fe_underflow = fetestexcept (FE_UNDERFLOW) != 0;
|
||||
+ return fetestexcept (FE_UNDERFLOW) != 0;
|
||||
#else
|
||||
- bool got_fe_underflow = false;
|
||||
+ return false;
|
||||
#endif
|
||||
- printf ("strtod (%s) (%s) returned %a, errno = %d, %sunderflow exception\n",
|
||||
- s, mode_name, d, got_errno, got_fe_underflow ? "" : "no ");
|
||||
- bool this_expect_underflow = expect_underflow (c, rm);
|
||||
- if (got_errno != 0 && got_errno != ERANGE)
|
||||
- {
|
||||
- puts ("FAIL: errno neither 0 nor ERANGE");
|
||||
- result = 1;
|
||||
- }
|
||||
- else if (this_expect_underflow != (errno == ERANGE))
|
||||
- {
|
||||
- puts ("FAIL: underflow from errno differs from expectations");
|
||||
- result = 1;
|
||||
- }
|
||||
- if (support_underflow_exception && got_fe_underflow != this_expect_underflow)
|
||||
- {
|
||||
- puts ("FAIL: underflow from exceptions differs from expectations");
|
||||
- result = 1;
|
||||
- }
|
||||
- return result;
|
||||
+}
|
||||
+
|
||||
+#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
+static int \
|
||||
+test_strto ## FSUF (int i, int rm, const char *mode_name) \
|
||||
+{ \
|
||||
+ const char *s = tests[i].s_ ## FSUF; \
|
||||
+ enum underflow_case c = tests[i].c; \
|
||||
+ int result = 0; \
|
||||
+ feclearexcept (FE_ALL_EXCEPT); \
|
||||
+ errno = 0; \
|
||||
+ FTYPE d = strto ## FSUF (s, NULL); \
|
||||
+ int got_errno = errno; \
|
||||
+ bool got_fe_underflow = test_got_fe_underflow (); \
|
||||
+ char buf[FSTRLENMAX]; \
|
||||
+ FTOSTR (buf, sizeof (buf), "%a", d); \
|
||||
+ printf ("strto" #FSUF \
|
||||
+ " (%s) (%s) returned %s, errno = %d, " \
|
||||
+ "%sunderflow exception\n", \
|
||||
+ s, mode_name, buf, got_errno, \
|
||||
+ got_fe_underflow ? "" : "no "); \
|
||||
+ bool this_expect_underflow = expect_underflow (c, rm); \
|
||||
+ if (got_errno != 0 && got_errno != ERANGE) \
|
||||
+ { \
|
||||
+ puts ("FAIL: errno neither 0 nor ERANGE"); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ else if (this_expect_underflow != (errno == ERANGE)) \
|
||||
+ { \
|
||||
+ puts ("FAIL: underflow from errno differs from expectations"); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ if (support_underflow_exception \
|
||||
+ && got_fe_underflow != this_expect_underflow) \
|
||||
+ { \
|
||||
+ puts ("FAIL: underflow from exceptions " \
|
||||
+ "differs from expectations"); \
|
||||
+ result = 1; \
|
||||
+ } \
|
||||
+ return result; \
|
||||
+}
|
||||
+
|
||||
+GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
|
||||
+
|
||||
+static int
|
||||
+test_in_one_mode (size_t i, int rm, const char *mode_name)
|
||||
+{
|
||||
+ return STRTOD_TEST_FOREACH (test_strto, i, rm, mode_name);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -191,12 +428,12 @@ do_test (void)
|
||||
#endif
|
||||
for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
|
||||
{
|
||||
- result |= test_in_one_mode (tests[i].s, tests[i].c, fe_tonearest,
|
||||
+ result |= test_in_one_mode (i, fe_tonearest,
|
||||
"default rounding mode");
|
||||
#ifdef FE_DOWNWARD
|
||||
if (!fesetround (FE_DOWNWARD))
|
||||
{
|
||||
- result |= test_in_one_mode (tests[i].s, tests[i].c, FE_DOWNWARD,
|
||||
+ result |= test_in_one_mode (i, FE_DOWNWARD,
|
||||
"FE_DOWNWARD");
|
||||
fesetround (save_round_mode);
|
||||
}
|
||||
@@ -204,7 +441,7 @@ do_test (void)
|
||||
#ifdef FE_TOWARDZERO
|
||||
if (!fesetround (FE_TOWARDZERO))
|
||||
{
|
||||
- result |= test_in_one_mode (tests[i].s, tests[i].c, FE_TOWARDZERO,
|
||||
+ result |= test_in_one_mode (i, FE_TOWARDZERO,
|
||||
"FE_TOWARDZERO");
|
||||
fesetround (save_round_mode);
|
||||
}
|
||||
@@ -212,7 +449,7 @@ do_test (void)
|
||||
#ifdef FE_UPWARD
|
||||
if (!fesetround (FE_UPWARD))
|
||||
{
|
||||
- result |= test_in_one_mode (tests[i].s, tests[i].c, FE_UPWARD,
|
||||
+ result |= test_in_one_mode (i, FE_UPWARD,
|
||||
"FE_UPWARD");
|
||||
fesetround (save_round_mode);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
commit dcaf51b41e259387602774829c45222d0507f90a
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Oct 28 14:45:30 2024 +0100
|
||||
|
||||
elf: Change ldconfig auxcache magic number (bug 32231)
|
||||
|
||||
In commit c628c2296392ed3bf2cb8d8470668e64fe53389f (elf: Remove
|
||||
ldconfig kernel version check), the layout of auxcache entries
|
||||
changed because the osversion field was removed from
|
||||
struct aux_cache_file_entry. However, AUX_CACHEMAGIC was not
|
||||
changed, so existing files are still used, potentially leading
|
||||
to unintended ldconfig behavior. This commit changes AUX_CACHEMAGIC,
|
||||
so that the file is regenerated.
|
||||
|
||||
Reported-by: DJ Delorie <dj@redhat.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit 0a536f6e2f76e3ef581b3fd9af1e5cf4ddc7a5a2)
|
||||
|
||||
diff --git a/elf/cache.c b/elf/cache.c
|
||||
index 8a618e11fa414abb..62d681df42746d55 100644
|
||||
--- a/elf/cache.c
|
||||
+++ b/elf/cache.c
|
||||
@@ -820,7 +820,7 @@ struct aux_cache_entry
|
||||
struct aux_cache_entry *next;
|
||||
};
|
||||
|
||||
-#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
|
||||
+#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-2.0"
|
||||
|
||||
struct aux_cache_file_entry
|
||||
{
|
@ -0,0 +1,196 @@
|
||||
commit 3b25c7fa878c01f9e656701b5d59438ea2e49ba4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Wed Jun 26 11:27:54 2024 +0200
|
||||
|
||||
Enhance test coverage for strnlen, wcsnlen
|
||||
|
||||
This commit adds string/test-strnlen-nonarray and
|
||||
wcsmbs/test-wcsnlen-nonarray.
|
||||
|
||||
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||
(cherry picked from commit 783d4c0b81889c39a9ddf13b60d0fde4040fb1c0)
|
||||
|
||||
diff --git a/string/Makefile b/string/Makefile
|
||||
index 8f31fa49e621c035..2e20fc00fdd8d607 100644
|
||||
--- a/string/Makefile
|
||||
+++ b/string/Makefile
|
||||
@@ -184,6 +184,7 @@ tests := \
|
||||
test-strncpy \
|
||||
test-strndup \
|
||||
test-strnlen \
|
||||
+ test-strnlen-nonarray \
|
||||
test-strpbrk \
|
||||
test-strrchr \
|
||||
test-strspn \
|
||||
diff --git a/string/test-Xnlen-nonarray.c b/string/test-Xnlen-nonarray.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..499bef2041ac4ae1
|
||||
--- /dev/null
|
||||
+++ b/string/test-Xnlen-nonarray.c
|
||||
@@ -0,0 +1,133 @@
|
||||
+/* Test non-array inputs to string length functions.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* This skeleton file is included from string/test-strnlen-nonarray.c
|
||||
+ and wcsmbs/test-wcsnlen-nonarray.c to test that reading of the array
|
||||
+ stops at the first null character.
|
||||
+
|
||||
+ TEST_IDENTIFIER must be the test function identifier. TEST_NAME is
|
||||
+ the same as a string.
|
||||
+
|
||||
+ CHAR must be defined as the character type. */
|
||||
+
|
||||
+#include <array_length.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <sys/param.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+typedef __typeof (TEST_IDENTIFIER) *proto_t;
|
||||
+
|
||||
+#define TEST_MAIN
|
||||
+#include "test-string.h"
|
||||
+
|
||||
+IMPL (TEST_IDENTIFIER, 1)
|
||||
+
|
||||
+static int
|
||||
+test_main (void)
|
||||
+{
|
||||
+ enum { buffer_length = 256 };
|
||||
+ TEST_VERIFY_EXIT (sysconf (_SC_PAGESIZE) >= buffer_length);
|
||||
+
|
||||
+ test_init ();
|
||||
+
|
||||
+ /* Buffer layout: There are a_count 'A' character followed by
|
||||
+ zero_count null character, for a total of buffer_length
|
||||
+ character:
|
||||
+
|
||||
+ AAAAA...AAAAA 00000 ... 00000 (unmapped page follows)
|
||||
+ \ / \ /
|
||||
+ (a_count) (zero_count)
|
||||
+ \___ (buffer_length) ___/
|
||||
+ ^
|
||||
+ |
|
||||
+ start_offset
|
||||
+
|
||||
+ The buffer length does not change, but a_count (and thus _zero)
|
||||
+ and start_offset vary.
|
||||
+
|
||||
+ If start_offset == buffer_length, only 0 is a valid length
|
||||
+ argument. The result is 0.
|
||||
+
|
||||
+ Otherwwise, if zero_count > 0 (if there a null characters in the
|
||||
+ buffer), then any length argument is valid. If start_offset <
|
||||
+ a_count (i.e., there is a non-null character at start_offset), the
|
||||
+ result is the minimum of a_count - start_offset and the length
|
||||
+ argument. Otherwise the result is 0.
|
||||
+
|
||||
+ Otherwise, there are no null characters before the unmapped page.
|
||||
+ The length argument must not be greater than buffer_length -
|
||||
+ start_offset, and the result is the length argument. */
|
||||
+
|
||||
+ struct support_next_to_fault ntf
|
||||
+ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR));
|
||||
+ CHAR *buffer = (CHAR *) ntf.buffer;
|
||||
+
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ {
|
||||
+ printf ("info: testing %s\n", impl->name);
|
||||
+ for (size_t i = 0; i < buffer_length; ++i)
|
||||
+ buffer[i] = 'A';
|
||||
+
|
||||
+ for (int zero_count = 0; zero_count <= buffer_length; ++zero_count)
|
||||
+ {
|
||||
+ if (zero_count > 0)
|
||||
+ buffer[buffer_length - zero_count] = 0;
|
||||
+ int a_count = buffer_length - zero_count;
|
||||
+ for (int start_offset = 0; start_offset <= buffer_length;
|
||||
+ ++start_offset)
|
||||
+ {
|
||||
+ CHAR *start_pointer = buffer + start_offset;
|
||||
+ if (start_offset == buffer_length)
|
||||
+ TEST_COMPARE (CALL (impl, buffer + start_offset, 0), 0);
|
||||
+ else if (zero_count > 0)
|
||||
+ for (int length_argument = 0;
|
||||
+ length_argument <= 2 * buffer_length;
|
||||
+ ++length_argument)
|
||||
+ {
|
||||
+ if (test_verbose)
|
||||
+ printf ("zero_count=%d a_count=%d start_offset=%d"
|
||||
+ " length_argument=%d\n",
|
||||
+ zero_count, a_count, start_offset,
|
||||
+ length_argument);
|
||||
+ if (start_offset < a_count)
|
||||
+ TEST_COMPARE (CALL (impl, start_pointer, length_argument),
|
||||
+ MIN (a_count - start_offset,
|
||||
+ length_argument));
|
||||
+ else
|
||||
+ TEST_COMPARE (CALL (impl, start_pointer, length_argument),
|
||||
+ 0);
|
||||
+ }
|
||||
+ else
|
||||
+ for (int length_argument = 0;
|
||||
+ length_argument <= buffer_length - start_offset;
|
||||
+ ++length_argument)
|
||||
+ TEST_COMPARE (CALL (impl, start_pointer, length_argument),
|
||||
+ length_argument);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ support_next_to_fault_free (&ntf);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/string/test-strnlen-nonarray.c b/string/test-strnlen-nonarray.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0ad05756d9a31a3d
|
||||
--- /dev/null
|
||||
+++ b/string/test-strnlen-nonarray.c
|
||||
@@ -0,0 +1,4 @@
|
||||
+#define TEST_IDENTIFIER strnlen
|
||||
+#define TEST_NAME "strnlen"
|
||||
+typedef char CHAR;
|
||||
+#include "test-Xnlen-nonarray.c"
|
||||
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
|
||||
index 65173e28aabf9f85..23da6f0eed55d543 100644
|
||||
--- a/wcsmbs/Makefile
|
||||
+++ b/wcsmbs/Makefile
|
||||
@@ -160,6 +160,7 @@ tests := \
|
||||
test-wcsncmp \
|
||||
test-wcsncpy \
|
||||
test-wcsnlen \
|
||||
+ test-wcsnlen-nonarray \
|
||||
test-wcspbrk \
|
||||
test-wcsrchr \
|
||||
test-wcsspn \
|
||||
diff --git a/wcsmbs/test-wcsnlen-nonarray.c b/wcsmbs/test-wcsnlen-nonarray.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..a4b21fecd388448a
|
||||
--- /dev/null
|
||||
+++ b/wcsmbs/test-wcsnlen-nonarray.c
|
||||
@@ -0,0 +1,5 @@
|
||||
+#include <wchar.h>
|
||||
+#define TEST_IDENTIFIER wcsnlen
|
||||
+#define TEST_NAME "wcsnlen"
|
||||
+typedef wchar_t CHAR;
|
||||
+#include "../string/test-Xnlen-nonarray.c"
|
@ -0,0 +1,257 @@
|
||||
commit 127ef30c46586cfe9fa3e19ad074280b139c84c4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Jun 27 16:26:56 2024 +0200
|
||||
|
||||
Enhanced test coverage for strncmp, wcsncmp
|
||||
|
||||
Add string/test-strncmp-nonarray and
|
||||
wcsmbs/test-wcsncmp-nonarray.
|
||||
|
||||
This is the test that uncovered bug 31934. Test run time
|
||||
is more than one minute on a fairly current system, so turn
|
||||
these into xtests that do not run automatically.
|
||||
|
||||
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||
(cherry picked from commit 54252394c25ddf0062e288d4a6ab7a885f8ae009)
|
||||
|
||||
diff --git a/string/Makefile b/string/Makefile
|
||||
index 2e20fc00fdd8d607..1dff405c273d1b31 100644
|
||||
--- a/string/Makefile
|
||||
+++ b/string/Makefile
|
||||
@@ -236,7 +236,10 @@ tests-unsupported += $(tests-translation)
|
||||
endif
|
||||
|
||||
# This test allocates a lot of memory and can run for a long time.
|
||||
-xtests = tst-strcoll-overflow
|
||||
+xtests += tst-strcoll-overflow
|
||||
+
|
||||
+# This test runs for a long time.
|
||||
+xtests += test-strncmp-nonarray
|
||||
|
||||
# This test needs libdl.
|
||||
ifeq (yes,$(build-shared))
|
||||
diff --git a/string/test-Xncmp-nonarray.c b/string/test-Xncmp-nonarray.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..9f3a3ca75d0e6827
|
||||
--- /dev/null
|
||||
+++ b/string/test-Xncmp-nonarray.c
|
||||
@@ -0,0 +1,183 @@
|
||||
+/* Test non-array inputs to string comparison functions.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* This skeleton file is included from string/test-strncmp-nonarray.c and
|
||||
+ wcsmbs/test-wcsncmp-nonarray.c to test that reading of the arrays stops
|
||||
+ at the first null character.
|
||||
+
|
||||
+ TEST_IDENTIFIER must be the test function identifier. TEST_NAME is
|
||||
+ the same as a string.
|
||||
+
|
||||
+ CHAR must be defined as the character type. */
|
||||
+
|
||||
+#include <array_length.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <sys/param.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Much shorter than test-Xnlen-nonarray.c because of deeply nested loops. */
|
||||
+enum { buffer_length = 80 };
|
||||
+
|
||||
+/* The test buffer layout follows what is described test-Xnlen-nonarray.c,
|
||||
+ except that there two buffers, left and right. The variables
|
||||
+ a_count, zero_count, start_offset are all duplicated. */
|
||||
+
|
||||
+/* Return the maximum string length for a string that starts at
|
||||
+ start_offset. */
|
||||
+static int
|
||||
+string_length (int a_count, int start_offset)
|
||||
+{
|
||||
+ if (start_offset == buffer_length || start_offset >= a_count)
|
||||
+ return 0;
|
||||
+ else
|
||||
+ return a_count - start_offset;
|
||||
+}
|
||||
+
|
||||
+/* This is the valid maximum length argument computation for
|
||||
+ strnlen/wcsnlen. See text-Xnlen-nonarray.c. */
|
||||
+static int
|
||||
+maximum_length (int start_offset, int zero_count)
|
||||
+{
|
||||
+ if (start_offset == buffer_length)
|
||||
+ return 0;
|
||||
+ else if (zero_count > 0)
|
||||
+ /* Effectively unbounded, but we need to stop fairly low,
|
||||
+ otherwise testing takes too long. */
|
||||
+ return buffer_length + 32;
|
||||
+ else
|
||||
+ return buffer_length - start_offset;
|
||||
+}
|
||||
+
|
||||
+typedef __typeof (TEST_IDENTIFIER) *proto_t;
|
||||
+
|
||||
+#define TEST_MAIN
|
||||
+#include "test-string.h"
|
||||
+
|
||||
+IMPL (TEST_IDENTIFIER, 1)
|
||||
+
|
||||
+static int
|
||||
+test_main (void)
|
||||
+{
|
||||
+ TEST_VERIFY_EXIT (sysconf (_SC_PAGESIZE) >= buffer_length);
|
||||
+ test_init ();
|
||||
+
|
||||
+ struct support_next_to_fault left_ntf
|
||||
+ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR));
|
||||
+ CHAR *left_buffer = (CHAR *) left_ntf.buffer;
|
||||
+ struct support_next_to_fault right_ntf
|
||||
+ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR));
|
||||
+ CHAR *right_buffer = (CHAR *) right_ntf.buffer;
|
||||
+
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ {
|
||||
+ printf ("info: testing %s\n", impl->name);
|
||||
+ for (size_t i = 0; i < buffer_length; ++i)
|
||||
+ left_buffer[i] = 'A';
|
||||
+
|
||||
+ for (int left_zero_count = 0; left_zero_count <= buffer_length;
|
||||
+ ++left_zero_count)
|
||||
+ {
|
||||
+ if (left_zero_count > 0)
|
||||
+ left_buffer[buffer_length - left_zero_count] = 0;
|
||||
+ int left_a_count = buffer_length - left_zero_count;
|
||||
+ for (size_t i = 0; i < buffer_length; ++i)
|
||||
+ right_buffer[i] = 'A';
|
||||
+ for (int right_zero_count = 0; right_zero_count <= buffer_length;
|
||||
+ ++right_zero_count)
|
||||
+ {
|
||||
+ if (right_zero_count > 0)
|
||||
+ right_buffer[buffer_length - right_zero_count] = 0;
|
||||
+ int right_a_count = buffer_length - right_zero_count;
|
||||
+ for (int left_start_offset = 0;
|
||||
+ left_start_offset <= buffer_length;
|
||||
+ ++left_start_offset)
|
||||
+ {
|
||||
+ CHAR *left_start_pointer = left_buffer + left_start_offset;
|
||||
+ int left_maxlen
|
||||
+ = maximum_length (left_start_offset, left_zero_count);
|
||||
+ int left_length
|
||||
+ = string_length (left_a_count, left_start_offset);
|
||||
+ for (int right_start_offset = 0;
|
||||
+ right_start_offset <= buffer_length;
|
||||
+ ++right_start_offset)
|
||||
+ {
|
||||
+ CHAR *right_start_pointer
|
||||
+ = right_buffer + right_start_offset;
|
||||
+ int right_maxlen
|
||||
+ = maximum_length (right_start_offset, right_zero_count);
|
||||
+ int right_length
|
||||
+ = string_length (right_a_count, right_start_offset);
|
||||
+
|
||||
+ /* Maximum length is modelled after strnlen/wcsnlen,
|
||||
+ and must be valid for both pointer arguments at
|
||||
+ the same time. */
|
||||
+ int maxlen = MIN (left_maxlen, right_maxlen);
|
||||
+
|
||||
+ for (int length_argument = 0; length_argument <= maxlen;
|
||||
+ ++length_argument)
|
||||
+ {
|
||||
+ if (test_verbose)
|
||||
+ {
|
||||
+ printf ("left: zero_count=%d"
|
||||
+ " a_count=%d start_offset=%d\n",
|
||||
+ left_zero_count, left_a_count,
|
||||
+ left_start_offset);
|
||||
+ printf ("right: zero_count=%d"
|
||||
+ " a_count=%d start_offset=%d\n",
|
||||
+ right_zero_count, right_a_count,
|
||||
+ right_start_offset);
|
||||
+ printf ("length argument: %d\n",
|
||||
+ length_argument);
|
||||
+ }
|
||||
+
|
||||
+ /* Effective lengths bounded by length argument.
|
||||
+ The effective length determines the
|
||||
+ outcome of the comparison. */
|
||||
+ int left_effective
|
||||
+ = MIN (left_length, length_argument);
|
||||
+ int right_effective
|
||||
+ = MIN (right_length, length_argument);
|
||||
+ if (left_effective == right_effective)
|
||||
+ TEST_COMPARE (CALL (impl,
|
||||
+ left_start_pointer,
|
||||
+ right_start_pointer,
|
||||
+ length_argument), 0);
|
||||
+ else if (left_effective < right_effective)
|
||||
+ TEST_COMPARE (CALL (impl,
|
||||
+ left_start_pointer,
|
||||
+ right_start_pointer,
|
||||
+ length_argument) < 0, 1);
|
||||
+ else
|
||||
+ TEST_COMPARE (CALL (impl,
|
||||
+ left_start_pointer,
|
||||
+ right_start_pointer,
|
||||
+ length_argument) > 0, 1);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/string/test-strncmp-nonarray.c b/string/test-strncmp-nonarray.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..581e52d01b0a6ae8
|
||||
--- /dev/null
|
||||
+++ b/string/test-strncmp-nonarray.c
|
||||
@@ -0,0 +1,4 @@
|
||||
+#define TEST_IDENTIFIER strncmp
|
||||
+#define TEST_NAME "strncmp"
|
||||
+typedef char CHAR;
|
||||
+#include "test-Xncmp-nonarray.c"
|
||||
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
|
||||
index 23da6f0eed55d543..6eb38c2dcd7a8c95 100644
|
||||
--- a/wcsmbs/Makefile
|
||||
+++ b/wcsmbs/Makefile
|
||||
@@ -205,6 +205,10 @@ tests := \
|
||||
wcsmbs-tst1 \
|
||||
# tests
|
||||
|
||||
+# This test runs for a long time.
|
||||
+xtests += test-wcsncmp-nonarray
|
||||
+
|
||||
+
|
||||
include ../Rules
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
diff --git a/wcsmbs/test-wcsncmp-nonarray.c b/wcsmbs/test-wcsncmp-nonarray.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..1ad9ebd8fdf7466f
|
||||
--- /dev/null
|
||||
+++ b/wcsmbs/test-wcsncmp-nonarray.c
|
||||
@@ -0,0 +1,5 @@
|
||||
+#include <wchar.h>
|
||||
+#define TEST_IDENTIFIER wcsncmp
|
||||
+#define TEST_NAME "wcsncmp"
|
||||
+typedef wchar_t CHAR;
|
||||
+#include "../string/test-Xncmp-nonarray.c"
|
@ -0,0 +1,50 @@
|
||||
commit 9f349d02c6065f77b485526b3d76a637f6f079dc
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Wed Jul 24 14:05:13 2024 -0700
|
||||
|
||||
linux: Update the mremap C implementation [BZ #31968]
|
||||
|
||||
Update the mremap C implementation to support the optional argument for
|
||||
MREMAP_DONTUNMAP added in Linux 5.7 since it may not always be correct
|
||||
to implement a variadic function as a non-variadic function on all Linux
|
||||
targets. Return MAP_FAILED and set errno to EINVAL for unknown flag bits.
|
||||
This fixes BZ #31968.
|
||||
|
||||
Note: A test must be added when a new flag bit is introduced.
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit 6c40cb0e9f893d49dc7caee580a055de53562206)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/mremap.c b/sysdeps/unix/sysv/linux/mremap.c
|
||||
index 4f770799c4f2fd18..1ada5c1f40dec1f6 100644
|
||||
--- a/sysdeps/unix/sysv/linux/mremap.c
|
||||
+++ b/sysdeps/unix/sysv/linux/mremap.c
|
||||
@@ -20,6 +20,12 @@
|
||||
#include <sysdep.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
+#include <errno.h>
|
||||
+
|
||||
+#define MREMAP_KNOWN_BITS \
|
||||
+ (MREMAP_MAYMOVE \
|
||||
+ | MREMAP_FIXED \
|
||||
+ | MREMAP_DONTUNMAP)
|
||||
|
||||
void *
|
||||
__mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
|
||||
@@ -27,7 +33,13 @@ __mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
|
||||
va_list va;
|
||||
void *new_addr = NULL;
|
||||
|
||||
- if (flags & MREMAP_FIXED)
|
||||
+ if (flags & ~(MREMAP_KNOWN_BITS))
|
||||
+ {
|
||||
+ __set_errno (EINVAL);
|
||||
+ return MAP_FAILED;
|
||||
+ }
|
||||
+
|
||||
+ if (flags & (MREMAP_FIXED | MREMAP_DONTUNMAP))
|
||||
{
|
||||
va_start (va, flags);
|
||||
new_addr = va_arg (va, void *);
|
@ -0,0 +1,83 @@
|
||||
commit a8c230c881b24af0f6f3f9105f6cd0e7bc05b0de
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Wed Jul 24 14:05:14 2024 -0700
|
||||
|
||||
mremap: Update manual entry
|
||||
|
||||
Update mremap manual entry:
|
||||
|
||||
1. Change mremap to variadic.
|
||||
2. Document MREMAP_FIXED and MREMAP_DONTUNMAP.
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit cb2dee4eccf46642eef588bee64f9c875c408f1c)
|
||||
|
||||
diff --git a/manual/llio.texi b/manual/llio.texi
|
||||
index fae49d14332db675..a65230d612eba7bf 100644
|
||||
--- a/manual/llio.texi
|
||||
+++ b/manual/llio.texi
|
||||
@@ -1781,7 +1781,7 @@ There is no existing mapping in at least part of the given region.
|
||||
|
||||
@end deftypefun
|
||||
|
||||
-@deftypefun {void *} mremap (void *@var{address}, size_t @var{length}, size_t @var{new_length}, int @var{flag})
|
||||
+@deftypefun {void *} mremap (void *@var{address}, size_t @var{length}, size_t @var{new_length}, int @var{flag}, ... /* void *@var{new_address} */)
|
||||
@standards{GNU, sys/mman.h}
|
||||
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||
|
||||
@@ -1790,12 +1790,40 @@ area. @var{address} and @var{length} must cover a region entirely mapped
|
||||
in the same @code{mmap} statement. A new mapping with the same
|
||||
characteristics will be returned with the length @var{new_length}.
|
||||
|
||||
-One option is possible, @code{MREMAP_MAYMOVE}. If it is given in
|
||||
-@var{flags}, the system may remove the existing mapping and create a new
|
||||
-one of the desired length in another location.
|
||||
+Possible flags are
|
||||
|
||||
-The address of the resulting mapping is returned, or @math{-1}. Possible
|
||||
-error codes include:
|
||||
+@table @code
|
||||
+
|
||||
+@item MREMAP_MAYMOVE
|
||||
+If it is given in @var{flags}, the system may remove the existing mapping
|
||||
+and create a new one of the desired length in another location.
|
||||
+
|
||||
+@item MREMAP_FIXED
|
||||
+If it is given in @var{flags}, @code{mremap} accepts a fifth argument,
|
||||
+@code{void *new_address}, which specifies a page-aligned address to
|
||||
+which the mapping must be moved. Any previous mapping at the address
|
||||
+range specified by @var{new_address} and @var{new_size} is unmapped.
|
||||
+
|
||||
+@code{MREMAP_FIXED} must be used together with @code{MREMAP_MAYMOVE}.
|
||||
+
|
||||
+@item MREMAP_DONTUNMAP
|
||||
+If it is given in @var{flags}, @code{mremap} accepts a fifth argument,
|
||||
+@code{void *new_address}, which specifies a page-aligned address. Any
|
||||
+previous mapping at the address range specified by @var{new_address} and
|
||||
+@var{new_size} is unmapped. If @var{new_address} is @code{NULL}, the
|
||||
+kernel chooses the page-aligned address at which to create the mapping.
|
||||
+Otherwise, the kernel takes it as a hint about where to place the mapping.
|
||||
+The mapping at the address range specified by @var{old_address} and
|
||||
+@var{old_size} isn't unmapped.
|
||||
+
|
||||
+@code{MREMAP_DONTUNMAP} must be used together with @code{MREMAP_MAYMOVE}.
|
||||
+@var{old_size} must be the same as @var{new_size}. This flag bit is
|
||||
+Linux-specific.
|
||||
+
|
||||
+@end table
|
||||
+
|
||||
+The address of the resulting mapping is returned, or @code{MAP_FAILED}.
|
||||
+Possible error codes include:
|
||||
|
||||
@table @code
|
||||
|
||||
@@ -1804,7 +1832,7 @@ There is no existing mapping in at least part of the original region, or
|
||||
the region covers two or more distinct mappings.
|
||||
|
||||
@item EINVAL
|
||||
-The address given is misaligned or inappropriate.
|
||||
+Any arguments are inappropriate, including unknown @var{flags} values.
|
||||
|
||||
@item EAGAIN
|
||||
The region has pages locked, and if extended it would exceed the
|
@ -0,0 +1,286 @@
|
||||
commit 7f5ccdd8afe107502b4567af61ffc7b86a2477f7
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Wed Jul 24 14:05:15 2024 -0700
|
||||
|
||||
Add mremap tests
|
||||
|
||||
Add tests for MREMAP_MAYMOVE and MREMAP_FIXED. On Linux, also test
|
||||
MREMAP_DONTUNMAP.
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
(cherry picked from commit ff0320bec2810192d453c579623482fab87bfa01)
|
||||
|
||||
diff --git a/misc/Makefile b/misc/Makefile
|
||||
index c273ec6974a96c3f..235fc7eacb6a980d 100644
|
||||
--- a/misc/Makefile
|
||||
+++ b/misc/Makefile
|
||||
@@ -251,6 +251,8 @@ tests := \
|
||||
tst-mntent-blank-passno \
|
||||
tst-mntent-escape \
|
||||
tst-mntent2 \
|
||||
+ tst-mremap1 \
|
||||
+ tst-mremap2 \
|
||||
tst-preadvwritev \
|
||||
tst-preadvwritev2 \
|
||||
tst-preadvwritev64 \
|
||||
diff --git a/misc/tst-mremap1.c b/misc/tst-mremap1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0469991a6c1438b6
|
||||
--- /dev/null
|
||||
+++ b/misc/tst-mremap1.c
|
||||
@@ -0,0 +1,46 @@
|
||||
+/* Test mremap with MREMAP_MAYMOVE.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <sys/mman.h>
|
||||
+#include <support/xstdlib.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/test-driver.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ size_t old_size = getpagesize ();
|
||||
+ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
+ old_addr[0] = 1;
|
||||
+ old_addr[old_size - 1] = 2;
|
||||
+
|
||||
+ /* Test MREMAP_MAYMOVE. */
|
||||
+ size_t new_size = old_size + old_size;
|
||||
+ char *new_addr = mremap (old_addr, old_size, new_size, MREMAP_MAYMOVE);
|
||||
+ TEST_VERIFY_EXIT (new_addr != MAP_FAILED);
|
||||
+ new_addr[0] = 1;
|
||||
+ new_addr[new_size - 1] = 2;
|
||||
+ xmunmap (new_addr, new_size);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/misc/tst-mremap2.c b/misc/tst-mremap2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..45be7f0369c2571e
|
||||
--- /dev/null
|
||||
+++ b/misc/tst-mremap2.c
|
||||
@@ -0,0 +1,54 @@
|
||||
+/* Test mremap with MREMAP_FIXED.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <sys/mman.h>
|
||||
+#include <support/xstdlib.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <mremap-failure.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ size_t old_size = getpagesize ();
|
||||
+ size_t new_size = old_size + old_size;
|
||||
+ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
+ old_addr[0] = 1;
|
||||
+ old_addr[old_size - 1] = 2;
|
||||
+
|
||||
+ char *fixed_addr = xmmap (NULL, new_size, PROT_READ | PROT_WRITE,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
+ fixed_addr[0] = 1;
|
||||
+ fixed_addr[new_size - 1] = 2;
|
||||
+
|
||||
+ /* Test MREMAP_FIXED. */
|
||||
+ char *new_addr = mremap (old_addr, old_size, new_size,
|
||||
+ MREMAP_FIXED | MREMAP_MAYMOVE,
|
||||
+ fixed_addr);
|
||||
+ if (new_addr == MAP_FAILED)
|
||||
+ return mremap_failure_exit (errno);
|
||||
+ new_addr[0] = 1;
|
||||
+ new_addr[new_size - 1] = 2;
|
||||
+ xmunmap (new_addr, new_size);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/generic/mremap-failure.h b/sysdeps/generic/mremap-failure.h
|
||||
new file mode 100644
|
||||
index 0000000000000000..bc0d476368050c2c
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/generic/mremap-failure.h
|
||||
@@ -0,0 +1,25 @@
|
||||
+/* mremap failure handling. Generic version.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* Return exit value on mremap failure with errno ERR. */
|
||||
+
|
||||
+static int
|
||||
+mremap_failure_exit (int err)
|
||||
+{
|
||||
+ return EXIT_FAILURE;
|
||||
+}
|
||||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||||
index 6ab9b901234dc72e..eee91c7b64d79fe7 100644
|
||||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||||
@@ -205,6 +205,7 @@ tests += \
|
||||
tst-getauxval \
|
||||
tst-gettid \
|
||||
tst-gettid-kill \
|
||||
+ tst-linux-mremap1 \
|
||||
tst-memfd_create \
|
||||
tst-misalign-clone \
|
||||
tst-mlock2 \
|
||||
diff --git a/sysdeps/unix/sysv/linux/mremap-failure.h b/sysdeps/unix/sysv/linux/mremap-failure.h
|
||||
new file mode 100644
|
||||
index 0000000000000000..c99ab30ca9ea796f
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/mremap-failure.h
|
||||
@@ -0,0 +1,30 @@
|
||||
+/* mremap failure handling. Linux version.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+/* Return exit value on mremap failure with errno ERR. */
|
||||
+
|
||||
+static int
|
||||
+mremap_failure_exit (int err)
|
||||
+{
|
||||
+ if (err != EINVAL)
|
||||
+ return EXIT_FAILURE;
|
||||
+
|
||||
+ return EXIT_UNSUPPORTED;
|
||||
+}
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-linux-mremap1.c b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..408e8af2abe59033
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c
|
||||
@@ -0,0 +1,63 @@
|
||||
+/* Test mremap with MREMAP_DONTUNMAP.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <sys/mman.h>
|
||||
+#include <support/xstdlib.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <mremap-failure.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ size_t old_size = getpagesize ();
|
||||
+ size_t new_size = old_size;
|
||||
+ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
+ old_addr[0] = 1;
|
||||
+ old_addr[old_size - 1] = 2;
|
||||
+
|
||||
+ /* Create an available 64-page mmap region. */
|
||||
+ size_t fixed_size = old_size * 64;
|
||||
+ char *fixed_addr = xmmap (NULL, fixed_size, PROT_READ | PROT_WRITE,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
+ xmunmap (fixed_addr, fixed_size);
|
||||
+
|
||||
+ /* Add 3 * pagesize. */
|
||||
+ fixed_size += 3 * old_size;
|
||||
+
|
||||
+ /* Test MREMAP_DONTUNMAP. It should return FIXED_ADDR created above. */
|
||||
+ char *new_addr = mremap (old_addr, old_size, new_size,
|
||||
+ MREMAP_DONTUNMAP | MREMAP_MAYMOVE,
|
||||
+ fixed_addr);
|
||||
+ if (new_addr == MAP_FAILED)
|
||||
+ return mremap_failure_exit (errno);
|
||||
+ TEST_VERIFY_EXIT (fixed_addr == new_addr);
|
||||
+ old_addr[0] = 3;
|
||||
+ old_addr[old_size - 1] = 4;
|
||||
+ new_addr[0] = 1;
|
||||
+ new_addr[new_size - 1] = 2;
|
||||
+ xmunmap (new_addr, new_size);
|
||||
+ xmunmap (old_addr, old_size);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue