core/glibc-32/glibc-2.34-upstream-fixes.patch

4388 lines
144 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff --git a/NEWS b/NEWS
index 3c610744c9..698964bb9e 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,25 @@ See the end for copying conditions.
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
+
+Version 2.34.1
+
+The following bugs are resolved with this release:
+
+ [12889] nptl: Fix race between pthread_kill and thread exit
+ [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
+ [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
+ [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
+ [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF)
+ [28340] ld.so crashes while loading a DSO with a read-only dynamic section
+ [28357] deadlock between pthread_create and ELF constructors
+ [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
+ [28407] pthread_kill assumes that kill and tgkill are equivalent
+ [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
+ [28607] Masked signals are delivered on thread exit
+ [28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect
+ [28678] nptl/tst-create1 hangs sporadically
+
Version 2.34
diff --git a/bits/stdlib-bsearch.h b/bits/stdlib-bsearch.h
index 4132dc6af0..e2fcea6e17 100644
--- a/bits/stdlib-bsearch.h
+++ b/bits/stdlib-bsearch.h
@@ -29,14 +29,23 @@ bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
while (__l < __u)
{
__idx = (__l + __u) / 2;
- __p = (void *) (((const char *) __base) + (__idx * __size));
+ __p = (const void *) (((const char *) __base) + (__idx * __size));
__comparison = (*__compar) (__key, __p);
if (__comparison < 0)
__u = __idx;
else if (__comparison > 0)
__l = __idx + 1;
else
- return (void *) __p;
+ {
+#if __GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+ return (void *) __p;
+#if __GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic pop
+#endif
+ }
}
return NULL;
diff --git a/elf/Makefile b/elf/Makefile
index d05f410592..118d579c42 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -224,7 +224,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls-ie tst-tls-ie-dlmopen argv0test \
tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \
- tst-dl-is_dso
+ tst-dl-is_dso tst-ro-dynamic
# reldep9
tests-internal += loadtest unload unload2 circleload1 \
neededtest neededtest2 neededtest3 neededtest4 \
@@ -357,7 +357,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \
tst-auxvalmod \
- tst-dlmopen-gethostbyname-mod \
+ tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \
# Most modules build with _ISOMAC defined, but those filtered out
# depend on internal headers.
@@ -399,8 +399,9 @@ endif
modules-execstack-yes = tst-execstack-mod
extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
-# filtmod1.so, tst-big-note-lib.so have special rules.
-modules-names-nobuild := filtmod1 tst-big-note-lib
+# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special
+# rules.
+modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod
tests += $(tests-static)
@@ -1906,3 +1907,10 @@ $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so
tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)
$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
+
+$(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so
+$(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \
+ tst-ro-dynamic-mod.map
+ $(LINK.o) -nostdlib -nostartfiles -shared -o $@ \
+ -Wl,--script=tst-ro-dynamic-mod.map \
+ $(objpfx)tst-ro-dynamic-mod.os
diff --git a/elf/dl-close.c b/elf/dl-close.c
index f39001cab9..cd7b9c9fe8 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force)
size_t tls_free_end;
tls_free_start = tls_free_end = NO_TLS_OFFSET;
+ /* Protects global and module specitic TLS state. */
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
/* We modify the list of loaded objects. */
__rtld_lock_lock_recursive (GL(dl_load_write_lock));
@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force)
GL(dl_tls_static_used) = tls_free_start;
}
+ /* TLS is cleaned up for the unloaded modules. */
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
#ifdef SHARED
/* Auditing checkpoint: we have deleted all objects. */
if (__glibc_unlikely (do_audit))
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 650e4edc35..0976977fbd 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1130,6 +1130,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
struct loadcmd loadcmds[l->l_phnum];
size_t nloadcmds = 0;
bool has_holes = false;
+ bool empty_dynamic = false;
/* The struct is initialized to zero so this is not necessary:
l->l_ld = 0;
@@ -1142,13 +1143,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
segments are mapped in. We record the addresses it says
verbatim, and later correct for the run-time load address. */
case PT_DYNAMIC:
- if (ph->p_filesz)
+ if (ph->p_filesz == 0)
+ empty_dynamic = true; /* Usually separate debuginfo. */
+ else
{
/* Debuginfo only files from "objcopy --only-keep-debug"
contain a PT_DYNAMIC segment with p_filesz == 0. Skip
such a segment to avoid a crash later. */
l->l_ld = (void *) ph->p_vaddr;
l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
}
break;
@@ -1264,6 +1268,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
goto lose;
}
+ /* This check recognizes most separate debuginfo files. */
+ if (__glibc_unlikely ((l->l_ld == 0 && type == ET_DYN) || empty_dynamic))
+ {
+ errstring = N_("object file has no dynamic section");
+ goto lose;
+ }
+
/* Length of the sections to be loaded. */
maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
@@ -1281,18 +1292,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
}
}
- if (l->l_ld == 0)
- {
- if (__glibc_unlikely (type == ET_DYN))
- {
- errstring = N_("object file has no dynamic section");
- goto lose;
- }
- }
- else
+ if (l->l_ld != 0)
l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
- elf_get_dynamic_info (l, NULL);
+ elf_get_dynamic_info (l);
/* Make sure we are not dlopen'ing an object that has the
DF_1_NOOPEN flag set, or a PIE object. */
diff --git a/elf/dl-open.c b/elf/dl-open.c
index ec386626f9..bc68e2c376 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -66,6 +66,9 @@ struct dl_open_args
libc_map value in the namespace in case of a dlopen failure. */
bool libc_already_loaded;
+ /* Set to true if the end of dl_open_worker_begin was reached. */
+ bool worker_continue;
+
/* Original parameters to the program and the current environment. */
int argc;
char **argv;
@@ -482,7 +485,7 @@ call_dl_init (void *closure)
}
static void
-dl_open_worker (void *a)
+dl_open_worker_begin (void *a)
{
struct dl_open_args *args = a;
const char *file = args->file;
@@ -774,6 +777,36 @@ dl_open_worker (void *a)
_dl_call_libc_early_init (libc_map, false);
}
+ args->worker_continue = true;
+}
+
+static void
+dl_open_worker (void *a)
+{
+ struct dl_open_args *args = a;
+
+ args->worker_continue = false;
+
+ {
+ /* Protects global and module specific TLS state. */
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
+ struct dl_exception ex;
+ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args);
+
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
+ if (__glibc_unlikely (ex.errstring != NULL))
+ /* Reraise the error. */
+ _dl_signal_exception (err, &ex, NULL);
+ }
+
+ if (!args->worker_continue)
+ return;
+
+ int mode = args->mode;
+ struct link_map *new = args->map;
+
/* Run the initializer functions of new objects. Temporarily
disable the exception handler, so that lazy binding failures are
fatal. */
@@ -886,7 +919,7 @@ no more namespaces available for dlmopen()"));
/* Avoid keeping around a dangling reference to the libc.so link
map in case it has been cached in libc_map. */
if (!args.libc_already_loaded)
- GL(dl_ns)[nsid].libc_map = NULL;
+ GL(dl_ns)[args.nsid].libc_map = NULL;
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index d5bd2f31e9..2fb02d7276 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -40,7 +40,17 @@ _dl_relocate_static_pie (void)
/* Read our own dynamic section and fill in the info array. */
main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
- elf_get_dynamic_info (main_map, NULL);
+
+ const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
+ size_t phnum = GL(dl_phnum);
+ for (ph = phdr; ph < &phdr[phnum]; ++ph)
+ if (ph->p_type == PT_DYNAMIC)
+ {
+ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+ break;
+ }
+
+ elf_get_dynamic_info (main_map);
# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info);
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 0155718175..d8c06ba7eb 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -229,6 +229,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock)
list of loaded objects while an object is added to or removed from
that list. */
__rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
+ /* This lock protects global and module specific TLS related data.
+ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+ accessed and when TLS related relocations are processed for a
+ module. It was introduced to keep pthread_create accessing TLS
+ state that is being set up. */
+__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
#ifdef HAVE_AUX_VECTOR
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index d47bef1340..2c684c2db2 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -317,7 +317,7 @@ _dl_show_auxv (void)
[AT_SYSINFO_EHDR - 2] = { "SYSINFO_EHDR: 0x", hex },
[AT_RANDOM - 2] = { "RANDOM: 0x", hex },
[AT_HWCAP2 - 2] = { "HWCAP2: 0x", hex },
- [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ ", dec },
+ [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ: ", dec },
[AT_L1I_CACHESIZE - 2] = { "L1I_CACHESIZE: ", dec },
[AT_L1I_CACHEGEOMETRY - 2] = { "L1I_CACHEGEOMETRY: 0x", hex },
[AT_L1D_CACHESIZE - 2] = { "L1D_CACHESIZE: ", dec },
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 423e380f7c..40263cf586 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result)
size_t maxgen = 0;
/* Protects global dynamic TLS related state. */
- __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
/* Check if the current dtv is big enough. */
if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
@@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result)
listp = listp->next;
assert (listp != NULL);
}
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
/* The DTV version is up-to-date now. */
dtv[0].counter = maxgen;
@@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
Here the dtv needs to be updated to new_gen generation count.
- This code may be called during TLS access when GL(dl_load_lock)
+ This code may be called during TLS access when GL(dl_load_tls_lock)
is not held. In that case the user code has to synchronize with
dlopen and dlclose calls of relevant modules. A module m is
relevant if the generation of m <= new_gen and dlclose of m is
@@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
if (__glibc_unlikely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET))
{
- __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
{
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
}
else if (__glibc_likely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET))
@@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
dtv[GET_ADDR_MODULE].pointer.val = p;
@@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
return (char *) p + GET_ADDR_OFFSET;
}
else
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
}
struct dtv_pointer result = allocate_and_init (the_map);
dtv[GET_ADDR_MODULE].pointer = result;
@@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l)
return NULL;
dtv_t *dtv = THREAD_DTV ();
- /* This may be called without holding the GL(dl_load_lock). Reading
+ /* This may be called without holding the GL(dl_load_tls_lock). Reading
arbitrary gen value is fine since this is best effort code. */
size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
if (__glibc_unlikely (dtv[0].counter != gen))
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index d8ec32377d..4aa2058abf 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -28,7 +28,7 @@ static
auto
#endif
inline void __attribute__ ((unused, always_inline))
-elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+elf_get_dynamic_info (struct link_map *l)
{
#if __ELF_NATIVE_CLASS == 32
typedef Elf32_Word d_tag_utype;
@@ -69,28 +69,15 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
info[i] = dyn;
}
-#define DL_RO_DYN_TEMP_CNT 8
-
-#ifndef DL_RO_DYN_SECTION
/* Don't adjust .dynamic unnecessarily. */
- if (l->l_addr != 0)
+ if (l->l_addr != 0 && dl_relocate_ld (l))
{
ElfW(Addr) l_addr = l->l_addr;
- int cnt = 0;
# define ADJUST_DYN_INFO(tag) \
do \
if (info[tag] != NULL) \
- { \
- if (temp) \
- { \
- temp[cnt].d_tag = info[tag]->d_tag; \
- temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \
- info[tag] = temp + cnt++; \
- } \
- else \
- info[tag]->d_un.d_ptr += l_addr; \
- } \
+ info[tag]->d_un.d_ptr += l_addr; \
while (0)
ADJUST_DYN_INFO (DT_HASH);
@@ -107,9 +94,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH));
# undef ADJUST_DYN_INFO
- assert (cnt <= DL_RO_DYN_TEMP_CNT);
}
-#endif
if (info[DT_PLTREL] != NULL)
{
#if ELF_MACHINE_NO_RELA
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 1037e8d0cf..b8893637f8 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -503,7 +503,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
entry->path[--i] = '\0';
if (i == 0)
- return;
+ {
+ free (entry->path);
+ free (entry);
+ return;
+ }
char *path = entry->path;
if (opt_chroot != NULL)
diff --git a/elf/rtld.c b/elf/rtld.c
index d733359eaf..d83ac1bdc4 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -322,6 +322,7 @@ struct rtld_global _rtld_global =
#ifdef _LIBC_REENTRANT
._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
#endif
._dl_nns = 1,
._dl_ns =
@@ -463,6 +464,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
#ifndef DONT_USE_BOOTSTRAP_MAP
GL(dl_rtld_map).l_addr = info->l.l_addr;
GL(dl_rtld_map).l_ld = info->l.l_ld;
+ GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly;
memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
sizeof GL(dl_rtld_map).l_info);
GL(dl_rtld_map).l_mach = info->l.l_mach;
@@ -546,7 +548,8 @@ _dl_start (void *arg)
/* Read our own dynamic section and fill in the info array. */
bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
- elf_get_dynamic_info (&bootstrap_map, NULL);
+ bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
+ elf_get_dynamic_info (&bootstrap_map);
#if NO_TLS_OFFSET != 0
bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
@@ -1468,6 +1471,7 @@ dl_main (const ElfW(Phdr) *phdr,
/* This tells us where to find the dynamic section,
which tells us everything we need to do. */
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
+ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
break;
case PT_INTERP:
/* This "interpreter segment" was used by the program loader to
@@ -1613,7 +1617,7 @@ dl_main (const ElfW(Phdr) *phdr,
if (! rtld_is_main)
{
/* Extract the contents of the dynamic section for easy access. */
- elf_get_dynamic_info (main_map, NULL);
+ elf_get_dynamic_info (main_map);
/* If the main map is libc.so, update the base namespace to
refer to this map. If libc.so is loaded later, this happens
diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
index 86c491e49c..f44748bc98 100644
--- a/elf/setup-vdso.h
+++ b/elf/setup-vdso.h
@@ -33,8 +33,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
0, LM_ID_BASE);
if (__glibc_likely (l != NULL))
{
- static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
-
l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
+ GLRO(dl_sysinfo_dso)->e_phoff);
l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
@@ -45,6 +43,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
{
l->l_ld = (void *) ph->p_vaddr;
l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
}
else if (ph->p_type == PT_LOAD)
{
@@ -65,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
l->l_map_end += l->l_addr;
l->l_text_end += l->l_addr;
l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
- elf_get_dynamic_info (l, dyn_temp);
+ elf_get_dynamic_info (l);
_dl_setup_hash (l);
l->l_relocated = 1;
diff --git a/elf/tst-ro-dynamic-mod.c b/elf/tst-ro-dynamic-mod.c
new file mode 100644
index 0000000000..6d99925964
--- /dev/null
+++ b/elf/tst-ro-dynamic-mod.c
@@ -0,0 +1,19 @@
+/* Test case for DSO with readonly dynamic section.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+int foo = -1;
diff --git a/elf/tst-ro-dynamic-mod.map b/elf/tst-ro-dynamic-mod.map
new file mode 100644
index 0000000000..2fe4a2998c
--- /dev/null
+++ b/elf/tst-ro-dynamic-mod.map
@@ -0,0 +1,16 @@
+SECTIONS
+{
+ . = SIZEOF_HEADERS;
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .rodata : { *(.data*) *(.bss*) } :text
+ /DISCARD/ : {
+ *(.note.gnu.property)
+ }
+ .note : { *(.note.*) } :text :note
+}
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS;
+ dynamic PT_DYNAMIC FLAGS(4);
+ note PT_NOTE FLAGS(4);
+}
diff --git a/elf/tst-ro-dynamic.c b/elf/tst-ro-dynamic.c
new file mode 100644
index 0000000000..3a18f8789a
--- /dev/null
+++ b/elf/tst-ro-dynamic.c
@@ -0,0 +1,31 @@
+/* Test case for DSO with readonly dynamic section.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+extern int foo;
+
+static int
+do_test (void)
+{
+ TEST_COMPARE (foo, -1);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index 62bee28769..cc391d8f93 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -478,7 +478,7 @@ __gconv_read_conf (void)
__gconv_get_path ();
for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
- gconv_parseconfdir (__gconv_path_elem[cnt].name,
+ gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name,
__gconv_path_elem[cnt].len);
#endif
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index a4153e54c6..a586268abc 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -39,7 +39,6 @@
/* Name of the file containing the module information in the directories
along the path. */
static const char gconv_conf_filename[] = "gconv-modules";
-static const char gconv_conf_dirname[] = "gconv-modules.d";
static void add_alias (char *);
static void add_module (char *, const char *, size_t, int);
@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len)
return true;
}
+/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and
+ parse configuration in it. */
+
static __always_inline bool
-gconv_parseconfdir (const char *dir, size_t dir_len)
+gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
{
- /* No slash needs to be inserted between dir and gconv_conf_filename;
- dir already ends in a slash. */
- char *buf = malloc (dir_len + sizeof (gconv_conf_dirname));
+ /* No slash needs to be inserted between dir and gconv_conf_filename; dir
+ already ends in a slash. The additional 2 is to accommodate the ".d"
+ when looking for configuration files in gconv-modules.d. */
+ size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2;
+ char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0));
+ char *cp = buf;
bool found = false;
if (buf == NULL)
return false;
- char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename,
- sizeof (gconv_conf_filename));
+ if (prefix != NULL)
+ cp = stpcpy (cp, prefix);
+
+ cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename,
+ sizeof (gconv_conf_filename));
/* Read the gconv-modules configuration file first. */
found = read_conf_file (buf, dir, dir_len);
@@ -153,12 +161,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len)
struct stat64 st;
if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
continue;
- if (ent->d_type == DT_UNKNOWN
- && (lstat64 (conf, &st) == -1
- || !S_ISREG (st.st_mode)))
- continue;
- found |= read_conf_file (conf, dir, dir_len);
+ if (ent->d_type != DT_UNKNOWN
+ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
+ found |= read_conf_file (conf, dir, dir_len);
+
free (conf);
}
}
diff --git a/iconv/iconv_charmap.c b/iconv/iconv_charmap.c
index e2d53fee3c..a8b6b56124 100644
--- a/iconv/iconv_charmap.c
+++ b/iconv/iconv_charmap.c
@@ -234,6 +234,8 @@ charmap_conversion (const char *from_code, struct charmap_t *from_charmap,
while (++remaining < argc);
/* All done. */
+ if (output != stdout)
+ fclose (output);
free_table (cvtbl);
return status;
}
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index 783b2bbdbb..273a71f673 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory,
static int
handle_dir (const char *dir)
{
+ char *newp = NULL;
size_t dirlen = strlen (dir);
bool found = false;
- char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
- dir, dir[dirlen - 1] != '/' ? "/" : "");
+ /* End directory path with a '/' if it doesn't already. */
+ if (dir[dirlen - 1] != '/')
+ {
+ newp = xmalloc (dirlen + 2);
+ memcpy (newp, dir, dirlen);
+ newp[dirlen++] = '/';
+ newp[dirlen] = '\0';
+ dir = newp;
+ }
- found = gconv_parseconfdir (fulldir, strlen (fulldir));
+ found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen);
if (!found)
{
@@ -671,7 +679,7 @@ handle_dir (const char *dir)
"configuration files with names ending in .conf.");
}
- free (fulldir);
+ free (newp);
return found ? 0 : 1;
}
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index c216f959df..d5507a048c 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -1,4 +1,5 @@
# Copyright (C) 1997-2021 Free Software Foundation, Inc.
+# Copyright (C) The GNU Toolchain Authors.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -74,7 +75,7 @@ ifeq (yes,$(build-shared))
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
- bug-iconv13 bug-iconv14
+ bug-iconv13 bug-iconv14 bug-iconv15
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
@@ -327,6 +328,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
+$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh \
$(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c
new file mode 100644
index 0000000000..cc04bd0313
--- /dev/null
+++ b/iconvdata/bug-iconv15.c
@@ -0,0 +1,60 @@
+/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv
+ may emit spurious NUL character on state reset.
+ Copyright (C) The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stddef.h>
+#include <iconv.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ char in[] = "\x1b(I";
+ char *inbuf = in;
+ size_t inleft = sizeof (in) - 1;
+ char out[1];
+ char *outbuf = out;
+ size_t outleft = sizeof (out);
+ iconv_t cd;
+
+ cd = iconv_open ("UTF8", "ISO-2022-JP-3");
+ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+ /* First call to iconv should alter internal state.
+ Now, JISX0201_Kana_set is selected and
+ state value != ASCII_set. */
+ TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1);
+
+ /* No bytes should have been added to
+ the output buffer at this point. */
+ TEST_VERIFY (outbuf == out);
+ TEST_VERIFY (outleft == sizeof (out));
+
+ /* Second call shall emit spurious NUL character in unpatched glibc. */
+ TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1);
+
+ /* No characters are expected to be produced. */
+ TEST_VERIFY (outbuf == out);
+ TEST_VERIFY (outleft == sizeof (out));
+
+ TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
index c8ba88cdc9..5fc0c0f739 100644
--- a/iconvdata/iso-2022-jp-3.c
+++ b/iconvdata/iso-2022-jp-3.c
@@ -1,5 +1,6 @@
/* Conversion module for ISO-2022-JP-3.
Copyright (C) 1998-2021 Free Software Foundation, Inc.
+ Copyright (C) The GNU Toolchain Authors.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
and Bruno Haible <bruno@clisp.org>, 2002.
@@ -81,20 +82,31 @@ enum
the output state to the initial state. This has to be done during the
flushing. */
#define EMIT_SHIFT_TO_INIT \
- if (data->__statep->__count != ASCII_set) \
+ if ((data->__statep->__count & ~7) != ASCII_set) \
{ \
if (FROM_DIRECTION) \
{ \
- if (__glibc_likely (outbuf + 4 <= outend)) \
+ uint32_t ch = data->__statep->__count >> 6; \
+ \
+ if (__glibc_unlikely (ch != 0)) \
{ \
- /* Write out the last character. */ \
- *((uint32_t *) outbuf) = data->__statep->__count >> 6; \
- outbuf += sizeof (uint32_t); \
- data->__statep->__count = ASCII_set; \
+ if (__glibc_likely (outbuf + 4 <= outend)) \
+ { \
+ /* Write out the last character. */ \
+ put32u (outbuf, ch); \
+ outbuf += 4; \
+ data->__statep->__count &= 7; \
+ data->__statep->__count |= ASCII_set; \
+ } \
+ else \
+ /* We don't have enough room in the output buffer. */ \
+ status = __GCONV_FULL_OUTPUT; \
} \
else \
- /* We don't have enough room in the output buffer. */ \
- status = __GCONV_FULL_OUTPUT; \
+ { \
+ data->__statep->__count &= 7; \
+ data->__statep->__count |= ASCII_set; \
+ } \
} \
else \
{ \
diff --git a/include/link.h b/include/link.h
index 4af16cb596..c46aced9f7 100644
--- a/include/link.h
+++ b/include/link.h
@@ -205,6 +205,7 @@ struct link_map
unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be
freed, ie. not allocated with
the dummy malloc in ld.so. */
+ unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly. */
/* NODELETE status of the map. Only valid for maps of type
lt_loaded. Lazy binding sets l_nodelete_active directly,
@@ -342,6 +343,8 @@ struct link_map
unsigned long long int l_serial;
};
+#include <dl-relocate-ld.h>
+
/* Information used by audit modules. For most link maps, this data
immediate follows the link map in memory. For the dynamic linker,
it is allocated separately. See link_map_audit_state in
diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h
index 7388356a19..c490561581 100644
--- a/include/sys/sysinfo.h
+++ b/include/sys/sysinfo.h
@@ -9,10 +9,15 @@
extern int __get_nprocs_conf (void);
libc_hidden_proto (__get_nprocs_conf)
-/* Return number of available processors. */
+/* Return number of available processors (not all of them will be
+ available to the caller process). */
extern int __get_nprocs (void);
libc_hidden_proto (__get_nprocs)
+/* Return the number of available processors which the process can
+ be scheduled. */
+extern int __get_nprocs_sched (void) attribute_hidden;
+
/* Return number of physical pages of memory in the system. */
extern long int __get_phys_pages (void);
libc_hidden_proto (__get_phys_pages)
diff --git a/io/fcntl.h b/io/fcntl.h
index 8917a73b42..1c96f98f4d 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -187,10 +187,10 @@ extern int fcntl64 (int __fd, int __cmd, ...);
# endif
#else /* __USE_TIME_BITS64 */
# ifdef __REDIRECT
-extern int __REDIRECT (fcntl, (int __fd, int __request, ...),
- __fcntl_time64) __THROW;
-extern int __REDIRECT (fcntl64, (int __fd, int __request, ...),
- __fcntl_time64) __THROW;
+extern int __REDIRECT_NTH (fcntl, (int __fd, int __request, ...),
+ __fcntl_time64);
+extern int __REDIRECT_NTH (fcntl64, (int __fd, int __request, ...),
+ __fcntl_time64);
# else
extern int __fcntl_time64 (int __fd, int __request, ...) __THROW;
# define fcntl64 __fcntl_time64
diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
index d4c187073c..395ec0d894 100644
--- a/io/tst-closefrom.c
+++ b/io/tst-closefrom.c
@@ -24,31 +24,22 @@
#include <support/check.h>
#include <support/descriptors.h>
#include <support/xunistd.h>
+#include <support/support.h>
#include <array_length.h>
#define NFDS 100
-static int
-open_multiple_temp_files (void)
-{
- /* Check if the temporary file descriptor has no no gaps. */
- int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
- for (int i = 1; i <= NFDS; i++)
- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i);
- return lowfd;
-}
-
static int
closefrom_test (void)
{
struct support_descriptors *descrs = support_descriptors_list ();
- int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
- const int maximum_fd = lowfd + NFDS;
+ const int maximum_fd = lowfd + NFDS - 1;
const int half_fd = lowfd + NFDS / 2;
- const int gap = maximum_fd / 4;
+ const int gap = lowfd + NFDS / 4;
/* Close half of the descriptors and check result. */
closefrom (half_fd);
@@ -58,7 +49,7 @@ closefrom_test (void)
TEST_COMPARE (fcntl (i, F_GETFL), -1);
TEST_COMPARE (errno, EBADF);
}
- for (int i = 0; i < half_fd; i++)
+ for (int i = lowfd; i < half_fd; i++)
TEST_VERIFY (fcntl (i, F_GETFL) > -1);
/* Create some gaps, close up to a threshold, and check result. */
@@ -74,7 +65,7 @@ closefrom_test (void)
TEST_COMPARE (fcntl (i, F_GETFL), -1);
TEST_COMPARE (errno, EBADF);
}
- for (int i = 0; i < gap; i++)
+ for (int i = lowfd; i < gap; i++)
TEST_VERIFY (fcntl (i, F_GETFL) > -1);
/* Close the remmaining but the last one. */
diff --git a/malloc/arena.c b/malloc/arena.c
index 667484630e..f1f0af8648 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena)
narenas_limit = mp_.arena_max;
else if (narenas > mp_.arena_test)
{
- int n = __get_nprocs ();
+ int n = __get_nprocs_sched ();
if (n >= 1)
narenas_limit = NARENAS_FROM_NCORES (n);
diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c
index 9922ef5f25..3d7e6d44fd 100644
--- a/malloc/malloc-debug.c
+++ b/malloc/malloc-debug.c
@@ -1,5 +1,6 @@
/* Malloc debug DSO.
Copyright (C) 2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -399,17 +400,17 @@ strong_alias (__debug_calloc, calloc)
size_t
malloc_usable_size (void *mem)
{
+ if (mem == NULL)
+ return 0;
+
if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
return mcheck_usable_size (mem);
if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
return malloc_check_get_size (mem);
- if (mem != NULL)
- {
- mchunkptr p = mem2chunk (mem);
- if (DUMPED_MAIN_ARENA_CHUNK (p))
- return chunksize (p) - SIZE_SZ;
- }
+ mchunkptr p = mem2chunk (mem);
+ if (DUMPED_MAIN_ARENA_CHUNK (p))
+ return chunksize (p) - SIZE_SZ;
return musable (mem);
}
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e065785af7..7882c70f0a 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1,5 +1,6 @@
/* Malloc implementation for multiple threads without lock contention.
Copyright (C) 1996-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
Contributed by Wolfram Gloger <wg@malloc.de>
and Doug Lea <dl@cs.oswego.edu>, 2001.
@@ -5009,20 +5010,13 @@ __malloc_trim (size_t s)
static size_t
musable (void *mem)
{
- mchunkptr p;
- if (mem != 0)
- {
- size_t result = 0;
-
- p = mem2chunk (mem);
+ mchunkptr p = mem2chunk (mem);
- if (chunk_is_mmapped (p))
- result = chunksize (p) - CHUNK_HDR_SZ;
- else if (inuse (p))
- result = memsize (p);
+ if (chunk_is_mmapped (p))
+ return chunksize (p) - CHUNK_HDR_SZ;
+ else if (inuse (p))
+ return memsize (p);
- return result;
- }
return 0;
}
@@ -5030,10 +5024,9 @@ musable (void *mem)
size_t
__malloc_usable_size (void *m)
{
- size_t result;
-
- result = musable (m);
- return result;
+ if (m == NULL)
+ return 0;
+ return musable (m);
}
#endif
diff --git a/malloc/tst-malloc-usable.c b/malloc/tst-malloc-usable.c
index a1074b782a..b0d702be10 100644
--- a/malloc/tst-malloc-usable.c
+++ b/malloc/tst-malloc-usable.c
@@ -2,6 +2,7 @@
MALLOC_CHECK_ exported to a positive value.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -21,29 +22,24 @@
#include <malloc.h>
#include <string.h>
#include <stdio.h>
+#include <support/support.h>
+#include <support/check.h>
static int
do_test (void)
{
size_t usable_size;
void *p = malloc (7);
- if (!p)
- {
- printf ("memory allocation failed\n");
- return 1;
- }
+ TEST_VERIFY_EXIT (p != NULL);
usable_size = malloc_usable_size (p);
- if (usable_size != 7)
- {
- printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size);
- return 1;
- }
-
+ TEST_COMPARE (usable_size, 7);
memset (p, 0, usable_size);
free (p);
+
+ TEST_COMPARE (malloc_usable_size (NULL), 0);
+
return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include "support/test-driver.c"
diff --git a/misc/getsysstats.c b/misc/getsysstats.c
index 0eedface6d..57d93601e2 100644
--- a/misc/getsysstats.c
+++ b/misc/getsysstats.c
@@ -45,6 +45,12 @@ weak_alias (__get_nprocs, get_nprocs)
link_warning (get_nprocs, "warning: get_nprocs will always return 1")
+int
+__get_nprocs_sched (void)
+{
+ return 1;
+}
+
long int
__get_phys_pages (void)
{
diff --git a/misc/sys/ioctl.h b/misc/sys/ioctl.h
index 6884d9925f..9945c1e918 100644
--- a/misc/sys/ioctl.h
+++ b/misc/sys/ioctl.h
@@ -42,8 +42,8 @@ __BEGIN_DECLS
extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
#else
# ifdef __REDIRECT
-extern int __REDIRECT (ioctl, (int __fd, unsigned long int __request, ...),
- __ioctl_time64) __THROW;
+extern int __REDIRECT_NTH (ioctl, (int __fd, unsigned long int __request, ...),
+ __ioctl_time64);
# else
extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW;
# define ioctl __ioctl_time64
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index cfe37a3443..50065bc9bd 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -32,6 +32,7 @@
#include <futex-internal.h>
#include <kernel-features.h>
#include <nptl-stack.h>
+#include <libc-lock.h>
/* Default alignment of stack. */
#ifndef STACK_ALIGN
@@ -127,6 +128,8 @@ get_cached_stack (size_t *sizep, void **memp)
/* No pending event. */
result->nextevent = NULL;
+ result->exiting = false;
+ __libc_lock_init (result->exit_lock);
result->tls_state = (struct tls_internal_t) { 0 };
/* Clear the DTV. */
diff --git a/nptl/descr.h b/nptl/descr.h
index c85778d449..4de84138fb 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -396,6 +396,12 @@ struct pthread
PTHREAD_CANCEL_ASYNCHRONOUS). */
unsigned char canceltype;
+ /* Used in __pthread_kill_internal to detected a thread that has
+ exited or is about to exit. exit_lock must only be acquired
+ after blocking signals. */
+ bool exiting;
+ int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */
+
/* Used on strsignal. */
struct tls_internal_t tls_state;
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
index cc25ff21f3..9bac6e3b76 100644
--- a/nptl/pthread_cancel.c
+++ b/nptl/pthread_cancel.c
@@ -62,10 +62,11 @@ __pthread_cancel (pthread_t th)
{
volatile struct pthread *pd = (volatile struct pthread *) th;
- /* Make sure the descriptor is valid. */
- if (INVALID_TD_P (pd))
- /* Not a valid thread handle. */
- return ESRCH;
+ if (pd->tid == 0)
+ /* The thread has already exited on the kernel side. Its outcome
+ (regular exit, other cancelation) has already been
+ determined. */
+ return 0;
static int init_sigcancel = 0;
if (atomic_load_relaxed (&init_sigcancel) == 0)
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index d8ec299cb1..3db0c9fdf4 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -37,6 +37,7 @@
#include <sys/single_threaded.h>
#include <version.h>
#include <clone_internal.h>
+#include <futex-internal.h>
#include <shlib-compat.h>
@@ -406,8 +407,6 @@ start_thread (void *arg)
unwind_buf.priv.data.prev = NULL;
unwind_buf.priv.data.cleanup = NULL;
- __libc_signal_restore_set (&pd->sigmask);
-
/* Allow setxid from now onwards. */
if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2))
futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE);
@@ -417,6 +416,8 @@ start_thread (void *arg)
/* Store the new cleanup handler info. */
THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
+ __libc_signal_restore_set (&pd->sigmask);
+
LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg);
/* Run the code the user provided. */
@@ -485,6 +486,27 @@ start_thread (void *arg)
/* This was the last thread. */
exit (0);
+ /* This prevents sending a signal from this thread to itself during
+ its final stages. This must come after the exit call above
+ because atexit handlers must not run with signals blocked.
+
+ Do not block SIGSETXID. The setxid handshake below expects the
+ signal to be delivered. (SIGSETXID cannot run application code,
+ nor does it use pthread_kill.) Reuse the pd->sigmask space for
+ computing the signal mask, to save stack space. */
+ __sigfillset (&pd->sigmask);
+ __sigdelset (&pd->sigmask, SIGSETXID);
+ INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL,
+ __NSIG_BYTES);
+
+ /* Tell __pthread_kill_internal that this thread is about to exit.
+ If there is a __pthread_kill_internal in progress, this delays
+ the thread exit until the signal has been queued by the kernel
+ (so that the TID used to send it remains valid). */
+ __libc_lock_lock (pd->exit_lock);
+ pd->exiting = true;
+ __libc_lock_unlock (pd->exit_lock);
+
#ifndef __ASSUME_SET_ROBUST_LIST
/* If this thread has any robust mutexes locked, handle them now. */
# if __PTHREAD_MUTEX_HAVE_PREV
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
index f79a2b26fc..35bf1f973e 100644
--- a/nptl/pthread_kill.c
+++ b/nptl/pthread_kill.c
@@ -16,39 +16,66 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <libc-lock.h>
#include <unistd.h>
#include <pthreadP.h>
#include <shlib-compat.h>
-int
-__pthread_kill_internal (pthread_t threadid, int signo)
+/* Sends SIGNO to THREADID. If the thread is about to exit or has
+ already exited on the kernel side, return NO_TID. Otherwise return
+ 0 or an error code. */
+static int
+__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
{
- pid_t tid;
struct pthread *pd = (struct pthread *) threadid;
-
if (pd == THREAD_SELF)
- /* It is a special case to handle raise() implementation after a vfork
- call (which does not update the PD tid field). */
- tid = INLINE_SYSCALL_CALL (gettid);
- else
- /* Force load of pd->tid into local variable or register. Otherwise
- if a thread exits between ESRCH test and tgkill, we might return
- EINVAL, because pd->tid would be cleared by the kernel. */
- tid = atomic_forced_read (pd->tid);
-
- int val;
- if (__glibc_likely (tid > 0))
{
- pid_t pid = __getpid ();
-
- val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo);
- val = (INTERNAL_SYSCALL_ERROR_P (val)
- ? INTERNAL_SYSCALL_ERRNO (val) : 0);
+ /* Use the actual TID from the kernel, so that it refers to the
+ current thread even if called after vfork. There is no
+ signal blocking in this case, so that the signal is delivered
+ immediately, before __pthread_kill_internal returns: a signal
+ sent to the thread itself needs to be delivered
+ synchronously. (It is unclear if Linux guarantees the
+ delivery of all pending signals after unblocking in the code
+ below. POSIX only guarantees delivery of a single signal,
+ which may not be the right one.) */
+ pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
+ int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo);
+ return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
}
+
+ /* Block all signals, as required by pd->exit_lock. */
+ sigset_t old_mask;
+ __libc_signal_block_all (&old_mask);
+ __libc_lock_lock (pd->exit_lock);
+
+ int ret;
+ if (pd->exiting)
+ /* The thread is about to exit (or has exited). Sending the
+ signal is either not observable (the target thread has already
+ blocked signals at this point), or it will fail, or it might be
+ delivered to a new, unrelated thread that has reused the TID.
+ So do not actually send the signal. */
+ ret = no_tid;
else
- val = ESRCH;
+ {
+ ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo);
+ ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
+ }
+
+ __libc_lock_unlock (pd->exit_lock);
+ __libc_signal_restore_set (&old_mask);
- return val;
+ return ret;
+}
+
+int
+__pthread_kill_internal (pthread_t threadid, int signo)
+{
+ /* Do not report an error in the no-tid case because the threadid
+ argument is still valid (the thread ID lifetime has not ended),
+ and ESRCH (for example) would be misleading. */
+ return __pthread_kill_implementation (threadid, signo, 0);
}
int
@@ -61,6 +88,7 @@ __pthread_kill (pthread_t threadid, int signo)
return __pthread_kill_internal (threadid, signo);
}
+
/* Some architectures (for instance arm) might pull raise through libgcc, so
avoid the symbol version if it ends up being used on ld.so. */
#if !IS_IN(rtld)
@@ -68,6 +96,17 @@ libc_hidden_def (__pthread_kill)
versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);
# if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
+/* Variant which returns ESRCH in the no-TID case, for backwards
+ compatibility. */
+int
+attribute_compat_text_section
+__pthread_kill_esrch (pthread_t threadid, int signo)
+{
+ if (__is_internal_signal (signo))
+ return EINVAL;
+
+ return __pthread_kill_implementation (threadid, signo, ESRCH);
+}
+compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0);
# endif
#endif
diff --git a/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf
new file mode 100644
index 0000000000..5b0c6a4199
--- /dev/null
+++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf
@@ -0,0 +1 @@
+hosts: files
diff --git a/posix/Makefile b/posix/Makefile
index 059efb3cd2..09460a28e8 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -107,7 +107,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \
tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
- tst-wordexp-nocmd tst-execveat tst-spawn5
+ tst-wordexp-nocmd tst-execveat tst-spawn5 \
+ tst-sched_getaffinity
# Test for the glob symbol version that was replaced in glibc 2.27.
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
index f0831386c7..622adeb2b2 100644
--- a/posix/bits/unistd.h
+++ b/posix/bits/unistd.h
@@ -199,10 +199,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path,
#endif
extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen)
- __THROW __wur __attr_access ((__write_only__, 1, 2));
+ __THROW __wur;
extern char *__REDIRECT_NTH (__getcwd_alias,
- (char *__buf, size_t __size), getcwd)
- __wur __attr_access ((__write_only__, 1, 2));
+ (char *__buf, size_t __size), getcwd) __wur;
extern char *__REDIRECT_NTH (__getcwd_chk_warn,
(char *__buf, size_t __size, size_t __buflen),
__getcwd_chk)
diff --git a/posix/fork.c b/posix/fork.c
index c471f7b15f..021691b9b7 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -99,6 +99,9 @@ __libc_fork (void)
/* Reset the lock the dynamic loader uses to protect its data. */
__rtld_lock_initialize (GL(dl_load_lock));
+ /* Reset the lock protecting dynamic TLS related data. */
+ __rtld_lock_initialize (GL(dl_load_tls_lock));
+
reclaim_stacks ();
/* Run the handlers registered for the child. */
diff --git a/posix/tst-sched_getaffinity.c b/posix/tst-sched_getaffinity.c
new file mode 100644
index 0000000000..db9d517a96
--- /dev/null
+++ b/posix/tst-sched_getaffinity.c
@@ -0,0 +1,48 @@
+/* Tests for sched_getaffinity with large buffers.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <sched.h>
+#include <support/check.h>
+
+/* NB: this test may fail on system with more than 32k cpus. */
+
+static int
+do_test (void)
+{
+ /* The values are larger than the default cpu_set_t. */
+ const int bufsize[] = { 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17 };
+ int cpucount[array_length (bufsize)];
+
+ for (int i = 0; i < array_length (bufsize); i++)
+ {
+ cpu_set_t *cpuset = CPU_ALLOC (bufsize[i]);
+ TEST_VERIFY (cpuset != NULL);
+ size_t size = CPU_ALLOC_SIZE (bufsize[i]);
+ TEST_COMPARE (sched_getaffinity (0, size, cpuset), 0);
+ cpucount[i] = CPU_COUNT_S (size, cpuset);
+ CPU_FREE (cpuset);
+ }
+
+ for (int i = 0; i < array_length (cpucount) - 1; i++)
+ TEST_COMPARE (cpucount[i], cpucount[i + 1]);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
index ac66738004..a95199af6b 100644
--- a/posix/tst-spawn5.c
+++ b/posix/tst-spawn5.c
@@ -47,17 +47,6 @@ static int initial_argv_count;
#define NFDS 100
-static int
-open_multiple_temp_files (void)
-{
- /* Check if the temporary file descriptor has no no gaps. */
- int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
- for (int i = 1; i <= NFDS; i++)
- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
- lowfd + i);
- return lowfd;
-}
-
static int
parse_fd (const char *str)
{
@@ -185,7 +174,7 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd,
static void
do_test_closefrom (void)
{
- int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
const int half_fd = lowfd + NFDS / 2;
/* Close half of the descriptors and check result. */
diff --git a/posix/unistd.h b/posix/unistd.h
index 3dca65732f..8224c5fbc9 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -528,8 +528,7 @@ extern int fchdir (int __fd) __THROW __wur;
an array is allocated with `malloc'; the array is SIZE
bytes long, unless SIZE == 0, in which case it is as
big as necessary. */
-extern char *getcwd (char *__buf, size_t __size) __THROW __wur
- __attr_access ((__write_only__, 1, 2));
+extern char *getcwd (char *__buf, size_t __size) __THROW __wur;
#ifdef __USE_GNU
/* Return a malloc'd string containing the current directory name.
diff --git a/rt/Makefile b/rt/Makefile
index 113cea03a5..910e775995 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \
tst-aio7 tst-aio8 tst-aio9 tst-aio10 \
tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
+ tst-bz28213 \
tst-timer3 tst-timer4 tst-timer5 \
tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \
tst-shm-cancel \
diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c
new file mode 100644
index 0000000000..0c096b5a0a
--- /dev/null
+++ b/rt/tst-bz28213.c
@@ -0,0 +1,101 @@
+/* Bug 28213: test for NULL pointer dereference in mq_notify.
+ Copyright (C) The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+
+static mqd_t m = -1;
+static const char msg[] = "hello";
+
+static void
+check_bz28213_cb (union sigval sv)
+{
+ char buf[sizeof (msg)];
+
+ (void) sv;
+
+ TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL)
+ == sizeof (buf));
+ TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0);
+
+ exit (0);
+}
+
+static void
+check_bz28213 (void)
+{
+ struct sigevent sev;
+
+ memset (&sev, '\0', sizeof (sev));
+ sev.sigev_notify = SIGEV_THREAD;
+ sev.sigev_notify_function = check_bz28213_cb;
+
+ /* Step 1: Register & unregister notifier.
+ Helper thread should receive NOTIFY_REMOVED notification.
+ In a vulnerable version of glibc, NULL pointer dereference follows. */
+ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
+ TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0);
+
+ /* Step 2: Once again, register notification.
+ Try to send one message.
+ Test is considered successful, if the callback does exit (0). */
+ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
+ TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0);
+
+ /* Wait... */
+ pause ();
+}
+
+static int
+do_test (void)
+{
+ static const char m_name[] = "/bz28213_queue";
+ struct mq_attr m_attr;
+
+ memset (&m_attr, '\0', sizeof (m_attr));
+ m_attr.mq_maxmsg = 1;
+ m_attr.mq_msgsize = sizeof (msg);
+
+ m = mq_open (m_name,
+ O_RDWR | O_CREAT | O_EXCL,
+ 0600,
+ &m_attr);
+
+ if (m < 0)
+ {
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n");
+ FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n");
+ }
+
+ TEST_VERIFY_EXIT (mq_unlink (m_name) == 0);
+
+ check_bz28213 ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py
index 5a77af90a6..86537fa800 100755
--- a/scripts/build-many-glibcs.py
+++ b/scripts/build-many-glibcs.py
@@ -782,7 +782,7 @@ class Context(object):
'gcc': 'vcs-11',
'glibc': 'vcs-mainline',
'gmp': '6.2.1',
- 'linux': '5.13',
+ 'linux': '5.14',
'mpc': '1.2.1',
'mpfr': '4.1.0',
'mig': 'vcs-mainline',
diff --git a/support/Makefile b/support/Makefile
index a462781718..2a0731796f 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -66,6 +66,7 @@ libsupport-routines = \
support_path_support_time64 \
support_process_state \
support_ptrace \
+ support-open-dev-null-range \
support_openpty \
support_paths \
support_quote_blob \
@@ -82,9 +83,10 @@ libsupport-routines = \
support_test_compare_blob \
support_test_compare_failure \
support_test_compare_string \
- support_write_file_string \
support_test_main \
support_test_verify_impl \
+ support_wait_for_thread_exit \
+ support_write_file_string \
temp_file \
timespec \
timespec-time64 \
@@ -264,6 +266,7 @@ tests = \
tst-support_capture_subprocess \
tst-support_descriptors \
tst-support_format_dns_packet \
+ tst-support-open-dev-null-range \
tst-support-process_state \
tst-support_quote_blob \
tst-support_quote_string \
diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c
new file mode 100644
index 0000000000..66a8504105
--- /dev/null
+++ b/support/support-open-dev-null-range.c
@@ -0,0 +1,134 @@
+/* Return a range of open file descriptors.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <support/support.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+static void
+increase_nofile (void)
+{
+ struct rlimit rl;
+ if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+
+ rl.rlim_cur += 128;
+
+ if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+}
+
+static int
+open_dev_null (int flags, mode_t mode)
+{
+ int fd = open64 ("/dev/null", flags, mode);
+ if (fd >= 0)
+ return fd;
+
+ if (fd < 0 && errno != EMFILE)
+ FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode);
+
+ increase_nofile ();
+
+ return xopen ("/dev/null", flags, mode);
+}
+
+struct range
+{
+ int lowfd;
+ size_t len;
+};
+
+struct range_list
+{
+ size_t total;
+ size_t used;
+ struct range *ranges;
+};
+
+static void
+range_init (struct range_list *r)
+{
+ r->total = 8;
+ r->used = 0;
+ r->ranges = xmalloc (r->total * sizeof (struct range));
+}
+
+static void
+range_add (struct range_list *r, int lowfd, size_t len)
+{
+ if (r->used == r->total)
+ {
+ r->total *= 2;
+ r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range));
+ }
+ r->ranges[r->used].lowfd = lowfd;
+ r->ranges[r->used].len = len;
+ r->used++;
+}
+
+static void
+range_close (struct range_list *r)
+{
+ for (size_t i = 0; i < r->used; i++)
+ {
+ int minfd = r->ranges[i].lowfd;
+ int maxfd = r->ranges[i].lowfd + r->ranges[i].len;
+ for (int fd = minfd; fd < maxfd; fd++)
+ xclose (fd);
+ }
+ free (r->ranges);
+}
+
+int
+support_open_dev_null_range (int num, int flags, mode_t mode)
+{
+ /* We keep track of the ranges that hit an already opened descriptor, so
+ we close them after we get a working range. */
+ struct range_list rl;
+ range_init (&rl);
+
+ int lowfd = open_dev_null (flags, mode);
+ int prevfd = lowfd;
+ while (true)
+ {
+ int i = 1;
+ for (; i < num; i++)
+ {
+ int fd = open_dev_null (flags, mode);
+ if (fd != lowfd + i)
+ {
+ range_add (&rl, lowfd, prevfd - lowfd + 1);
+
+ prevfd = lowfd = fd;
+ break;
+ }
+ prevfd = fd;
+ }
+ if (i == num)
+ break;
+ }
+
+ range_close (&rl);
+
+ return lowfd;
+}
diff --git a/support/support.h b/support/support.h
index 834dba9097..c219e0d9d1 100644
--- a/support/support.h
+++ b/support/support.h
@@ -174,6 +174,10 @@ timer_t support_create_timer (uint64_t sec, long int nsec, bool repeat,
/* Disable the timer TIMER. */
void support_delete_timer (timer_t timer);
+/* Wait until all threads except the current thread have exited (as
+ far as the kernel is concerned). */
+void support_wait_for_thread_exit (void);
+
struct support_stack
{
void *stack;
@@ -193,6 +197,14 @@ struct support_stack support_stack_alloc (size_t size);
/* Deallocate the STACK. */
void support_stack_free (struct support_stack *stack);
+
+/* Create a range of NUM opened '/dev/null' file descriptors using FLAGS and
+ MODE. The function takes care of restarting the open range if a file
+ descriptor is found within the specified range and also increases
+ RLIMIT_NOFILE if required.
+ The returned value is the lowest file descriptor number. */
+int support_open_dev_null_range (int num, int flags, mode_t mode);
+
__END_DECLS
#endif /* SUPPORT_H */
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index 27bfd19c93..0bacf6dbc2 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -170,6 +170,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid)
support_subprogram because we only want the program exit status, not the
contents. */
ret = 0;
+ infd = outfd = -1;
char * const args[] = {execname, child_id, NULL};
diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c
new file mode 100644
index 0000000000..5e3be421a7
--- /dev/null
+++ b/support/support_wait_for_thread_exit.c
@@ -0,0 +1,75 @@
+/* Wait until all threads except the current thread has exited.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <unistd.h>
+
+void
+support_wait_for_thread_exit (void)
+{
+#ifdef __linux__
+ DIR *proc_self_task = opendir ("/proc/self/task");
+ TEST_VERIFY_EXIT (proc_self_task != NULL);
+
+ while (true)
+ {
+ errno = 0;
+ struct dirent *e = readdir (proc_self_task);
+ if (e == NULL && errno != 0)
+ FAIL_EXIT1 ("readdir: %m");
+ if (e == NULL)
+ {
+ /* Only the main thread remains. Testing may continue. */
+ closedir (proc_self_task);
+ return;
+ }
+
+ /* In some kernels, "0" entries denote a thread that has just
+ exited. */
+ if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0
+ || strcmp (e->d_name, "0") == 0)
+ continue;
+
+ int task_tid = atoi (e->d_name);
+ if (task_tid <= 0)
+ FAIL_EXIT1 ("Invalid /proc/self/task entry: %s", e->d_name);
+
+ if (task_tid == gettid ())
+ /* The current thread. Keep scanning for other
+ threads. */
+ continue;
+
+ /* task_tid does not refer to this thread here, i.e., there is
+ another running thread. */
+
+ /* Small timeout to give the thread a chance to exit. */
+ usleep (50 * 1000);
+
+ /* Start scanning the directory from the start. */
+ rewinddir (proc_self_task);
+ }
+#else
+ /* Use a large timeout because we cannot verify that the thread has
+ exited. */
+ usleep (5 * 1000 * 1000);
+#endif
+}
diff --git a/support/tst-support-open-dev-null-range.c b/support/tst-support-open-dev-null-range.c
new file mode 100644
index 0000000000..8e29def1ce
--- /dev/null
+++ b/support/tst-support-open-dev-null-range.c
@@ -0,0 +1,155 @@
+/* Tests for support_open_dev_null_range.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/resource.h>
+#include <stdlib.h>
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+#include <stdio.h>
+
+static void
+check_path (int fd)
+{
+ char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd);
+ char file_path[PATH_MAX];
+ ssize_t file_path_length
+ = readlink (proc_fd_path, file_path, sizeof (file_path));
+ free (proc_fd_path);
+ if (file_path_length < 0)
+ FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path,
+ sizeof (file_path));
+ file_path[file_path_length] = '\0';
+ TEST_COMPARE_STRING (file_path, "/dev/null");
+}
+
+static int
+number_of_opened_files (void)
+{
+ DIR *fds = opendir ("/proc/self/fd");
+ if (fds == NULL)
+ FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m");
+
+ int r = 0;
+ while (true)
+ {
+ errno = 0;
+ struct dirent64 *e = readdir64 (fds);
+ if (e == NULL)
+ {
+ if (errno != 0)
+ FAIL_EXIT1 ("readdir: %m");
+ break;
+ }
+
+ if (e->d_name[0] == '.')
+ continue;
+
+ char *endptr;
+ long int fd = strtol (e->d_name, &endptr, 10);
+ if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
+ FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
+ e->d_name);
+
+ /* Skip the descriptor which is used to enumerate the
+ descriptors. */
+ if (fd == dirfd (fds))
+ continue;
+
+ r = r + 1;
+ }
+
+ closedir (fds);
+
+ return r;
+}
+
+static int
+do_test (void)
+{
+ const int nfds1 = 8;
+ int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600);
+ for (int i = 0; i < nfds1; i++)
+ {
+ TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1);
+ check_path (lowfd + i);
+ }
+
+ /* create some gaps. */
+ xclose (lowfd + 1);
+ xclose (lowfd + 5);
+ xclose (lowfd + 6);
+
+ const int nfds2 = 16;
+ int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600);
+ for (int i = 0; i < nfds2; i++)
+ {
+ TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1);
+ check_path (lowfd2 + i);
+ }
+
+ /* Decrease the maximum number of files. */
+ {
+ struct rlimit rl;
+ if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+
+ rl.rlim_cur = number_of_opened_files ();
+
+ if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+ }
+
+ const int nfds3 = 16;
+ int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600);
+ for (int i = 0; i < nfds3; i++)
+ {
+ TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1);
+ check_path (lowfd3 + i);
+ }
+
+ /* create a lot of gaps to trigger the range extension. */
+ xclose (lowfd3 + 1);
+ xclose (lowfd3 + 3);
+ xclose (lowfd3 + 5);
+ xclose (lowfd3 + 7);
+ xclose (lowfd3 + 9);
+ xclose (lowfd3 + 11);
+ xclose (lowfd3 + 13);
+
+ const int nfds4 = 16;
+ int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600);
+ for (int i = 0; i < nfds4; i++)
+ {
+ TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1);
+ check_path (lowfd4 + i);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h
new file mode 100644
index 0000000000..cfb86c2d6a
--- /dev/null
+++ b/sysdeps/generic/dl-relocate-ld.h
@@ -0,0 +1,25 @@
+/* Check if dynamic section should be relocated. Generic version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_RELOCATE_LD_H
+#define _DL_RELOCATE_LD_H
+
+/* The dynamic section is writable. */
+#define DL_RO_DYN_SECTION 0
+
+#endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 9c15259236..fcbbf69748 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -69,17 +69,24 @@ __BEGIN_DECLS
`ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type)
+/* Return true if dynamic section in the shared library L should be
+ relocated. */
+
+static inline bool
+dl_relocate_ld (const struct link_map *l)
+{
+ /* Don't relocate dynamic section if it is readonly */
+ return !(l->l_ld_readonly || DL_RO_DYN_SECTION);
+}
+
/* All references to the value of l_info[DT_PLTGOT],
l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA],
l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)]
have to be accessed via the D_PTR macro. The macro is needed since for
most architectures the entry is already relocated - but for some not
and we need to relocate at access time. */
-#ifdef DL_RO_DYN_SECTION
-# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr)
-#else
-# define D_PTR(map, i) (map)->i->d_un.d_ptr
-#endif
+#define D_PTR(map, i) \
+ ((map)->i->d_un.d_ptr + (dl_relocate_ld (map) ? 0 : (map)->l_addr))
/* Result of the lookup functions and how to retrieve the base address. */
typedef struct link_map *lookup_t;
@@ -372,6 +379,13 @@ struct rtld_global
list of loaded objects while an object is added to or removed
from that list. */
__rtld_lock_define_recursive (EXTERN, _dl_load_write_lock)
+ /* This lock protects global and module specific TLS related data.
+ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+ accessed and when TLS related relocations are processed for a
+ module. It was introduced to keep pthread_create accessing TLS
+ state that is being set up. */
+ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock)
/* Incremented whenever something may have been added to dl_loaded. */
EXTERN unsigned long long _dl_load_adds;
@@ -1261,7 +1275,7 @@ extern int _dl_scope_free (void *) attribute_hidden;
/* Add module to slot information data. If DO_ADD is false, only the
required memory is allocated. Must be called with GL
- (dl_load_lock) acquired. If the function has already been called
+ (dl_load_tls_lock) acquired. If the function has already been called
for the link map L with !do_add, then this function will not raise
an exception, otherwise it is possible that it encounters a memory
allocation failure. */
diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c
index 1267f39da2..cc8023f979 100644
--- a/sysdeps/mach/getsysstats.c
+++ b/sysdeps/mach/getsysstats.c
@@ -62,6 +62,12 @@ __get_nprocs (void)
libc_hidden_def (__get_nprocs)
weak_alias (__get_nprocs, get_nprocs)
+int
+__get_nprocs_sched (void)
+{
+ return __get_nprocs ();
+}
+
/* Return the number of physical pages on the system. */
long int
__get_phys_pages (void)
diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h
new file mode 100644
index 0000000000..376ad75dd1
--- /dev/null
+++ b/sysdeps/mips/dl-relocate-ld.h
@@ -0,0 +1,25 @@
+/* Check if dynamic section should be relocated. MIPS version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_RELOCATE_LD_H
+#define _DL_RELOCATE_LD_H
+
+/* The dynamic section is readonly. */
+#define DL_RO_DYN_SECTION 1
+
+#endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h
index 4db7c60e38..36fd09a8bd 100644
--- a/sysdeps/mips/ldsodefs.h
+++ b/sysdeps/mips/ldsodefs.h
@@ -75,10 +75,6 @@ struct La_mips_64_retval;
struct La_mips_64_retval *, \
const char *);
-/* The MIPS ABI specifies that the dynamic section has to be read-only. */
-
-#define DL_RO_DYN_SECTION 1
-
#include_next <ldsodefs.h>
/* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index f1b7f2bdc6..43146e91c9 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr,
# ifdef __USE_GNU
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np,
- (pthread_mutex_t *, int *),
+ (pthread_mutexattr_t *, int *),
pthread_mutexattr_getrobust) __nonnull ((1))
__attribute_deprecated_msg__ ("\
pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust");
@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr,
# ifdef __USE_GNU
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np,
- (pthread_mutex_t *, int),
+ (pthread_mutexattr_t *, int),
pthread_mutexattr_setrobust) __nonnull ((1))
__attribute_deprecated_msg__ ("\
pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust");
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 838a68f022..43dfc6739e 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -2008,6 +2008,7 @@ gaiconf_init (void)
l = l->next;
}
free_prefixlist (labellist);
+ labellist = NULL;
/* Sort the entries so that the most specific ones are at
the beginning. */
@@ -2046,6 +2047,7 @@ gaiconf_init (void)
l = l->next;
}
free_prefixlist (precedencelist);
+ precedencelist = NULL;
/* Sort the entries so that the most specific ones are at
the beginning. */
diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
index 589f7c8d18..cfcfa69f91 100644
--- a/sysdeps/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/powerpc/powerpc64/sysdep.h
@@ -275,12 +275,14 @@ LT_LABELSUFFIX(name,_name_end): ; \
/* Allocate frame and save register */
#define NVOLREG_SAVE \
stdu r1,-SCV_FRAME_SIZE(r1); \
+ cfi_adjust_cfa_offset(SCV_FRAME_SIZE); \
std r31,SCV_FRAME_NVOLREG_SAVE(r1); \
- cfi_adjust_cfa_offset(SCV_FRAME_SIZE);
+ cfi_rel_offset(r31,SCV_FRAME_NVOLREG_SAVE);
/* Restore register and destroy frame */
#define NVOLREG_RESTORE \
ld r31,SCV_FRAME_NVOLREG_SAVE(r1); \
+ cfi_restore(r31); \
addi r1,r1,SCV_FRAME_SIZE; \
cfi_adjust_cfa_offset(-SCV_FRAME_SIZE);
@@ -331,13 +333,13 @@ LT_LABELSUFFIX(name,_name_end): ; \
#define DO_CALL_SCV \
mflr r9; \
- std r9,FRAME_LR_SAVE(r1); \
- cfi_offset(lr,FRAME_LR_SAVE); \
+ std r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \
+ cfi_rel_offset(lr,SCV_FRAME_SIZE+FRAME_LR_SAVE); \
.machine "push"; \
.machine "power9"; \
scv 0; \
.machine "pop"; \
- ld r9,FRAME_LR_SAVE(r1); \
+ ld r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \
mtlr r9; \
cfi_restore(lr);
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 42f9fc5072..c657101696 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -89,7 +89,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
tst-join8 tst-join9 tst-join10 tst-join11 tst-join12 tst-join13 \
tst-join14 tst-join15 \
tst-key1 tst-key2 tst-key3 tst-key4 \
- tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
+ tst-kill1 tst-kill2 tst-kill3 tst-kill5 tst-kill6 \
tst-locale1 tst-locale2 \
tst-memstream \
tst-mutex-errorcheck tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 \
@@ -118,6 +118,14 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
tst-unload \
tst-unwind-thread \
tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
+ tst-pthread-exit-signal \
+ tst-pthread-setuid-loop \
+ tst-pthread_cancel-exited \
+ tst-pthread_cancel-select-loop \
+ tst-pthread-raise-blocked-self \
+ tst-pthread_kill-exited \
+ tst-pthread_kill-exiting \
+ # tests
tests-time64 := \
tst-abstime-time64 \
@@ -145,15 +153,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \
tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3
ifeq ($(build-shared),yes)
-tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1
+tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1
tests-nolibpthread += tst-fini1
endif
modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \
- tst-_res1mod1 tst-_res1mod2 tst-fini1mod
+ tst-_res1mod1 tst-_res1mod2 tst-fini1mod \
+ tst-create1mod
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
tst-atfork2mod.so-no-z-defs = yes
+tst-create1mod.so-no-z-defs = yes
ifeq ($(build-shared),yes)
# Build all the modules even when not actually running test programs.
@@ -272,4 +282,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so
CFLAGS-tst-unwind-thread.c += -funwind-tables
+LDFLAGS-tst-create1 = -Wl,-export-dynamic
+$(objpfx)tst-create1: $(shared-thread-library)
+$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so
+
endif
diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c
new file mode 100644
index 0000000000..763ded8d79
--- /dev/null
+++ b/sysdeps/pthread/tst-create1.c
@@ -0,0 +1,123 @@
+/* Verify that pthread_create does not deadlock when ctors take locks.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+
+/*
+Check if ctor and pthread_create deadlocks in
+
+thread 1: dlopen -> ctor -> lock(user_lock)
+thread 2: lock(user_lock) -> pthread_create
+
+or in
+
+thread 1: dlclose -> dtor -> lock(user_lock)
+thread 2: lock(user_lock) -> pthread_create
+*/
+
+static pthread_barrier_t bar_ctor;
+static pthread_barrier_t bar_ctor_finish;
+static pthread_barrier_t bar_dtor;
+static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void
+ctor (void)
+{
+ xpthread_barrier_wait (&bar_ctor);
+ dprintf (1, "thread 1: in ctor: started.\n");
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 1: in ctor: locked user_lock.\n");
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 1: in ctor: unlocked user_lock.\n");
+ dprintf (1, "thread 1: in ctor: done.\n");
+ xpthread_barrier_wait (&bar_ctor_finish);
+}
+
+void
+dtor (void)
+{
+ xpthread_barrier_wait (&bar_dtor);
+ dprintf (1, "thread 1: in dtor: started.\n");
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 1: in dtor: locked user_lock.\n");
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 1: in dtor: unlocked user_lock.\n");
+ dprintf (1, "thread 1: in dtor: done.\n");
+}
+
+static void *
+thread3 (void *a)
+{
+ dprintf (1, "thread 3: started.\n");
+ dprintf (1, "thread 3: done.\n");
+ return 0;
+}
+
+static void *
+thread2 (void *a)
+{
+ pthread_t t3;
+ dprintf (1, "thread 2: started.\n");
+
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 2: locked user_lock.\n");
+ xpthread_barrier_wait (&bar_ctor);
+ t3 = xpthread_create (0, thread3, 0);
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 2: unlocked user_lock.\n");
+ xpthread_join (t3);
+ xpthread_barrier_wait (&bar_ctor_finish);
+
+ xpthread_mutex_lock (&user_lock);
+ dprintf (1, "thread 2: locked user_lock.\n");
+ xpthread_barrier_wait (&bar_dtor);
+ t3 = xpthread_create (0, thread3, 0);
+ xpthread_mutex_unlock (&user_lock);
+ dprintf (1, "thread 2: unlocked user_lock.\n");
+ xpthread_join (t3);
+
+ dprintf (1, "thread 2: done.\n");
+ return 0;
+}
+
+static void
+thread1 (void)
+{
+ dprintf (1, "thread 1: started.\n");
+ xpthread_barrier_init (&bar_ctor, NULL, 2);
+ xpthread_barrier_init (&bar_ctor_finish, NULL, 2);
+ xpthread_barrier_init (&bar_dtor, NULL, 2);
+ pthread_t t2 = xpthread_create (0, thread2, 0);
+ void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL);
+ dprintf (1, "thread 1: dlopen done.\n");
+ xdlclose (p);
+ dprintf (1, "thread 1: dlclose done.\n");
+ xpthread_join (t2);
+ dprintf (1, "thread 1: done.\n");
+}
+
+static int
+do_test (void)
+{
+ thread1 ();
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c
new file mode 100644
index 0000000000..62c9006961
--- /dev/null
+++ b/sysdeps/pthread/tst-create1mod.c
@@ -0,0 +1,41 @@
+/* Verify that pthread_create does not deadlock when ctors take locks.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+/* Require TLS setup for the module. */
+__thread int tlsvar;
+
+void ctor (void);
+void dtor (void);
+
+static void __attribute__ ((constructor))
+do_init (void)
+{
+ dprintf (1, "constructor started: %d.\n", tlsvar++);
+ ctor ();
+ dprintf (1, "constructor done: %d.\n", tlsvar++);
+}
+
+static void __attribute__ ((destructor))
+do_end (void)
+{
+ dprintf (1, "destructor started: %d.\n", tlsvar++);
+ dtor ();
+ dprintf (1, "destructor done: %d.\n", tlsvar++);
+}
diff --git a/sysdeps/pthread/tst-kill4.c b/sysdeps/pthread/tst-kill4.c
deleted file mode 100644
index 9563939792..0000000000
--- a/sysdeps/pthread/tst-kill4.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2003-2021 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have 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 <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-static void *
-tf (void *a)
-{
- return NULL;
-}
-
-
-int
-do_test (void)
-{
- pthread_attr_t at;
- if (pthread_attr_init (&at) != 0)
- {
- puts ("attr_create failed");
- exit (1);
- }
-
- /* Limit thread stack size, because if it is too large, pthread_join
- will free it immediately rather than put it into stack cache. */
- if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0)
- {
- puts ("setstacksize failed");
- exit (1);
- }
-
- pthread_t th;
- if (pthread_create (&th, &at, tf, NULL) != 0)
- {
- puts ("create failed");
- exit (1);
- }
-
- pthread_attr_destroy (&at);
-
- if (pthread_join (th, NULL) != 0)
- {
- puts ("join failed");
- exit (1);
- }
-
- /* The following only works because we assume here something about
- the implementation. Namely, that the memory allocated for the
- thread descriptor is not going away, that the TID field is
- cleared and therefore the signal is sent to process 0, and that
- we can savely assume there is no other process with this ID at
- that time. */
- int e = pthread_kill (th, 0);
- if (e == 0)
- {
- puts ("pthread_kill succeeded");
- exit (1);
- }
- if (e != ESRCH)
- {
- puts ("pthread_kill didn't return ESRCH");
- exit (1);
- }
-
- return 0;
-}
-
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c
new file mode 100644
index 0000000000..b4526fe663
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread-exit-signal.c
@@ -0,0 +1,45 @@
+/* Test that pending signals are not delivered on thread exit (bug 28607).
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* Due to bug 28607, pthread_kill (or pthread_cancel) restored the
+ signal mask during during thread exit, triggering the delivery of a
+ blocked pending signal (SIGUSR1 in this test). */
+
+#include <support/xthread.h>
+#include <support/xsignal.h>
+
+static void *
+threadfunc (void *closure)
+{
+ sigset_t sigmask;
+ sigfillset (&sigmask);
+ xpthread_sigmask (SIG_SETMASK, &sigmask, NULL);
+ xpthread_kill (pthread_self (), SIGUSR1);
+ pthread_exit (NULL);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, threadfunc, NULL);
+ xpthread_join (thr);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
new file mode 100644
index 0000000000..128e1a6071
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
@@ -0,0 +1,92 @@
+/* Test that raise sends signal to current thread even if blocked.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <signal.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <pthread.h>
+#include <unistd.h>
+
+/* Used to create a dummy thread ID distinct from all other thread
+ IDs. */
+static void *
+noop (void *ignored)
+{
+ return NULL;
+}
+
+static volatile pthread_t signal_thread;
+
+static void
+signal_handler (int signo)
+{
+ signal_thread = pthread_self ();
+}
+
+/* Used to ensure that waiting_thread has launched and can accept
+ signals. */
+static pthread_barrier_t barrier;
+
+static void *
+waiting_thread (void *ignored)
+{
+ xpthread_barrier_wait (&barrier);
+ pause ();
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ xsignal (SIGUSR1, signal_handler);
+ xpthread_barrier_init (&barrier, NULL, 2);
+
+ /* Distinct thread ID value to */
+ pthread_t dummy = xpthread_create (NULL, noop, NULL);
+ signal_thread = dummy;
+
+ pthread_t helper = xpthread_create (NULL, waiting_thread, NULL);
+
+ /* Make sure that the thread is running. */
+ xpthread_barrier_wait (&barrier);
+
+ /* Block signals on this thread. */
+ sigset_t set;
+ sigfillset (&set);
+ xpthread_sigmask (SIG_BLOCK, &set, NULL);
+
+ /* Send the signal to this thread. It must not be delivered. */
+ raise (SIGUSR1);
+ TEST_VERIFY (signal_thread == dummy);
+
+ /* Wait a bit to give a chance for signal delivery (increases
+ chances of failure with bug 28407). */
+ usleep (50 * 1000);
+
+ /* Unblocking should cause synchronous delivery of the signal. */
+ xpthread_sigmask (SIG_UNBLOCK, &set, NULL);
+ TEST_VERIFY (signal_thread == pthread_self ());
+
+ xpthread_cancel (helper);
+ xpthread_join (helper);
+ xpthread_join (dummy);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c
new file mode 100644
index 0000000000..fda2a49b7f
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread-setuid-loop.c
@@ -0,0 +1,61 @@
+/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361).
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xthread.h>
+#include <unistd.h>
+
+/* How many threads to launch during each iteration. */
+enum { threads = 4 };
+
+/* How many iterations to perform. This value seems to reproduce
+ bug 28361 in a bout one in three runs. */
+enum { iterations = 5000 };
+
+/* Cache of the real user ID used by setuid_thread. */
+static uid_t uid;
+
+/* Start routine for the threads. */
+static void *
+setuid_thread (void *closure)
+{
+ TEST_COMPARE (setuid (uid), 0);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ /* The setxid machinery is still invoked even if the UID is
+ unchanged. (The kernel might reset other credentials as part of
+ the system call.) */
+ uid = getuid ();
+
+ for (int i = 0; i < iterations; ++i)
+ {
+ pthread_t thread_ids[threads];
+ for (int j = 0; j < threads; ++j)
+ thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL);
+ for (int j = 0; j < threads; ++j)
+ xpthread_join (thread_ids[j]);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread_cancel-exited.c b/sysdeps/pthread/tst-pthread_cancel-exited.c
new file mode 100644
index 0000000000..811c9bee07
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_cancel-exited.c
@@ -0,0 +1,45 @@
+/* Test that pthread_kill succeeds for an exited thread.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* This test verifies that pthread_kill returns 0 (and not ESRCH) for
+ a thread that has exited on the kernel side. */
+
+#include <stddef.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+static void *
+noop_thread (void *closure)
+{
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, noop_thread, NULL);
+
+ support_wait_for_thread_exit ();
+
+ xpthread_cancel (thr);
+ xpthread_join (thr);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
new file mode 100644
index 0000000000..a62087589c
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
@@ -0,0 +1,87 @@
+/* Test that pthread_cancel succeeds during thread exit.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* This test tries to trigger an internal race condition in
+ pthread_cancel, where the cancellation signal is sent after the
+ thread has begun the cancellation process. This can result in a
+ spurious ESRCH error. For the original bug 12889, the window is
+ quite small, so the bug was not reproduced in every run. */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <support/check.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+/* Set to true by timeout_thread_function when the test should
+ terminate. */
+static bool timeout;
+
+static void *
+timeout_thread_function (void *unused)
+{
+ usleep (5 * 1000 * 1000);
+ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
+ return NULL;
+}
+
+/* Used for blocking the select function below. */
+static int pipe_fds[2];
+
+static void *
+canceled_thread_function (void *unused)
+{
+ while (true)
+ {
+ fd_set rfs;
+ fd_set wfs;
+ fd_set efs;
+ FD_ZERO (&rfs);
+ FD_ZERO (&wfs);
+ FD_ZERO (&efs);
+ FD_SET (pipe_fds[0], &rfs);
+
+ /* If the cancellation request is recognized early, the thread
+ begins exiting while the cancellation signal arrives. */
+ select (FD_SETSIZE, &rfs, &wfs, &efs, NULL);
+ }
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ xpipe (pipe_fds);
+ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
+
+ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
+ {
+ pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL);
+ xpthread_cancel (thr);
+ TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED);
+ }
+
+ xpthread_join (thr_timeout);
+ xclose (pipe_fds[0]);
+ xclose (pipe_fds[1]);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c
new file mode 100644
index 0000000000..a2fddad526
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_kill-exited.c
@@ -0,0 +1,63 @@
+/* Test that pthread_kill succeeds for an exited thread.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* This test verifies that the default pthread_kill returns 0 (and not
+ ESRCH) for a thread that has exited on the kernel side. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <shlib-compat.h>
+#include <signal.h>
+#include <stddef.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+static void *
+noop_thread (void *closure)
+{
+ return NULL;
+}
+
+#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
+extern __typeof (pthread_kill) compat_pthread_kill;
+compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill,
+ GLIBC_2_0);
+#endif
+
+static int
+do_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, noop_thread, NULL);
+
+ support_wait_for_thread_exit ();
+
+ /* NB: Always uses the default symbol due to separate compilation. */
+ xpthread_kill (thr, SIGUSR1);
+
+#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
+ /* Old binaries need the non-conforming ESRCH error code. */
+ TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH);
+#endif
+
+ xpthread_join (thr);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c
new file mode 100644
index 0000000000..f803e94f11
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_kill-exiting.c
@@ -0,0 +1,123 @@
+/* Test that pthread_kill succeeds during thread exit.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* This test verifies that pthread_kill for a thread that is exiting
+ succeeds (with or without actually delivering the signal). */
+
+#include <array_length.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <unistd.h>
+
+/* Set to true by timeout_thread_function when the test should
+ terminate. */
+static bool timeout;
+
+static void *
+timeout_thread_function (void *unused)
+{
+ usleep (1000 * 1000);
+ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
+ return NULL;
+}
+
+/* Used to synchronize the sending threads with the target thread and
+ main thread. */
+static pthread_barrier_t barrier_1;
+static pthread_barrier_t barrier_2;
+
+/* The target thread to which signals are to be sent. */
+static pthread_t target_thread;
+
+/* Set by the main thread to true after timeout has been set to
+ true. */
+static bool exiting;
+
+static void *
+sender_thread_function (void *unused)
+{
+ while (true)
+ {
+ /* Wait until target_thread has been initialized. The target
+ thread and main thread participate in this barrier. */
+ xpthread_barrier_wait (&barrier_1);
+
+ if (exiting)
+ break;
+
+ xpthread_kill (target_thread, SIGUSR1);
+
+ /* Communicate that the signal has been sent. The main thread
+ participates in this barrier. */
+ xpthread_barrier_wait (&barrier_2);
+ }
+ return NULL;
+}
+
+static void *
+target_thread_function (void *unused)
+{
+ target_thread = pthread_self ();
+ xpthread_barrier_wait (&barrier_1);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ xsignal (SIGUSR1, SIG_IGN);
+
+ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
+
+ pthread_t threads[4];
+ xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2);
+ xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1);
+
+ for (int i = 0; i < array_length (threads); ++i)
+ threads[i] = xpthread_create (NULL, sender_thread_function, NULL);
+
+ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
+ {
+ xpthread_create (NULL, target_thread_function, NULL);
+
+ /* Wait for the target thread to be set up and signal sending to
+ start. */
+ xpthread_barrier_wait (&barrier_1);
+
+ /* Wait for signal sending to complete. */
+ xpthread_barrier_wait (&barrier_2);
+
+ xpthread_join (target_thread);
+ }
+
+ exiting = true;
+
+ /* Signal the sending threads to exit. */
+ xpthread_create (NULL, target_thread_function, NULL);
+ xpthread_barrier_wait (&barrier_1);
+
+ for (int i = 0; i < array_length (threads); ++i)
+ xpthread_join (threads[i]);
+ xpthread_join (thr_timeout);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h
new file mode 100644
index 0000000000..2ab2b8ac6c
--- /dev/null
+++ b/sysdeps/riscv/dl-relocate-ld.h
@@ -0,0 +1,25 @@
+/* Check if dynamic section should be relocated. RISC-V version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_RELOCATE_LD_H
+#define _DL_RELOCATE_LD_H
+
+/* The dynamic section is readonly for ABI compatibility. */
+#define DL_RO_DYN_SECTION 1
+
+#endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h
index 0c696714a7..8947ffe4b5 100644
--- a/sysdeps/riscv/ldsodefs.h
+++ b/sysdeps/riscv/ldsodefs.h
@@ -38,11 +38,6 @@ struct La_riscv_retval;
struct La_riscv_retval *, \
const char *);
-/* Although the RISC-V ABI does not specify that the dynamic section has
- to be read-only, it needs to be kept for ABI compatibility. */
-
-#define DL_RO_DYN_SECTION 1
-
#include_next <ldsodefs.h>
#endif
diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c
index c174e27b35..155f0bd99e 100644
--- a/sysdeps/s390/dl-procinfo.c
+++ b/sysdeps/s390/dl-procinfo.c
@@ -46,13 +46,13 @@
#if !defined PROCINFO_DECL && defined SHARED
._dl_s390_cap_flags
#else
-PROCINFO_CLASS const char _dl_s390_cap_flags[21][9]
+PROCINFO_CLASS const char _dl_s390_cap_flags[23][9]
#endif
#ifndef PROCINFO_DECL
= {
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh",
"highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt",
- "vxp2", "nnpa"
+ "vxp2", "nnpa", "pcimio", "sie"
}
#endif
#if !defined SHARED || defined PROCINFO_DECL
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
index 2d9c305808..e4e3e334a5 100644
--- a/sysdeps/s390/dl-procinfo.h
+++ b/sysdeps/s390/dl-procinfo.h
@@ -21,7 +21,7 @@
#define _DL_PROCINFO_H 1
#include <ldsodefs.h>
-#define _DL_HWCAP_COUNT 21
+#define _DL_HWCAP_COUNT 23
#define _DL_PLATFORMS_COUNT 10
@@ -63,6 +63,8 @@ enum
HWCAP_S390_DFLT = 1 << 18,
HWCAP_S390_VXRS_PDE2 = 1 << 19,
HWCAP_S390_NNPA = 1 << 20,
+ HWCAP_S390_PCI_MIO = 1 << 21,
+ HWCAP_S390_SIE = 1 << 22,
};
#define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S
index c5c8d8c97e..58df8cdb14 100644
--- a/sysdeps/s390/memmem-arch13.S
+++ b/sysdeps/s390/memmem-arch13.S
@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13)
# error The arch13 variant of memmem needs the z13 variant of memmem!
# endif
clgfi %r5,9
- jh MEMMEM_Z13
+ jgh MEMMEM_Z13
aghik %r0,%r5,-1 /* vll needs highest index. */
bc 4,0(%r14) /* cc==1: return if needle-len == 0. */
diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S
index c7183e627c..222a6de91a 100644
--- a/sysdeps/s390/strstr-arch13.S
+++ b/sysdeps/s390/strstr-arch13.S
@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13)
# error The arch13 variant of strstr needs the z13 variant of strstr!
# endif
clgfi %r4,9
- jh STRSTR_Z13
+ jgh STRSTR_Z13
/* In case of a partial match, the vstrs instruction returns the index
of the partial match in a vector-register. Then we have to
diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
index e9eb707d0a..bedab1abba 100644
--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
@@ -126,6 +126,7 @@
#define __NR_mbind 235
#define __NR_membarrier 283
#define __NR_memfd_create 279
+#define __NR_memfd_secret 447
#define __NR_migrate_pages 238
#define __NR_mincore 232
#define __NR_mkdirat 34
@@ -187,6 +188,7 @@
#define __NR_pwritev 70
#define __NR_pwritev2 287
#define __NR_quotactl 60
+#define __NR_quotactl_fd 443
#define __NR_read 63
#define __NR_readahead 213
#define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
index bd6b7d4003..91354ed9e2 100644
--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
@@ -337,6 +337,7 @@
#define __NR_pwritev2 521
#define __NR_query_module 347
#define __NR_quotactl 148
+#define __NR_quotactl_fd 553
#define __NR_read 3
#define __NR_readahead 379
#define __NR_readlink 58
diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
index 10650549c1..ff5c7eb36d 100644
--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
@@ -190,6 +190,7 @@
#define __NR_pwritev 70
#define __NR_pwritev2 287
#define __NR_quotactl 60
+#define __NR_quotactl_fd 443
#define __NR_read 63
#define __NR_readahead 213
#define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
index 85c9b236ce..5772333cee 100644
--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
@@ -244,6 +244,7 @@
#define __NR_pwritev 362
#define __NR_pwritev2 393
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 225
#define __NR_readlink 85
diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h
index 3b1ae418e0..31451c28d9 100644
--- a/sysdeps/unix/sysv/linux/bits/mman-linux.h
+++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h
@@ -89,6 +89,10 @@
# define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK. */
# define MADV_COLD 20 /* Deactivate these pages. */
# define MADV_PAGEOUT 21 /* Reclaim these pages. */
+# define MADV_POPULATE_READ 22 /* Populate (prefault) page tables
+ readable. */
+# define MADV_POPULATE_WRITE 23 /* Populate (prefault) page tables
+ writable. */
# define MADV_HWPOISON 100 /* Poison a page for testing. */
#endif
diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h
index ee37694e8f..4a5db6deca 100644
--- a/sysdeps/unix/sysv/linux/bits/timex.h
+++ b/sysdeps/unix/sysv/linux/bits/timex.h
@@ -25,7 +25,7 @@
struct timex
{
-# ifdef __USE_TIME_BITS64
+# if defined __USE_TIME_BITS64 || (__TIMESIZE == 64 && __WORDSIZE == 32)
unsigned int modes; /* mode selector */
int :32; /* pad */
long long offset; /* time offset (usec) */
diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
index 24b0d1f94e..4af6d6202f 100644
--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
@@ -199,6 +199,7 @@
#define __NR_pwritev 70
#define __NR_pwritev2 287
#define __NR_quotactl 60
+#define __NR_quotactl_fd 443
#define __NR_read 63
#define __NR_readahead 213
#define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
index 1391e360b8..7fc6521942 100644
--- a/sysdeps/unix/sysv/linux/getsysstats.c
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
@@ -18,6 +18,8 @@
<https://www.gnu.org/licenses/>. */
#include <array_length.h>
+#include <assert.h>
+#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <ldsodefs.h>
@@ -29,61 +31,170 @@
#include <sys/sysinfo.h>
#include <sysdep.h>
-/* Compute the population count of the entire array. */
-static int
-__get_nprocs_count (const unsigned long int *array, size_t length)
+int
+__get_nprocs_sched (void)
{
- int count = 0;
- for (size_t i = 0; i < length; ++i)
- if (__builtin_add_overflow (count, __builtin_popcountl (array[i]),
- &count))
- return INT_MAX;
- return count;
+ enum
+ {
+ max_num_cpus = 32768,
+ cpu_bits_size = CPU_ALLOC_SIZE (32768)
+ };
+
+ /* This cannot use malloc because it is used on malloc initialization. */
+ __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)];
+ int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size,
+ cpu_bits);
+ if (r > 0)
+ return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits);
+ else if (r == -EINVAL)
+ /* The input buffer is still not enough to store the number of cpus. This
+ is an arbitrary values assuming such systems should be rare and there
+ is no offline cpus. */
+ return max_num_cpus;
+ /* Some other error. 2 is conservative (not a uniprocessor system, so
+ atomics are needed). */
+ return 2;
+}
+
+static char *
+next_line (int fd, char *const buffer, char **cp, char **re,
+ char *const buffer_end)
+{
+ char *res = *cp;
+ char *nl = memchr (*cp, '\n', *re - *cp);
+ if (nl == NULL)
+ {
+ if (*cp != buffer)
+ {
+ if (*re == buffer_end)
+ {
+ memmove (buffer, *cp, *re - *cp);
+ *re = buffer + (*re - *cp);
+ *cp = buffer;
+
+ ssize_t n = __read_nocancel (fd, *re, buffer_end - *re);
+ if (n < 0)
+ return NULL;
+
+ *re += n;
+
+ nl = memchr (*cp, '\n', *re - *cp);
+ while (nl == NULL && *re == buffer_end)
+ {
+ /* Truncate too long lines. */
+ *re = buffer + 3 * (buffer_end - buffer) / 4;
+ n = __read_nocancel (fd, *re, buffer_end - *re);
+ if (n < 0)
+ return NULL;
+
+ nl = memchr (*re, '\n', n);
+ **re = '\n';
+ *re += n;
+ }
+ }
+ else
+ nl = memchr (*cp, '\n', *re - *cp);
+
+ res = *cp;
+ }
+
+ if (nl == NULL)
+ nl = *re - 1;
+ }
+
+ *cp = nl + 1;
+ assert (*cp <= *re);
+
+ return res == *re ? NULL : res;
}
-/* __get_nprocs with a large buffer. */
static int
-__get_nprocs_large (void)
+get_nproc_stat (char *buffer, size_t buffer_size)
{
- /* This code cannot use scratch_buffer because it is used during
- malloc initialization. */
- size_t pagesize = GLRO (dl_pagesize);
- unsigned long int *page = __mmap (0, pagesize, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page == MAP_FAILED)
- return 2;
- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, pagesize, page);
- int count;
- if (r > 0)
- count = __get_nprocs_count (page, pagesize / sizeof (unsigned long int));
- else if (r == -EINVAL)
- /* One page is still not enough to store the bits. A more-or-less
- arbitrary value. This assumes t hat such large systems never
- happen in practice. */
- count = GLRO (dl_pagesize) * CHAR_BIT;
- else
- count = 2;
- __munmap (page, GLRO (dl_pagesize));
- return count;
+ char *buffer_end = buffer + buffer_size;
+ char *cp = buffer_end;
+ char *re = buffer_end;
+
+ /* Default to an SMP system in case we cannot obtain an accurate
+ number. */
+ int result = 2;
+
+ const int flags = O_RDONLY | O_CLOEXEC;
+ int fd = __open_nocancel ("/proc/stat", flags);
+ if (fd != -1)
+ {
+ result = 0;
+
+ char *l;
+ while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
+ /* The current format of /proc/stat has all the cpu* entries
+ at the front. We assume here that stays this way. */
+ if (strncmp (l, "cpu", 3) != 0)
+ break;
+ else if (isdigit (l[3]))
+ ++result;
+
+ __close_nocancel_nostatus (fd);
+ }
+
+ return result;
}
int
__get_nprocs (void)
{
- /* Fast path for most systems. The kernel expects a buffer size
- that is a multiple of 8. */
- unsigned long int small_buffer[1024 / CHAR_BIT / sizeof (unsigned long int)];
- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0,
- sizeof (small_buffer), small_buffer);
- if (r > 0)
- return __get_nprocs_count (small_buffer, r / sizeof (unsigned long int));
- else if (r == -EINVAL)
- /* The kernel requests a larger buffer to store the data. */
- return __get_nprocs_large ();
- else
- /* Some other error. 2 is conservative (not a uniprocessor
- system, so atomics are needed). */
- return 2;
+ enum { buffer_size = 1024 };
+ char buffer[buffer_size];
+ char *buffer_end = buffer + buffer_size;
+ char *cp = buffer_end;
+ char *re = buffer_end;
+
+ const int flags = O_RDONLY | O_CLOEXEC;
+ /* This file contains comma-separated ranges. */
+ int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags);
+ char *l;
+ int result = 0;
+ if (fd != -1)
+ {
+ l = next_line (fd, buffer, &cp, &re, buffer_end);
+ if (l != NULL)
+ do
+ {
+ char *endp;
+ unsigned long int n = strtoul (l, &endp, 10);
+ if (l == endp)
+ {
+ result = 0;
+ break;
+ }
+
+ unsigned long int m = n;
+ if (*endp == '-')
+ {
+ l = endp + 1;
+ m = strtoul (l, &endp, 10);
+ if (l == endp)
+ {
+ result = 0;
+ break;
+ }
+ }
+
+ result += m - n + 1;
+
+ l = endp;
+ if (l < re && *l == ',')
+ ++l;
+ }
+ while (l < re && *l != '\n');
+
+ __close_nocancel_nostatus (fd);
+
+ if (result > 0)
+ return result;
+ }
+
+ return get_nproc_stat (buffer, buffer_size);
}
libc_hidden_def (__get_nprocs)
weak_alias (__get_nprocs, get_nprocs)
@@ -117,7 +228,9 @@ __get_nprocs_conf (void)
return count;
}
- return 1;
+ enum { buffer_size = 1024 };
+ char buffer[buffer_size];
+ return get_nproc_stat (buffer, buffer_size);
}
libc_hidden_def (__get_nprocs_conf)
weak_alias (__get_nprocs_conf, get_nprocs_conf)
diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
index feb70abc3e..b07fc8549d 100644
--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
@@ -231,6 +231,7 @@
#define __NR_pwritev 316
#define __NR_pwritev2 348
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 207
#define __NR_readlink 85
diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
index 3b1894a79b..6e4264698b 100644
--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
@@ -183,6 +183,7 @@
#define __NR_mbind 274
#define __NR_membarrier 375
#define __NR_memfd_create 356
+#define __NR_memfd_secret 447
#define __NR_migrate_pages 294
#define __NR_mincore 218
#define __NR_mkdir 39
@@ -266,6 +267,7 @@
#define __NR_pwritev2 379
#define __NR_query_module 167
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 225
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
index fb388a5fa4..1ca706d721 100644
--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
@@ -218,6 +218,7 @@
#define __NR_pwritev 1320
#define __NR_pwritev2 1349
#define __NR_quotactl 1137
+#define __NR_quotactl_fd 1467
#define __NR_read 1026
#define __NR_readahead 1216
#define __NR_readlink 1092
diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
index 7bc8c4af92..2f10f71f90 100644
--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
@@ -254,6 +254,7 @@
#define __NR_pwritev2 378
#define __NR_query_module 167
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 240
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
index cf560d3af4..0607a4dfa6 100644
--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
@@ -266,6 +266,7 @@
#define __NR_pwritev2 394
#define __NR_query_module 167
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 225
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/mips/fxstat.c b/sysdeps/unix/sysv/linux/mips/fxstat.c
index 11511d30b3..4a6016ff12 100644
--- a/sysdeps/unix/sysv/linux/mips/fxstat.c
+++ b/sysdeps/unix/sysv/linux/mips/fxstat.c
@@ -35,7 +35,9 @@ __fxstat (int vers, int fd, struct stat *buf)
{
struct kernel_stat kbuf;
int r = INTERNAL_SYSCALL_CALL (fstat, fd, &kbuf);
- return r ?: __xstat_conv (vers, &kbuf, buf);
+ if (r == 0)
+ return __xstat_conv (vers, &kbuf, buf);
+ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
}
}
}
diff --git a/sysdeps/unix/sysv/linux/mips/lxstat.c b/sysdeps/unix/sysv/linux/mips/lxstat.c
index 871fb6c6c5..54f990a250 100644
--- a/sysdeps/unix/sysv/linux/mips/lxstat.c
+++ b/sysdeps/unix/sysv/linux/mips/lxstat.c
@@ -35,7 +35,9 @@ __lxstat (int vers, const char *name, struct stat *buf)
{
struct kernel_stat kbuf;
int r = INTERNAL_SYSCALL_CALL (lstat, name, &kbuf);
- return r ?: __xstat_conv (vers, &kbuf, buf);
+ if (r == 0)
+ return __xstat_conv (vers, &kbuf, buf);
+ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
}
}
}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
index f346460f48..0055eec0b1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
@@ -251,6 +251,7 @@
#define __NR_pwritev2 4362
#define __NR_query_module 4187
#define __NR_quotactl 4131
+#define __NR_quotactl_fd 4443
#define __NR_read 4003
#define __NR_readahead 4223
#define __NR_readdir 4089
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
index 38ed84997a..8e8e9f91cc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
@@ -232,6 +232,7 @@
#define __NR_pwritev2 6326
#define __NR_query_module 6171
#define __NR_quotactl 6172
+#define __NR_quotactl_fd 6443
#define __NR_read 6000
#define __NR_readahead 6179
#define __NR_readlink 6087
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
index e6a10c8421..ebd1545f80 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
@@ -219,6 +219,7 @@
#define __NR_pwritev2 5322
#define __NR_query_module 5171
#define __NR_quotactl 5172
+#define __NR_quotactl_fd 5443
#define __NR_read 5000
#define __NR_readahead 5179
#define __NR_readlink 5087
diff --git a/sysdeps/unix/sysv/linux/mips/xstat.c b/sysdeps/unix/sysv/linux/mips/xstat.c
index 9d810b6f65..86f4dc31a8 100644
--- a/sysdeps/unix/sysv/linux/mips/xstat.c
+++ b/sysdeps/unix/sysv/linux/mips/xstat.c
@@ -35,7 +35,9 @@ __xstat (int vers, const char *name, struct stat *buf)
{
struct kernel_stat kbuf;
int r = INTERNAL_SYSCALL_CALL (stat, name, &kbuf);
- return r ?: __xstat_conv (vers, &kbuf, buf);
+ if (r == 0)
+ return __xstat_conv (vers, &kbuf, buf);
+ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
}
}
}
diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
index 9799dcdaa4..eccae2e4c6 100644
--- a/sysdeps/unix/sysv/linux/mq_notify.c
+++ b/sysdeps/unix/sysv/linux/mq_notify.c
@@ -131,7 +131,7 @@ helper_thread (void *arg)
to wait until it is done with it. */
(void) __pthread_barrier_wait (&notify_barrier);
}
- else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
+ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL)
{
/* The only state we keep is the copy of the thread attributes. */
__pthread_attr_destroy (data.attr);
diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
index 5314890289..2b530b1f88 100644
--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
@@ -198,6 +198,7 @@
#define __NR_pwritev 70
#define __NR_pwritev2 287
#define __NR_quotactl 60
+#define __NR_quotactl_fd 443
#define __NR_read 63
#define __NR_readahead 213
#define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
index b5b0758532..a32984a9c1 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
@@ -260,6 +260,7 @@
#define __NR_pwritev2 381
#define __NR_query_module 166
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 191
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
index c77435ca61..b01e464fb9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
@@ -243,6 +243,7 @@
#define __NR_pwritev2 381
#define __NR_query_module 166
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 191
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
index 70854bb9e3..24d0a2c455 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
@@ -179,6 +179,7 @@
#define __NR_pwritev 70
#define __NR_pwritev2 287
#define __NR_quotactl 60
+#define __NR_quotactl_fd 443
#define __NR_read 63
#define __NR_readahead 213
#define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
index 83b9f31aba..e526c89ae7 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
@@ -187,6 +187,7 @@
#define __NR_pwritev 70
#define __NR_pwritev2 287
#define __NR_quotactl 60
+#define __NR_quotactl_fd 443
#define __NR_read 63
#define __NR_readahead 213
#define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
index e9bd3684db..00e73a3e3b 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
@@ -22,6 +22,11 @@
/*
* The following must match the kernels asm/elf.h.
+ * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e
+ * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros
+ * from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not
+ * change the prefix in public glibc header file.
+ *
* Note that these are *not* the same as the STORE FACILITY LIST bits.
*/
#define HWCAP_S390_ESAN3 1
@@ -48,3 +53,5 @@
#define HWCAP_S390_DFLT 262144
#define HWCAP_S390_VXRS_PDE2 524288
#define HWCAP_S390_NNPA 1048576
+#define HWCAP_S390_PCI_MIO 2097152
+#define HWCAP_S390_SIE 4194304
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
index b224c4aad4..d4c7b101b6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
@@ -251,6 +251,7 @@
#define __NR_pwritev2 377
#define __NR_query_module 167
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 222
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
index 59864af125..bd8c78d705 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
@@ -221,6 +221,7 @@
#define __NR_pwritev2 377
#define __NR_query_module 167
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 222
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
index 23612c9092..3b6ac3d084 100644
--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
@@ -246,6 +246,7 @@
#define __NR_pwritev 334
#define __NR_pwritev2 382
#define __NR_quotactl 131
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 225
#define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
index b481b4f9f8..45db6b6ffb 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
@@ -28,32 +28,35 @@
struct stat
{
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
__dev_t st_dev; /* Device. */
-#if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64
+# if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64
unsigned short int __pad1;
__ino_t st_ino; /* File serial number. */
-#else
+# else
__ino64_t st_ino; /* File serial number. */
-#endif
+# endif
__mode_t st_mode; /* File mode. */
__nlink_t st_nlink; /* Link count. */
__uid_t st_uid; /* User ID of the file's owner. */
__gid_t st_gid; /* Group ID of the file's group.*/
__dev_t st_rdev; /* Device number, if device. */
unsigned short int __pad2;
-#ifndef __USE_FILE_OFFSET64
+# ifndef __USE_FILE_OFFSET64
__off_t st_size; /* Size of file, in bytes. */
-#else
+# else
__off64_t st_size; /* Size of file, in bytes. */
-#endif
+# endif
__blksize_t st_blksize; /* Optimal block size for I/O. */
-#ifndef __USE_FILE_OFFSET64
+# ifndef __USE_FILE_OFFSET64
__blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
-#else
+# else
__blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
-#endif
-#ifdef __USE_XOPEN2K8
+# endif
+# ifdef __USE_XOPEN2K8
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
@@ -63,28 +66,32 @@ struct stat
struct timespec st_atim; /* Time of last access. */
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
-# define st_atime st_atim.tv_sec /* Backward compatibility. */
-# define st_mtime st_mtim.tv_sec
-# define st_ctime st_ctim.tv_sec
-#else
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
+# define st_mtime st_mtim.tv_sec
+# define st_ctime st_ctim.tv_sec
+# else
__time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
-#endif
+# endif
unsigned long int __glibc_reserved4;
unsigned long int __glibc_reserved5;
+#endif /* __USE_TIME_BITS64 */
};
#ifdef __USE_LARGEFILE64
struct stat64
{
+# ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+# else
__dev_t st_dev; /* Device. */
-# if __WORDSIZE == 64
+# if __WORDSIZE == 64
unsigned short int __pad1;
-# endif
+# endif
__ino64_t st_ino; /* File serial number. */
__mode_t st_mode; /* File mode. */
__nlink_t st_nlink; /* Link count. */
@@ -96,7 +103,7 @@ struct stat64
__blksize_t st_blksize; /* Optimal block size for I/O. */
__blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
-# ifdef __USE_XOPEN2K8
+# ifdef __USE_XOPEN2K8
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
@@ -106,19 +113,20 @@ struct stat64
struct timespec st_atim; /* Time of last access. */
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
-# define st_atime st_atim.tv_sec /* Backward compatibility. */
-# define st_mtime st_mtim.tv_sec
-# define st_ctime st_ctim.tv_sec
-# else
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
+# define st_mtime st_mtim.tv_sec
+# define st_ctime st_ctim.tv_sec
+# else
__time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
-# endif
+# endif
unsigned long int __glibc_reserved4;
unsigned long int __glibc_reserved5;
+# endif /* __USE_TIME_BITS64 */
};
#endif
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
index 380cddb2d8..35221a707e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
@@ -252,6 +252,7 @@
#define __NR_pwritev2 359
#define __NR_query_module 184
#define __NR_quotactl 165
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 205
#define __NR_readdir 204
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
index 2175eeb6ed..5ba2b20509 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
@@ -231,6 +231,7 @@
#define __NR_pwritev2 359
#define __NR_query_module 184
#define __NR_quotactl 165
+#define __NR_quotactl_fd 443
#define __NR_read 3
#define __NR_readahead 205
#define __NR_readdir 204
diff --git a/sysdeps/unix/sysv/linux/sys/prctl.h b/sysdeps/unix/sysv/linux/sys/prctl.h
index db88938b3a..f0e0d2f27f 100644
--- a/sysdeps/unix/sysv/linux/sys/prctl.h
+++ b/sysdeps/unix/sysv/linux/sys/prctl.h
@@ -42,7 +42,7 @@ __BEGIN_DECLS
extern int prctl (int __option, ...) __THROW;
#else
# ifdef __REDIRECT
-extern int __REDIRECT (prctl, (int __option, ...), __prctl_time64) __THROW;
+extern int __REDIRECT_NTH (prctl, (int __option, ...), __prctl_time64);
# else
extern int __prctl_time64 (int __option,d ...) __THROW;
# define ioctl __prctl_time64
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index 89c5895b9b..fd98893b0e 100644
--- a/sysdeps/unix/sysv/linux/syscall-names.list
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
@@ -21,8 +21,8 @@
# This file can list all potential system calls. The names are only
# used if the installed kernel headers also provide them.
-# The list of system calls is current as of Linux 5.13.
-kernel 5.13
+# The list of system calls is current as of Linux 5.14.
+kernel 5.14
FAST_atomic_update
FAST_cmpxchg
@@ -247,6 +247,7 @@ madvise
mbind
membarrier
memfd_create
+memfd_secret
memory_ordering
migrate_pages
mincore
@@ -452,6 +453,7 @@ pwritev
pwritev2
query_module
quotactl
+quotactl_fd
read
readahead
readdir
diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
index dccb6189c5..f5069d1b8a 100644
--- a/sysdeps/unix/sysv/linux/tst-close_range.c
+++ b/sysdeps/unix/sysv/linux/tst-close_range.c
@@ -36,23 +36,12 @@
#define NFDS 100
-static int
-open_multiple_temp_files (void)
-{
- /* Check if the temporary file descriptor has no no gaps. */
- int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
- for (int i = 1; i <= NFDS; i++)
- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
- lowfd + i);
- return lowfd;
-}
-
static void
close_range_test_max_upper_limit (void)
{
struct support_descriptors *descrs = support_descriptors_list ();
- int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
{
int r = close_range (lowfd, ~0U, 0);
@@ -68,7 +57,7 @@ close_range_test_max_upper_limit (void)
static void
close_range_test_common (int lowfd, unsigned int flags)
{
- const int maximum_fd = lowfd + NFDS;
+ const int maximum_fd = lowfd + NFDS - 1;
const int half_fd = lowfd + NFDS / 2;
const int gap_1 = maximum_fd - 8;
@@ -121,7 +110,7 @@ close_range_test (void)
struct support_descriptors *descrs = support_descriptors_list ();
/* Check if the temporary file descriptor has no no gaps. */
- int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
close_range_test_common (lowfd, 0);
@@ -146,7 +135,7 @@ close_range_test_subprocess (void)
struct support_descriptors *descrs = support_descriptors_list ();
/* Check if the temporary file descriptor has no no gaps. */
- int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
struct support_stack stack = support_stack_alloc (4096);
@@ -184,7 +173,7 @@ close_range_unshare_test (void)
struct support_descriptors *descrs1 = support_descriptors_list ();
/* Check if the temporary file descriptor has no no gaps. */
- int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
struct support_descriptors *descrs2 = support_descriptors_list ();
@@ -200,7 +189,7 @@ close_range_unshare_test (void)
support_stack_free (&stack);
- for (int i = 0; i < NFDS; i++)
+ for (int i = lowfd; i < lowfd + NFDS; i++)
TEST_VERIFY (fcntl (i, F_GETFL) > -1);
support_descriptors_check (descrs2);
@@ -226,9 +215,9 @@ static void
close_range_cloexec_test (void)
{
/* Check if the temporary file descriptor has no no gaps. */
- const int lowfd = open_multiple_temp_files ();
+ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
- const int maximum_fd = lowfd + NFDS;
+ const int maximum_fd = lowfd + NFDS - 1;
const int half_fd = lowfd + NFDS / 2;
const int gap_1 = maximum_fd - 8;
@@ -251,13 +240,13 @@ close_range_cloexec_test (void)
/* Create some gaps, close up to a threshold, and check result. */
static int gap_close[] = { 57, 78, 81, 82, 84, 90 };
for (int i = 0; i < array_length (gap_close); i++)
- xclose (gap_close[i]);
+ xclose (lowfd + gap_close[i]);
TEST_COMPARE (close_range (half_fd + 1, gap_1, CLOSE_RANGE_CLOEXEC), 0);
for (int i = half_fd + 1; i < gap_1; i++)
{
int flags = fcntl (i, F_GETFD);
- if (is_in_array (gap_close, array_length (gap_close), i))
+ if (is_in_array (gap_close, array_length (gap_close), i - lowfd))
TEST_COMPARE (flags, -1);
else
{
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
index ee5b13ee12..810433c238 100644
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
@@ -33,7 +33,7 @@ def main():
help='C compiler (including options) to use')
args = parser.parse_args()
linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
- linux_version_glibc = (5, 13)
+ linux_version_glibc = (5, 14)
sys.exit(glibcextract.compare_macro_consts(
'#define _GNU_SOURCE 1\n'
'#include <sys/mman.h>\n',
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
index 8e028eb62b..26d6ac68a6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
@@ -154,6 +154,7 @@
#define __NR_mbind 237
#define __NR_membarrier 324
#define __NR_memfd_create 319
+#define __NR_memfd_secret 447
#define __NR_migrate_pages 256
#define __NR_mincore 27
#define __NR_mkdir 83
@@ -224,6 +225,7 @@
#define __NR_pwritev2 328
#define __NR_query_module 178
#define __NR_quotactl 179
+#define __NR_quotactl_fd 443
#define __NR_read 0
#define __NR_readahead 187
#define __NR_readlink 89
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 004feb53f1..36847783f6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
@@ -148,6 +148,7 @@
#define __NR_mbind 1073742061
#define __NR_membarrier 1073742148
#define __NR_memfd_create 1073742143
+#define __NR_memfd_secret 1073742271
#define __NR_migrate_pages 1073742080
#define __NR_mincore 1073741851
#define __NR_mkdir 1073741907
@@ -216,6 +217,7 @@
#define __NR_pwritev 1073742359
#define __NR_pwritev2 1073742371
#define __NR_quotactl 1073742003
+#define __NR_quotactl_fd 1073742267
#define __NR_read 1073741824
#define __NR_readahead 1073742011
#define __NR_readlink 1073741913
diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
index 9f02624375..abde8438d4 100644
--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
+++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
@@ -325,7 +325,7 @@ L(movsb):
/* Avoid slow backward REP MOVSB. */
jb L(more_8x_vec_backward)
# if AVOID_SHORT_DISTANCE_REP_MOVSB
- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
+ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
jz 3f
movq %rdi, %rcx
subq %rsi, %rcx
@@ -333,7 +333,7 @@ L(movsb):
# endif
1:
# if AVOID_SHORT_DISTANCE_REP_MOVSB
- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
+ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
jz 3f
movq %rsi, %rcx
subq %rdi, %rcx